為什么要有繼承,繼承的作用?
繼承(inheritance)機制:是面向對象程序設計使代碼可以復用的最重要的手段,它允許程序員在保持原有類特性的基礎上進行擴展,增加新功能,這樣產生新的類,稱派生類。
作用:進行共性抽取,實現代碼的復用
//代碼一
public class Cat {public String name;public int age;public void meow(){System.out.println(this.name + "喵喵叫");}
}
//代碼二
public class Dog {public String name;public int age;public void bark(){System.out.println(this.name + "汪汪叫");}
}
對上述代碼一和代碼二,我們不難發現他們有著共同字段 name 和 age,因此可以將兩段代碼的共性抽取出來,放到Animal類中,如下
public class Animal {public String name;public int age;
}
這樣就將共性抽取了出來,如果以后還有別的動物需定義一個類,就可以繼承Animal類,從而達到代碼的復用。那么怎么寫繼承呢?請看下文。
語法
表示類之間的繼承關系,用 extends 關鍵字。
修飾符 class 子類/派生類 extends 父類/基類/超類{
}//例
public class Animal {public String name;public int age;
}public class Cat extends Animal{//將Animal類字段name和age繼承過來且有自己的成員public void meow(){System.out.println(this.name + "喵喵叫");}
}
- 子類會將父類中的成員變量或成員方法繼承到子類中
- 子類繼承父類后,需添加自己特有的成員,體現出與父類不同,否則沒必要繼承
子類訪問父類成員
- 子類訪問父類成員變量
當父類和子類擁有同名的成員變量時,優先訪問子類成員變量,若要在子類中訪問與父類同名的成員變量,則需借助super關鍵字==(super.成員變量)==- 當父類和子類擁有同名成員方法時,優先訪問子類成員方法,若要在子類中訪問與父類同名的成員方法,則需借助super(super.成員方法)
子類構造方法
子類對象構造時 ,需先調用基類構造方法,來幫助基類成員方法初始化,然后執行子類構造方法。
public class Animal {public String name;public int age;public Animal(String name,int age){this.name = name;this.age = age;}
}public class Dog extends Animal{public Dog(String name,int age){super(name,age);//用super(參數列表名)來調用父類構造方法,幫助父類成員進行初始化System.out.println("==構造方法執行==");}public void bark(){System.out.println(this.name + "汪汪叫");}
}public class Test {public static void main(String[] args) {Dog dog = new Dog("dog",2);}
}
上述代碼中,Dog類這個子類中調用了構造方法(子類構造方法),那么就需要先調用父類的構造方法(用super(參數列表)),也就是Animal類的構造方法來幫助Animal類的成員初始化,然后再繼續執行子類構造方法,打印出構造方法執行。
注意:構造方法中 super(參數列表)或 this(方法名)都必須放在構造方法中的第一行,且不能在靜態方法中使用
如果父類沒有定義構造方法或者定義了無參的構造方法,那么子類構造方法第一行會有隱藏的super()調用(子類構造方法執行前會先調用父類的構造方法【用super()調用】,如果父類沒有顯示定義構造方法,則Java會提供默認的不帶參數的構造方法)
代碼塊執行順序
- 靜態代碼塊先執行且只執行一次,在類加載階段執行
- 當有對象創建時,執行實例代碼塊,后執行構造方法
當有父類和子類時,先執行父類和子類的靜態代碼塊,再執行父類的實例代碼塊和構造方法,再執行子類的實例代碼塊和構造方法,且如果是第二次實例化子類對象時,父類和子類的靜態代碼塊不會再執行(靜態代碼塊只執行一次)
//父類
public class Father {public String name;public int age;static {System.out.println("父類靜態代碼塊");}{System.out.println("父類實例代碼塊");}public Father(String name,int age){this.name = name;this.age = age;System.out.println("父類構造方法");}
}//子類
public class Son extends Father{static {System.out.println("子類靜態代碼塊");}{System.out.println("子類實例代碼塊");}public Son(String name,int age){super(name,age);System.out.println("子類構造方法");}
}//測試類
public class Test {public static void main(String[] args) {Son son = new Son("dog",3);System.out.println("===========================");//分割線Son son2 = new Son("cat",2);}}
有上述代碼和運行結果可知上文所說的執行順序以及靜態代碼塊只執行一次