摘要:對象的引用關鍵字總是指向調用該方法的對象。根據出現位置的不同,作為對象的默認引用有兩種情形。構造器中引用該構造器正在初始化的對象。如果同一個類中包含了兩個或兩個以上方法的方法名相同,但形參列表不同,則被稱為方法重載。
類和對象 定義類
面向對象的程序設計過程中有兩個重要概念:類(class)和對象(object,也被稱為實例,instance),其中類是某一批對象的抽象,可以把類理解成某種概念;對象才是一個具體存在的實體。
[修飾符] class 類名 { 零個到多個構造器定義... 零個到多個成員變量... 零個到多個方法... }
修飾符可以是public、final、abstract或者完全忽略。
如果從程序的可讀性方面來看,Java類名必須由一個或多個有意義的單詞連綴而成的,每個單詞首字母大寫,其他字母全部小寫,單詞與單詞之間不要使用任何分隔符。
構造器是一個類創建對象的根本途徑,如果一個類沒有構造器,這個類通常無法創建實例。如果程序員沒有為一個類編寫構造器,則系統會為該類提供一個默認的構造器。一旦程序員為一個類提供了構造器,系統將不再為該類提供構造器。
定義成員變量static修飾的成員不能訪問沒有static修飾的成員。
成員變量用于定義該類或該類的實例所包含的狀態數據,方法則用于定義該類或該類的實例的行為特征或者功能實現。構造器用于構造該類的實例,Java語言通過new關鍵字來調用構造器,從而返回該類的實例。
[修飾符] 類型 成員變量名 [=默認值]
修飾符:public、protected、private三個最多只能出現其中之一,可以與static、final組合起來修飾成員變量。
類型:基本類型和引用類型
成員變量名:如果從程序的可讀性方面來看,Java類名必須由一個或多個有意義的單詞連綴而成的,第一個單詞首字母小寫,后面每個單詞首字母大寫,其他字母全部小寫,單詞與單詞之間不要使用任何分隔符。
默認值:定義成員變量還可以指定一個可選的默認值。
定義方法[修飾符] 方法返回值類型 方法名(形參列表) { //由零條到多條可執行性語句組成的方法體 }
修飾符:public、protected、private三個最多只能出現其中之一,可以與static、final組合起來修飾成員變量。
方法返回值類型:基本類型和引用類型如果聲明了方法返回值類型,則方法體內必須與此處聲明的類型匹配。如果一個方法沒有返回值,則必須使用void來聲明沒有返回值。
形參列表:形參列表用于定義該方法可以接受的參數,形參列表由零組到多組“參數類型 形參名”組合而成,多組參數之間以英文逗號(,)隔開,形參類型和形參名之間以英文空格隔開。
staticstatic是一個特殊的關鍵字,可用于修飾方法、成員變量等成員。static修飾的成員表明它屬于這個類本身,而不屬于該類的單個實例,因為通常把static修飾的成員變量和方法也稱為類變量、類方法。不使用static修飾的普通方法、成員變量則屬于該類的單個實例,而不屬于該類。因為通常把不使用static修飾的成員變量和方法也稱為實例變量、實例方法。
static修飾的成員變量和方法稱為靜態變量和靜態方法,把不使用static修飾的成員變量和方法稱為非靜態變量和非靜態方法。靜態方法不能直接訪問非靜態成員。
有static修飾的成員屬于類本身,沒有static修飾的成員屬于該類的實例。
構造器構造器是一個特殊的方法,定義構造器的語法格式與定義方法的語法格式很像,定義構造器的語法格式如下:
[修飾符] 構造器名(形參列表) { //由零條到多條可執行性語句組成的構造器執行體 }
修飾符:public、protected、private
構造器名:構造器名必須和類同名
形參列表:和定義方法形參列表的格式完全相同。
構造器既不能定義返回值類型,也不能使用void聲明構造器沒有返回值。
static修飾的方法和成員變量,既可通過類來調用,也可通過實例來調用;沒有使用static修飾的普通方法和成員變量,只可通過實例來調用。
對象、引用和指針變量實例實際上是一個引用,它被存放在棧內存里,指向實際的類對象;而真正的類對象則存放在堆內存中。棧內存里的引用變量并未真正存儲對象的成員變量,對象的成員變量數據實際存放在堆內存里;而引用變量只是指向該堆內存里的對象。
對象的this引用this關鍵字總是指向調用該方法的對象。根據this出現位置的不同,this作為對象的默認引用有兩種情形。
構造器中引用該構造器正在初始化的對象。
在方法中引用調用該方法的對象。
對于static修飾的方法而言,則可以使用類來直接調用該方法,如果在static修飾的方法中使用this關鍵字,則這個關鍵字就無法指向合適的對象。所以,static修飾的方法中不能使用this引用。由于static修飾的方法不能使用this引用,所以static修飾的方法不能訪問不使用static修飾的普通成員,因此Java語法規定:靜態成員不能直接訪問非靜態成員。
普通方法訪問其他方法、成員變量時無須使用this前綴,但如果方法里有個局部變量和成員變量同名,但程序又需要在該方法里訪問這個被覆蓋的成員變量,則必須使用this前綴。this引用也可以用于構造器中作為默認引用,由于構造器是直接使用new關鍵字來調用,而不是使用對象來調用的,所以this在構造器中代表該構造器正在初始化的對象。
方法詳解 方法的所屬性Java語言里方法的所屬性主要體現在如下幾個方面:
方法不能獨立完成,方法只能在類體里定義。
從邏輯意義上來看,方法要么屬于該類本身,要么屬于該類的一個對象。
永遠不能獨立執行方法,執行方法必須使用類或對象作為調用者。
同一個類的一個方法調用另一個方法時,如果被調用方法是普通方法,則默認使用this作為調用者;如果被調方法是靜態方法,則默認方法類作為調用者。
方法的參數傳遞機制聲明方法時包含了形參聲明,則調用方法時必須給這些形參指定參數值,調用方法時實際傳給形參的參數值也被稱為實參。
形參個數可變的方法Java允許定義形參個數可變的參數,從而允許為方法指定數量不確定的形參。如果在定義方法時,在最后一個形參的類型后增加三點(...),則表明該形參可以接受多個參數值,多個參數值被當成數組傳入。
public statci void test(int a, String ... books)
數組形式的形參可以處于形參列表的任意位置,但個數可變的形參只能處于形參列表的最后。也就是說一個方法中最多只能有一個長度可變的形參。
遞歸方法一個方法體內調用它自身,被稱為方法遞歸。方法遞歸包含了一種隱式的循環,它會重復執行某段代碼,但這種重復執行無限循環控制。
希望遍歷某個路徑下的所有文件,但這個路徑下文件夾的深度是未知的,那么就可以使用遞歸來實現這個需求。系統可定義一個方法,該方法接受一個文件路徑作為參數,該方法可遍歷當前路徑下的所有文件和文件路徑——該方法中再次調用該方法本身來處理該路徑下的所有文件路徑。
方法重載Java允許同一個類里定義多個同名方法,只有形參列表不同就行。如果同一個類中包含了兩個或兩個以上方法的方法名相同,但形參列表不同,則被稱為方法重載。
方法重載三個因素:
調用者,也就是方法的所屬者,既可以是類,也可以是對象。
方法名,方法的標識。
形參列表,當調用方法時,系統將會根據傳入的實參列表匹配。
兩同一不同:同一個類中方法名相同,參數列表不同。方法返回值類型、修飾符等,與方法重載沒有任何關系。
成員變量和局部變量 成員變量成員變量指的是類里定義的變量,也就是前面所介紹的field;局部變量指的是方法里定義的變量。
成員變量:一個類不能定義兩個同名的成員變量。
static修飾的類變量。類變量從該類的準備階段起開始存在,直到系統完全銷毀這個類,類變量的作用域與這個類的生存范圍相同;而實例變量則從該類的實例被創建起開始存在,直到系統完全銷毀這個實例,實例變量的作用域與對應實例的生存范圍相同。
成員變量無須顯式初始化,只要為一個類定義了類變量或實例變量,系統就會在這個類的準備階段或創建該類的實例時進行默認初始化,成員變量默認初始化時的賦值規則與數組動態初始化時數組元素的賦值規則完全相同。
局部變量:一個方法里不能定義兩個同名的方法局部變量,方法局部變量與形參也不能同名;同一個方法中不同代碼塊內的代碼塊局部變量可以同名;如果先定義代碼塊局部變量,后定義方法局部變量,前面定義的代碼塊局部變量與后面定義的方法局部變量也可以同名。
形參(方法簽名中定義的變量) 作用域在整個方法內有效 必須顯式初始化
方法局部變量(在方法內定義) 作用域從定義該變量的地方生效,到該方法結束時失效 必須顯式初始化
代碼塊局部變量(在代碼塊內定義) 作用域從定義該變量的地方生效,到該代碼塊結束時失效 無須顯式初始化
Java允許局部變量和成員變量同名,如果方法里的局部變量和成員變量同名,局部變量會覆蓋成員變量,如果需要在這個方法里引用被覆蓋的成員變量,則可使用this(對于實例變量)或類名(對于類變量)作為調用者來限定訪問成員變量。
成員變量的初始化和內存中的運行機制當系統加載類或創建該類的實例時,系統自動為成員變量分配內存空間,并在分配內存空間后,自動為成員變量指定初始值。
局部變量的初始化和內存中的運行機制局部變量定義后,必須經過顯式初始化后才能使用,系統不會為局部變量執行初始化。這意味著定義局部變量后,系統并未為這個變量分配內存空間,直到等到程序為這個變量賦初始值時,系統才會為局部變量分配內存,并將初始值保存到這塊內存中。
變量的使用規則定義一個成員變量時,成員變量將被放置到堆內存中,成員變量的作用域將擴大到類存在范圍或者對象存在范圍,這種范圍的擴大有兩個害處。
增大了變量的生存時間,這將導致更大的內存開銷。
擴大了變量的作用域,這不利于提供程序的內聚性。
應該考慮使用成員變量的情況:
如果需要定義的變量是用于描述某個類或某個對象的固有信息。
如果在某個類中需要以一個變量來保存該類或者實例運行時的狀態信息。
如果某個信息需要在某個類的多個方法之間進行共享,則這個信息應該使用成員變量來保存。
即使在程序中使用局部變量,也應該盡可能地縮小局部變量的作用范圍,局部變量的作用范圍越小,它在內存里停留的時間就越短,程序運行性能就越好。因此,能用代碼塊局部變量的地方,就堅決不要使用方法局部變量。
隱藏和封裝 理解封裝封裝指的是將對象的狀態信息隱藏在對象內部,不允許外部程序直接訪問對象內部信息,二世通過該類所提供的方法來實現對內部信息的操作和訪問。
對一個類或對象實現良好的封裝,可以實現以下目的。
隱藏類的實現細節
讓使用者只能通過事先預定的方法來訪問數據,從而可以在該方法里加入控制邏輯,限制對成員變量的不合理訪問。
可進行數據檢查,從而有利于保證對象信息的完整性。
便于修改,提高代碼的可維護性。
為了實現良好的封裝,需要從兩個方面考慮:
將對象的成員變量和實現細節隱藏起來,不允許外部直接訪問。
把方法暴露出來,讓方法來控制對這些成員變量進行安全的訪問和操作。
使用訪問控制符private → default → protected → public
訪問控制級別由小到大
private(當前類訪問權限):使用它來修飾成員變量就可以把成員變量隱藏在該類的內部。
default(包訪問權限):defaulte訪問控制的成員或外部類可以被相同包下的其他類訪問。
protected(子類訪問權限):成員既可以被同一包中的其他類訪問,也可以被不同包中的子類訪問。通常,如果使用protected來修飾一個方法,是希望其子類來重寫這個方法。
public(公共訪問權限):成員或外部類可以被所以類訪問,不管訪問類和被訪問類是否處于同一包中,是否具有父子繼承關系。
private default protected public 同一個類中 √ √ √ √ 同一個包中 √ √ √ 子類中 √ √ 全局范圍內 √
外部類只能有兩種訪問控制級別:public和default,外部類不能用private和protected修飾,因為外部類沒有處于任何類內部,也就沒有其所在類的內部、所在類的子類的兩個范圍。
如果一個Java類的每個實例變量都被使用private修飾,并為每個實例變量都提供了public修飾setter和getter方法,那么這個類就是一個符號JavaBean規范的類。因此,JavaBean總是一個封裝良好的類。
進行程序設計時,應盡量避免一個模塊直接操作和訪問另一個模塊的數據,模塊設計追求高內聚(盡可能把模塊的內部數據、功能實現細節隱藏在模塊內部獨立完成,不允許外部直接干預)、低耦合(僅暴露少量的方法給外部使用)。
訪問控制符的使用的基本原則:
類里的絕大部分成員變量都應該使用private,只有一些static修飾的、類似全局變量的成員變量,才可能考慮使用public修飾。除此之外,有些方法只用于輔助實現該類的其他方法,這些方法被稱為工具方法,工具方法也應該使用private修飾。
如果某個類主要用作其他類的父類,該類里包含的大部分方法可能僅希望被其子類重寫,而不想被外界直接調用,則應該使用protected修飾這些方法。
希望暴露出來給其他類自由調用的方法應該使用public修飾。因此,類的構造器通過public修飾,從而允許在其他地方創建該類的實例。因為外部類通常都希望被其他類自由使用,所以大部分外部類都使用public修飾。
package、import和import static如果希望把一個類放到指定的包結構下,應該在Java源程序的第一個非注釋行放置如下格式的代碼:
package packageName;
一旦在Java源文件中使用了這個package語句,就意味著該源文件里定義的所有類都屬于這個包。位于包中的每個類的完整類名都應該是包名和類名的組合,如果其他人需要使用該包下的類,也應該使用包名加類名的組合。
同一個包中的類不必位于相同的目錄下,例如有leePerson和LeePersonTest兩個類,它們完全可以一個位于C盤下某個位置,一個位于D盤下某個位置,只要讓CLASSPATH環境變量里包含這兩個路徑即可。虛擬機會自動搜索CLASSPATH下的子路徑,把它們當成同一個包下的類來處理。也應該把Java源文件放在與包名一致的目錄結構下。通常建議將源文件和class文件分開存放,以便管理。
從可讀性規范角度來看,包名應該全部是小寫字母,而且應該由一個或多個有意義的單詞連綴而成。
package語句必須作為源文件的第一條非注釋性語句,一個源文件只能指定一個包,即只能包含一條package語句,該源文件中可以定義多個類,則這些類將全部位于該包下。如果沒有顯式指定package語言,則處于默認包下。
同一個包下的類可以自由訪問,無須添加包前綴。
父包和子包之間確實表示了某種內在的邏輯關系。但父包和子包在用法上不存在任何關系,如果父包中的類需要使用子包中的類,則必須使用子包的全名,而不能省略父包部分。
//調用構造器時需要在構造器前添加包前綴 lee.sub.Apple a = new lee.sub.Apple();import關鍵字
import可以向某個Java文件中導入指定包層次下某個類或全部類,import語句應該出現在package語句之后(如果有)、類定義之前。一個Java源文件只能包含一個package語句,但可以包含多個import語句,多個import語句用于導入多個包層次下的類。java.lang包下的所有類默認導入。
//使用import語句導入單個類 import package.subpackage...ClassName; //使用import語句導入指定包下全部 import package.subpackage.*
星號()只能代表類,不能代表包。因此使用import.lee.;語句時,它表明導入lee包下的所有類,而lee包下sub子包內的類則不會被導入。如需導入lee.sub.Apple類,則可以使用impor.lee.sub.*;語句來導入lee.sub包下的所有類。
一旦在Java源文件中使用import語句來導入指定類,在該源文件中使用這些類時就可以省略包前綴,不再需要使用類全名。
靜態導入import static
import static package.subpackage..ClassName.fieldName|methodName; field:靜態成員變量;methodName:靜態方法。 使用import可以省略寫包名;使用import static則可以連類名都省略。
Java源文件的大致結構:
package語句 //0個或1個,必須放在文件開始 import | import static 語句 //0個或多個,必須放在所有類定義之前 public classDefinition | interfaceDefinition | enumDefinition //0個或1個public類、接口或枚舉定義 classDefinition | interfaceDefinition | enumDefinition //0個或多個普通類、接口或枚舉定義Java的常用包
Java.lang:核心類,如String、Math、System和thread類等,使用這個包下的類無須使用import語句導入,系統會自動導入這個包下的所有類。 java.util:Java的大量工具類/接口和集合框架類/接口,例如Arrays和List、Set等 java.net:一些Java網絡編程相關的類/接口 java.io:一些Java輸入/輸出編程相關的類/接口 java.text:一些Java格式化相關的類 java.sql:Java進行JDBC數據庫編程的想相關類/接口 java.awt:抽象窗口工具集的相關類/接口,這些類主要用于構建圖形用戶界面GUI程序 java.swing:Swing圖形用戶界面編程的相關類/接口,這些類可用于構建平臺無關的GUI程序深入構造器
構造器是一個特殊的方法,用于創建實例時執行初始化。
使用構造器執行當創建一個對象時,系統為這個對象的實例變量進行默認初始化,這種默認的初始化把所有基本類型的實例變量設為0或false,把所有引用類型的實例變量設為Null。
如果程序員沒有為Java類提供任何構造器,則系統會為這個類提供一個無參數的構造器,這個構造器的執行體為空,不做任何事情。無論如何,Java類至少包含一個構造器。
通常把構造器設置為public訪問權限,從而允許系統中任何位置的類來創建該類的對象。
構造器重載同一個類里具有多個構造器,多個構造器的形參列表不同,即被稱為構造器重載,構造器重載允許Java類里包含多個初始化邏輯,從而允許使用不同的構造器來初始化Java對象。
類的繼承 繼承的特點Java的繼承通過extends關鍵字來實現,實現繼承的類被稱為子類,被繼承的類被稱為父類。父類與子類的關系,是一種一般和特殊的關系。Java類只能有一個直接父類。
修飾符 class SubClass extends SuperClass { //類定義部分 }
java.lang.Object類是所有類的父類,要么是直接父類,要么是其間接父類。因此所有的java對象都可以調用java.lang.Object類定義的實例方法。
重寫父類的方法子類包含與父類同名方法你的現象被稱為方法重寫(Override),也稱為方法覆蓋。
方法的重寫遵循“兩同兩小一大”規則
“兩同”:方法名、形參列表相同;
“兩小”:子類方法返回值類型應比父類返回值類型更小或相等,子類方法聲明拋出的異常類應比父類方法聲明拋出的異常類更小或相等。
“一大”:子類方法的訪問權限應比父類方法的訪問權限更大或相等。
覆蓋方法和被覆蓋方法要么都是類方法,要么都是實例方法,不能一個類方法,一個是實例方法。
當子類覆蓋了父類方法后,子類的對象將無法訪問父類中被覆蓋的方法,但可以在子類方法中調用父類中被覆蓋的方法。如果需要在子類方法最后調用父類中被覆蓋的方法,則可以使用super(被覆蓋的是實例方法)或者父類類名(被覆蓋的是類方法)作為調用者來調用父類中被覆蓋的方法。
如果父類方法具有private訪問權限,則該方法對其子類是隱藏的,因此其子類無法訪問該方法,也就是無法重寫該方法。如果子類中定義了一個與父類private方法具有相同的方法名、相同的形參列表、相同的返回值類型的方法,依然不是重寫,只是在子類中重新定義了一個新方法。
super限定如果需要在子類方法中調用父類被覆蓋的實例方法,則可使用super限定來調用父類被覆蓋的實例方法。super用于限定該對象調用它從父類繼承得到的實例變量或方法。this和super均不能出現在static修飾的方法中。
如果在某個方法中訪問名為a的成員變量,但沒有顯式指定調用者,則系統查找a的順序為:
查找該方法中是否有名為a的局部變量。
查找當前類中是否包括名為a的成員變量。
查找a的直接父類中是否包含名為a的成員變量,依次上溯a的所有父類,直到java.lang.Object類,如果最終不能找到名為a的成員變量,則系統出現編譯錯誤。
如果被覆蓋的是類變量,在子類的方法中則可以通過父類名作為調用者來訪問被覆蓋的類變量。
當程序創建一個子類對象時,系統不僅會為該類中定義的實例變量分配內存,也會為它從父類繼承得到的所有實例變量分配內存,即使子類定義了與父類中同名的實例變量。
調用父類構造器在一個構造器中調用另一個重載的構造器使用this來完成,在子類構造器使用super調用來完成。this和super調用構造器必須出現在構造器執行體的第一行。
子類構造器調用父類構造器分如下幾種情況:
子類構造器執行體的第一行使用super顯式調用父類構造器,系統將根據super調用里傳入的實參列表調用父類對應的構造器。
子類構造器執行體的第一行代碼使用this顯式調用本類中重載構造器,系統將根據this調用里傳入的實參列表調用本類中的另一個構造器。執行本類中另一個構造器時即會調用父類構造器。
子類構造器執行體中既沒有super調用,也沒有this調用,系統將會在執行子類構造器之前,隱式調用父類無參數的構造器。
創建任何java對象,最先執行的總是java.lang.Object類的構造器。即,創建任何對象總是從該類所在繼承樹最頂層類的構造器開始執行,然后依次向下執行,最后才執行本類的構造器。如果某個父類通過this調用了同類中重載的構造器,就會依次執行此父類的多個構造器。
多態 多態性Java引用變量有兩個類型:編譯時類型,運行時類型。
編譯時類型由聲明該變量時使用的類型決定,運行時類型由實際賦給該變量的對象決定。如果編譯時類型和運行時類型不一致,就可能出現所謂的多態。
BaseClass bc = new BaseClass(); SubClass sc = new SubClass(); BaseClass polymorphicBc = new SubClass();
上面程序顯式創建了三個引用變量,對于前兩個引用變量bc和sc,它們編譯時類型和運行時類型完全相同,因此調用它們的成員變量和方法非常正常,完全沒有任何問題。但第三個引用變量polymorphic則比較特殊,它的編譯時類型是BaseClass,而運行時類型是SubClass,當調用該引用變量的test()方法(BaseClass類中定義了該方法,子類SubClass覆蓋了父類的該方法)時,實際執行的是SubClass類中覆蓋后的test()方法,這就可能出現多態了。
因為子類其實是一種特殊的父類,因此Java允許把一個子類對象直接賦給一個父類引用變量,無須任何類型轉換,或者被稱為向上轉型(upcasting),向上轉型由系統自動完成。
相同類型的變量、調用同一方法時呈現出多種不同的行為特征,這就是多態。
polymorphicBc.sub();這行代碼會在編譯時引發錯誤。雖然polymorphicBc引用變量實際上確實包含sub()方法,但因為它的編譯時類型為BaseClass,因此編譯時無法調用sub方法。
與方法不同的是,對象的實例變量則不具備多態性。比如上面的polymorphicBc引用變量,程序中輸出它的book實例變量時,并不是輸出SubClass類里定義的實例變量,而是輸出BaseClass類的實例變量。
引用變量在編譯階段只能調用其編譯時類型所具有的方法,但運行時則執行它運行時類型所具有的方法。因此,編寫Java代碼時,引用變量只能調用聲明該變量時所用類里包含的方法。例如,通過Object p = new Person()代碼定義了一個變量p,則這個p只能調用Object類的方法,而不能調用Person類里定義的方法。
通過引用變量來訪問其包含的實例變量時,系統總是試圖訪問它編譯時類型所定義的成員變量,而不是它運行時類型所定義的成員變量。
引用變量的強制類型轉換編寫Java程序時,引用變量只能調用它編譯時類型的方法,而不能調用它運行時類型的方法,即使它實際所引用的對象卻是包含該方法。如果需要讓這個引用變量調用它運行時類型的方法,則必須把它強制類型轉換成運行時類型,強制類型轉換需要借助于類型轉換運算符。
當進行強制類型轉換時需要注意:
基本類型之間的轉換只能在數值類型之間進行,這里所說的數組類型包括整數性、字符型和浮點型。但數值型和布爾類型直接不能進行類型轉換。
引用類型直接的轉換只能在具有繼承關系的兩個類型之間進行,如果是兩個沒有任何繼承關系的類型,則無法進行類型轉換,否則編譯時就會出現錯誤。如果試圖把一個父類實例轉換成子類實例,則這個對象必須實際上是子類實例才行(即編譯時類型為福類型,而運行時類型是子類類型),否則將在運行時引發ClassCastException異常。
進行強制類型轉換時可能出現異常,因此進行類型轉換之前應先通過instanceof運算符來判斷是否可以成功轉換,從而避免出現ClassCastException異常,這樣可以保證程序更加健壯。
instanceof運算符instanceof運算符的前一個操作數通常是一個引用類型變量,后一個操作數通常是一個類(也可以是接口),它用于判斷前面的對象是否是后面的類,或者其子類、實現類的實例。如果是返回true,否則返回false。
instanceof運算符前面操作數的編譯時類型要么與后面的類相同,要么與后面的類具有父子繼承關系,否則會引起編譯錯誤。
instanceof和(type)是Java提供的兩個相關的運算符,通常先用instanceof判斷一個對象是否可以強制類型轉換,然后再使用(type)運算符進行強制類型轉換,從而保證程序不會出現錯誤。
繼承與組合 使用繼承的注意點為了保證父類有良好的封裝性,不會被子類隨意改變,設計父類通常應該遵循如下規則。
盡量隱藏父類的內部結構。盡量把父類的所有變量都設置成private訪問類型,不要讓子類直接訪問父類的成員變量。
不要讓子類可以隨意訪問、修改父類的方法。父類中那些僅為輔助其他的工具方法,應該使用private訪問控制符修飾,讓子類無法訪問該方法;如果父類中的方法需要被外部類調用,則必須以public修飾,但又不希望子類重寫該方法,可以使用final修飾符(該修飾符后面會有更詳細的介紹)來修飾該方法。如果希望父類的某個方法被子類重寫,但不希望被其他類自由訪問,則可以使用protected來修飾該方法。
盡量不要在父類構造器中調用將要被子類重寫的方法。 將引發空指針異常。
如果想把某些類設置成最終類,既不能被當成父類,則可以使用final修飾這個類;使用private修飾這個類的所有構造器,從而保證子類無法調用該類的構造器,也就無法繼承該類的實例。
何時需要從父類派生新的子類:
子類需要額外增加屬性,而不僅僅是屬性值的改變。
子類需要增加自己獨有的行為方式(包括增加新的方法或重寫父類的方法)。
利用組合實現復用對于繼承而已,子類可以直接獲得父類的public方法,程序使用子類時,將可以直接訪問該子類從父類那里繼承到的方法;而組合則是把舊類對象作為新類的成員變量組合進來,用以實現新類的功能,用戶看到的是新類的方法,而不能看到被組合對象的方法。
繼承要表達的是一種“是(is-a)”的關系,而組合表達的是“有(has-a)”的關系。
初始化塊 使用初始化塊初始化塊是Java類里可出現的第4種成員(前面依次有成員變量、方法和構造器),一個類里可以有多個初始化塊,相同類型的初始化塊之間有順序:前面定義的初始化塊先執行,后面定義的初始化塊后執行。
[修飾符] { //初始化塊的可執行性代碼 }
初始化塊的修飾符只能是static,使用static修飾的初始化塊被稱為靜態初始化塊。初始化塊里的代碼可以包含任何可執行性語句,包括定義局部變量、調用其他對象的方法,以及使用分支、循環語句等。
當創建Java對象時,系統總是先調用該類里定義的初始化塊,如果一個類里定義了2個普通初始化塊,則前面定義的初始化塊先執行,后面定義的初始化塊后執行。初始化塊只在創建Java對象時隱式執行,而且在執行構造器之前執行。
初始化塊和構造器與構造器不同的是,初始化塊是一段固定執行的代碼,它不能接收任何參數。
靜態初始化塊如果定義初始化塊時使用了static修飾符,則這個初始化塊就變成了靜態初始化塊,也被稱為類初始化塊(普通初始化塊負責對對象執行初始化,類初始化塊則負責對類進行初始化)。靜態初始化塊是類相關的,系統將在類初始化階段執行靜態初始化塊,而不是在創建對象時才執行。因此靜態初始化塊總是比普通初始化塊先執行。
靜態初始化塊也被稱為類初始化塊,也屬于類的靜態成員,同樣需要遵循靜態成員不能訪問非靜態成員的規則,因此靜態初始化塊不能訪問非靜態成員,包括不能訪問實例變量和實例方法。
系統在類初始化階段執行靜態初始化塊時,不僅會執行本類的靜態初始化塊,而且還會一直上溯到java.lang.Object類(如果它包含靜態初始化塊),先執行java.lang.Object類的靜態初始化塊(如果有),然后執行其父類的靜態初始化塊······最后才執行該類的靜態初始化塊。
系統在創建一個Java對象時,不僅會執行該類的普通初始化塊和構造器,而且系統會一直上溯到java.lang.Object類,先執行java.lang.Object類的初始化塊,開始執行java.lang.Object的構造器,一次向下執行其父類的初始化塊,開始執行其父類的構造器······最后才執行該類的初始化塊和構造器,返回該類的對象。
當JVM第一次主動使用某個類時,系統會在類準備階段為該類的所有靜態成員變量分配內存;在初始化階段則負責初始化這些靜態成員變量,初始化靜態成員變量就是執行類初始化代碼或者聲明類成員變量時指定的初始值,它們的執行順序與源代碼中的排列順序相同。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66140.html
摘要:對象既是該類事物實實在在存在的個體。類與對象的關系圖類就是汽車汽車就是堆內存中的對象。成員變量成員變量成員函數的車,輪胎數個,跑起來了對象的創建創建對象中創建對象,使用關鍵字在堆內存中開辟了空間,產生了一個實體。 聲明:本文首發于我的個人微信公眾號【Java編程社區】,查看更多文章與學習資源請移步我的公眾號Java編程社區 萬物皆對象 學習Java,我們都聽過這句話:萬物皆對象。那么什...
摘要:是一種典型的面向對象編程語言。這篇文章主要是來初步理解一下面向對象的思維為下面的內容先給一個基礎。針對面向對象編程的更多內容,會在后面的文章里面詳細解釋。他們都稱之為對象。之后,我們再用編程語言,把這種映射編寫出來,就是的面向對象編程啦。 showImg(https://segmentfault.com/img/remote/1460000012983458?w=900&h=500);...
摘要:眾多面向對象的編程思想雖不盡一致,但是無論哪種面向對象編程語言都具有以下的共通功能。原型編程以類為中心的傳統面向對象編程,是以類為基礎生成新對象。而原型模式的面向對象編程語言沒有類這樣一個概念。 什么是面向對象?這個問題往往會問到剛畢業的新手or實習生上,也是往往作為一個技術面試的開頭題。在這里我們不去談如何答(fu)好(yan)問(guo)題(qu),僅談談我所理解的面向對象。 從歷...
摘要:面向對象與面向過程的區別要知道,二者并不是非此即彼,而是相輔相成的。而面向過程,則在微觀上對對象內部進行具體的實現。面向對象的三大特性說到面向對象,就不得不說其三大特性封裝繼承和多態。封裝封裝是面向對象最基礎的特性。 作者:伯特出處:github.com/ruicbAndroid/LoulanPlan聲明:本文出自伯特的《LoulanPlan》,轉載務必注明作者及出處。 剛學習 Jav...
摘要:知識點總結面向對象知識點總結面向對象面向對象概念是相對于面向過程而言,過程其實就是函數,對象是將函數和屬性進行了封裝。指向了該對象關鍵字代表對象。靜態變量所屬于類,所以也稱為類變量成員變量存在于堆內存中。 Java知識點總結(面向對象) @(Java知識點總結)[Java, Java面向對象] [toc] 面向對象概念 是相對于面向過程而言,過程其實就是函數,對象是將函數和屬性進行了封...
摘要:最近在備戰面試的過程中,整理一下面試題。成員變量如果沒有被賦初值,則會自動以類型的默認值而賦值一種情況例外被修飾但沒有被修飾的成員變量必須顯示地賦值而局部變量則不會自動賦值。 最近在備戰面試的過程中,整理一下面試題。大多數題目都是自己手敲的,網上也有很多這樣的總結。自己感覺總是很亂,所以花了很久把自己覺得重要的東西總結了一下。 面向對象和面向過程的區別 面向過程: 優點:性能比面...
閱讀 3212·2023-04-25 18:43
閱讀 891·2021-11-24 09:39
閱讀 1361·2021-10-14 09:43
閱讀 3890·2021-09-22 15:58
閱讀 1899·2019-08-29 17:18
閱讀 409·2019-08-29 14:14
閱讀 3077·2019-08-29 13:01
閱讀 1614·2019-08-29 12:33