1.類的繼承
1)繼承
父類:所有子類所共有的屬性和行為
子類:子類所特有的屬性和行為
- 通過extends關鍵字來實現類的繼承
- 子類(Sub class)可以繼承父類(Super class)的成員變量及成員方法,同時也可以定義自己的成員變量和成員方法
- Java語言不支持多重繼承,一個類只能繼承一個父類(單一繼承),但一個父類可以有多個子類
- 繼承具有傳遞性,子類的子類可以繼承父類的父類的成員變量及成員方法
2)繼承中構造方法(super關鍵字)
- Java規定:構造子類之前必須先構造父類
- 子類的構造方法中必須通過super關鍵字調用父類的構造方法,這樣可以妥善的初始化繼承自父類的成員變量
- 如果子類的構造方法中沒有調用父類的構造方法,Java編譯器會自動的加入對父類無參構造方法的調用(如果該父類沒有無參的構造方法,則會出現編譯錯誤)
- super()調父類構造必須位於子類構造的第一句
- super指代當前對象的父類對象
super的用法:
- super.成員變量名:訪問父類的成員變量
- super.方法名():調用父類的方法
- super():調用父類的構造方法
案例1:調用父類無參構造
public class Person {
String name;
char gender;
}
public class Student extends Person {
// super (); //編譯錯誤,必須位於子類構造方法的第一句
double score;
Student(double score){
super(); //編譯器默認會自動加上
this.score = score;
super.name = "Tom";
}
}
案例2:調用父類有參構造
public class Person {
String name;
char gender;
Person(String name,char gender){
this.name = name;
this.gender = gender;
}
}
public class Student extends Person {
// super (); //編譯錯誤,必須位於子類構造方法的第一句
double score;
Student(String name,char gender,double score){
// super(); //編譯錯誤,父類中沒有無參構造
super(name,gender); //調用父類有參構造
this.score = score;
super.name = "Tom";
}
}
3)向上造型
- 一個子類的對象可以向上造型為父類的類型。即定義父類型的引用可以指向子類的對象
- 父類的引用可以指向子類的對象,但通過父類的引用只能訪問父類所定義的成員,不能訪問子類擴展的部分(能點出什么看引用)
案例3:向上造型
public class Person {
String name;
char gender;
Person(String name,char gender){
this.name = name;
this.gender = gender;
}
}
public class Student extends Person {
double score;
Student(String name,char gender,double score){
super(name,gender); //調用父類有參構造
this.score = score;
super.name = "Tom";
}
public static void main(String[] args) {
Person p = new Student("Tom",'男',80); //向上造型
p.score = 100; //編譯錯誤,Java編譯器會根據引用的類型(Person),而不是對象的類型(Student)來檢查調用的方法是否匹配。
}
}
2.方法的重寫(Override)
- 發生在父子類中,方法簽名相同,方法體不同:子類可以重寫(覆蓋)繼承自父類的方法,即方法名和參數列表與父類的方法相同,但方法的實現不同(方法體不同)
- 重寫方法被調用時,看對象的類型:當子類對象的重寫方法被調用時(無論是通過子類的引用調用還是通過父類的引用調用),運行的是子類的重寫后的版本
- 子類在重寫父類的方法時,可以通過super關鍵字調用父類的版本,這樣的語法通常用於子類的重寫方法在父類方法的基礎之上進行功能擴展。
1).重寫原則
重寫遵循“兩同兩小一大”原則:
1)兩同:
1.1)方法名相同
1.2)參數列表相同
2)兩小:
2.1)子類方法的返回值類型要小於或等於父類
2.1.1)void時,必須相同
2.1.2)基本數據類型時,必須相同
2.1.3)引用類型時,小於或等於
2.2)子類方法拋出的異常要小於或等於父類的----異常之后
3)一大:
3.1)子類方法的訪問權限要大於或等於父類的----訪問控制修飾符之后
class Aoo{ void show(){} double test(){return 0.0;} Boo sayHi(){return null;} public Aoo say(){return null;} } class Boo extends Aoo{ //int show(){return 1;} //編譯錯誤,void時必須相同 //int test(){return 0;} //編譯錯誤,基本類型時必須相同 //Aoo sayHi(){return null;} //編譯錯誤,引用類型必須小於或等於 public Boo say(){return null;} }
案例4:方法重寫
public class Student {
public static void main(String[] args) {
Goo o = new Goo();
o.f();
Foo oo = new Goo();
oo.f();
}
}
class Foo{
public void f(){
System.out.println("Foo.f()");
}
}
class Goo extends Foo{
public void f(){
System.out.println("Goo.f()");
}
}
//當子類對象的重寫方法被調用時(無論通過子類的引用還是通過父類的引用),運行的都是子類重寫后的方法。
/*
運行結果:
Goo.f()
Goo.f()
*/
案例5:方法重寫,super調用父類版本
public class Student {
public static void main(String[] args) {
Goo o = new Goo();
o.f();
Foo oo = new Goo();
oo.f();
}
}
class Foo{
public void f(){
System.out.println("Foo.f()");
}
}
class Goo extends Foo{
public void f(){
super.f(); //調用父類的方法
System.out.println("Goo.f()");
}
}
//子類重寫方法中的super.f(); 調用了父類的版本,這樣的語法通常用於子類的重寫方法再父類方法的基礎之上進行功能擴展。
/*
運行結果:
Foo.f()
Goo.f()
Foo.f()
Goo.f()
*/
2)重寫和重載的區別
- 重寫(Override):1.發生在父子類中,(方法簽名相同)方法名稱相同,參數列表相同,方法體不同 2.遵循“運行期”綁定,重寫方法被調用時,看對象的類型
- 重載(Overload):1.發生在同一類中,方法名稱相同,參數列表不同,方法體不同 2.遵循“編譯期”綁定,看引用的類型綁定方法
案例6:重寫與重載區別
public class OverrideAndOverload { public static void main(String[] args){ Super obj = new Sub(); //向上造型 Goo goo = new Goo(); goo.g(obj); } } class Super{ public void f(){ System.out.println("super.f()"); } } class Sub extends Super{ public void f(){ //方法重寫 System.out.println("sub.f()"); } } class Goo{ public void g(Super obj){ System.out.println("g(Super)"); obj.f(); } public void g(Sub obj){ //方法重載 System.out.println("g(Sub)"); obj.f(); } }
以上代碼運行結果:
g(Super) sub.f()