JavaSE學習筆記(3.Java類的介紹)
1.類的成員:
類的成員包括:構造器、類成員變數、例項成員變數、類方法、例項方法、類初始化塊、例項初始化塊
2.構造器描述:
a.構造器名必須與類名相同,在類的例項化過程中,需要呼叫構造器,如果類沒有構造器,系統會預設提供一個預設的無參構造器。
b.構造器不能定義返回型別(包括void型別),如果構造器存在返回型別,系統會將其當做一個類的方法而不是構造器!
c.構造器可支援過載
d.public修飾構造器,類可以在類內類外例項化;private修飾構造器,類只能在類內例項化(單例模式的實現依賴於這種方式)
單例模式的程式碼:
public class Test { public static void main(String arg[]){ Data d = Data.getInstance(); Data d1 = Data.getInstance(); System.out.println(d == d1); } } class Data{ private static Data Instance = null; private Data(){ System.out.println("Data Init"); } public static Data getInstance() { if(null == Instance) { Instance = new Data(); } return Instance; } }
e.類例項化的過程,會預設將例項成員變數進行初始化,基本型別變數賦值為0/false,引用型別變數賦值為null
3.this物件:
a.this物件表示的是當前物件,即當前執行態執行方法或者獲取成員變數的物件,通過這個原則就可以知道當前訪問的是那個例項的成員
b.this訪問的都是例項成員,是需要例項化後才可以訪問的,所以static修飾的靜態類方法中是不可以使用this來訪問例項成員的
c.通常情況下,訪問例項成員的時候有this和沒有this是一樣的,但是當例項成員和區域性變數重名的時候,為了避免歧義就要使用this物件來區分!
d.構造器發生過載的時候,在構造器內部需要呼叫其他構造器的時候,需要使用this作為構造器名
public class Test{
public static void main(String arg[]){
Data d = new Data("java test");
}
}
class Data{
public Data()
{
System.out.println("Data init");
}
public Data(String name)
{
/*必須放到第一行*/
this();
System.out.println("Data "+name+" init");
}
}
Ps:只有構造器中才可以呼叫構造器,而且構造器其中呼叫構造器必須放到函式第一行!
4.可變長行參:
Java1.5 引入形參可變長,格式為:【型別... 變數名】,只能放在引數列表的最後。本質就是陣列,但是入參選擇陣列形式也可以選擇可變長行參形式,具體程式碼如下:
public class Test{
public static void main(String arg[]){
Data d = new Data();
/*可變引數形式*/
d.TestFun(2,3,4,5,6);
/*陣列形式,過載的時候只能使用陣列的形式*/
d.TestFun(2,new int[]{3,4,5,6});
}
}
class Data{
public void TestFun(int a,int... b){
for(int temp : b)
{
System.out.println(temp);
}
}
}
Ps:當使用可變長形參的時候,如果發生方法過載,必須使用陣列形式作為入參!Java的過載為,同類中方法名相同,引數列表不同,與返回值和修飾符無關!
4.類的繼承:
a.Java為單繼承,但是介面可以用來補充多繼承
b.方法重寫:
1)子類父類方法名相同,入參相同;
2)子類方法的返回值型別比父類方法的返回值型別小或者相對;
3)子類方法宣告丟擲異常類比父類方法宣告丟擲異常類小或者相等;
4)子類方法訪問許可權比父類方法訪問許可權大或者相等;
5)子類父類方法同為類方法或者同為例項方法;
Ps:與方法過載比較,方法過載發生在同一個類內,方法名相同,入參不同的時候(返回值型別、方法修飾符不參與判斷);方法重寫發生在父類子類之間,方法名相同,入參相同的時候;但是如果不滿足如上條件2、條件3、條件4、條件5,編譯會報錯!
c.方法重寫的時候,要注意儘可能的避免在父類建構函式中呼叫被重寫的方法,因為當子類構造父類的時候,子類呼叫父類的建構函式,父類建構函式中呼叫的是子類重寫後的方法(原因是因為當前執行的物件為子類物件,通過列印this物件可以看到),設計不好,容易觸發邏輯異常!
public class Test{
public static void main(String arg[]){
DataTemp d = new DataTemp();
}
}
class Data{
public Data(){
System.out.println(this);
test();
}
public void test(){
System.out.println("Data Init");
}
}
class DataTemp extends Data{
public DataTemp(){
System.out.println(this);
test();
}
public void test(){
System.out.println("DataTemp Init");
}
}
輸出:
[email protected]
DataTemp Init
[email protected]
DataTemp Init
c.當建立一個子類物件的時候,系統不僅僅會為子類成員分配記憶體空間,同時也會為其所有父類分配記憶體空間,並且會從上至下呼叫建構函式!子類呼叫父類建構函式的順序如下:
5.super限定:
a.super限定用來獲取父類中的例項方法和例項成員變數,主要應用於方法的重寫和子父類中同名成員的覆蓋場景!
b.子類建構函式中,呼叫父類建構函式,使用super();super()也需要放在構造器中的第一行,所以super()和this()不能同時使用!
6.類的多型:
a.當一個引用變數,在編譯期型別和執行期型別不一樣的時候,就可能發生多型!
b.java引用型別預設都是向上轉換的,就是可以將子類賦值給父類;當父類賦值給子類的時候就需要強制型別轉換並且保證執行期,父類的內容就是這個子類內容,不然會丟擲異常!
c.強制型別轉換前,可以使用instanceof運算子來(if (object instanceof TYPE)),判斷前一個引數object物件是否是TYPE類或者TYPE子類的例項,進而判斷是否可以強制型別轉換成功,instanceof前後引數在編譯期必須要存在父子類關係,不然會編譯報錯!
7.初始化塊的描述:
a.初始化塊就是執行在構造器前面的一段程式碼塊,如果該程式碼塊寫在變數初始化前面,程式碼塊會在變數初始化前完成;如果程式碼塊寫在變數初始化後面,程式碼塊會改變變數初始化的值,當執行完變數初始化和初始化塊後再執行構造器;多個初始化塊會按照先後順序執行;初始化塊不存在繼承!
b.初始化塊的本質:初始化塊設計的本質就是將多個構造器中的,引數無關的公共程式碼統一處理;通過檢視class檔案可以發現,初始化塊在編譯後消失了,分別被編譯器放到每個構造器中去了!
c.staic修飾靜態類初始化塊:例項初始化塊是在物件建立的時候執行的,類初始化塊是在類建立的時候執行的,所以屬於類成員;類成員統一滿足一個原則,不能訪問例項成員,包括例項成員變數、例項方法、super、this物件!