1 繼承
繼承的實現:public class 子類 extends 父類 {… }
注釋:子類可直接使用,父類(保護,公開)的屬性和方法
優點:減少重復代碼,缺點:只能單繼承
// 父類
public class Test {private String str1; //私有String str2; //默認protected String str3;// 保護public String str4; //公開private void fn1() {} //私有void fn2() {} //默認protected void fn3() {}// 保護public void fn4() {} //公開
}
// 子類
public class SubTest extends Test {public void subFn1() {String t3 = str3;String t4 = str4;fn3();fn4();}
}
2 子類實例化
子類構造器默認先調用父類無參構造器(可省略),父類沒有無參構造器(必須先顯示調用有參構造器)
public class 子類 extends 父類 {public 子類() {[super();] // 可省略子類處理…}
}
3 方法重寫
注釋:子類定義了與父類相同的方法(方法重寫)
// 父類
public class Test {public String name = "張三";public void doTest() {System.out.println(name);}
}
測試類1:子類未重寫方法,調父類方法使用的是父類屬性(不會輸出子類同名屬性)
// 子類
public class SubTest1 extends Test {public String name = "李四";
}
public class Main {public static void main(String[] args) {SubTest1 s = new SubTest1(); System.out.println(s.name); //輸出 李四s.doTest(); //輸出 張三(子類沒有該方法,父類該方法輸出父類名字)}
}
測試類2:子類重寫屬性方法后,使用的是子類的屬性
//子類
public class SubTest2 extends Test {public String name = "李四";public void doTest() {System.out.println("son:"+name);}
}
public class Main {public static void main(String[] args) {SubTest2 s = new SubTest2();System.out.println(s.name); // 輸出 李四s.doTest();// 輸出 son:李四}
}
測試類3:子類對象定義為父類類型,輸出父類屬性,調用的是子類方法
//子類
public class SubTest2 extends Test {public String name = "李四";public void doTest() {System.out.println("son:"+name);}
}
public class Main {public static void main(String[] args) {Test s = new SubTest2();System.out.println(s.name); // 輸出 張三s.doTest(); // 輸出 son:李四}
}
測試類4:子類對象強轉父類類型,輸出父類屬性,調用的是子類方法
//子類
public class SubTest2 extends Test {public String name = "李四";public void doTest() {System.out.println("son:"+name);}
}
public class Main {public static void main(String[] args) {SubTest2 s = new SubTest2();Test ss = (Test)s;System.out.println(ss.name); // 輸出 張三ss.doTest(); // 輸出 son:李四}
}
4 方法重載
方法名(相同),參數(個數或類型)(不同),與返回值無關
public class Test {public String fn(String str){ }// 重載1,參數類型不同public String fn(int num) {}// 重載2,參數個數不同public String fn(int age, int num) {}}
5 super關鍵字
注釋:只可在子類內部使用,使子類可以使用父類原生方法與屬性
(1) 調用父類構造器:super([參數…]);
(2) 調用父類屬性:super.屬性; //?獲取與更改父類的屬性,不影響子類同名屬性
(3) 調用父類方法:super.方法(); //?調用父類的方法,與子類是否重寫無關
// 父類
public class Test {private String str1 = "私有";String str2 = "默認";protected String str3 = "保護";public String str4 = "公開";private String fn1() { return str1; }String fn2() { return str2; }protected String fn3() { return str3; }public String fn4() { return str4; }
}
// 子類
public class SubTest extends Test {protected String str3 = "保護(son)";public String str4 = "公開(son)";protected String fn3() { return str3; }public String fn4() { return str4; }// 調用父類構造器(默認不寫也調用)public SubTest() {super();}// 調用父類方法public void test() {System.out.println(super.str3); // 輸出 父類 保護System.out.println(super.str4); // 輸出 父類 公開System.out.println(super.fn3()); // 輸出 父類 保護System.out.println(super.fn4()); // 輸出 父類 公開}public void testSub() {System.out.println(str3); // 輸出 子類 保護(son)System.out.println(str4); // 輸出 子類 公開(son)System.out.println(fn3()); // 輸出 子類 保護(son)System.out.println(fn4()); // 輸出 子類 公開(son)}
}
6 代碼執行順序
6.1 靜態方法
// 初次調用:類名.靜態方法()?
1.類加載(靜態變量初期化,只執行1次)
2.類加載(靜態代碼塊,只執行1次)
3.靜態方法執行
// 之后再調用:類名.靜態方法() // 只重復執行3
3.靜態方法執行
6.2 實例化對象
// 初次實例化:new 對象()
1.類加載(靜態變量初期化,只執行1次)
2.類加載(靜態代碼塊,只執行1次)
3.代碼塊(執行)
4.構造器(執行)
// 之后再實例化:new 對象()??// 只重復執行3,4
3.代碼塊(執行)
4.構造器(執行)
6.3 子類靜態方法
// 初次調用:子類.靜態方法()?
1.父類加載(靜態變量初期化,只執行1次)
2.父類加載(靜態代碼塊,只執行1次)
3.子類加載(靜態變量初期化,只執行1次)
4.子類加載(靜態代碼塊,只執行1次)
5.子類靜態方法(執行)
// 之后再調用:子類.靜態方法()??// 只重復執行5
5.子類靜態方法(執行)
6.4 子類實例化對象
// 初次調用:new 子類對象()?
1.父類加載(靜態變量初期化,只執行1次)
2.父類加載(靜態代碼塊,只執行1次)
3.子類加載(靜態變量初期化,只執行1次)
4.子類加載(靜態代碼塊,只執行1次)
5.父類代碼塊(執行)
6.父類構造器(執行)
7.子類代碼塊(執行)
8.子類構造器(執行)
// 之后再調用:new 子類對象()??// 只重復執行5,6,7,8
5.父類代碼塊(執行)
6.父類構造器(執行)
7.子類代碼塊(執行)
8.子類構造器(執行)
總結:1 只有初次類加載初始化靜態變量,執行靜態代碼塊。2 父類(變量,代碼塊,構造器)優先于子類執行。3?代碼塊優先于構造器執行。