概述
類的繼承是指在一個現有類的基礎上構建一個新類。
- 新類稱作子類,現有類稱作父類。
- 子類自動擁有父類所有可繼承的屬性和方法。
如何實現類的繼承?
聲明一個類繼承另一個類,需要使用關鍵字extends。
比如我先創建一個Person類,代碼如下:
public class Person {
private char gender;
public Person(){
System.out.println("Person類無參構造方法執行");
}
public char getGender(){
return gender;
}
public void setGender(char gender){
this.gender = gender;
}
public void sleep(){
System.out.println("要睡覺...");
}
}
創建一個Student類,繼承Person類,代碼如下:
public class Student extends Person{
private String name;
int age;
public Student(){}
public Student(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public void intro(){
System.out.println("我的性別是"+getGender());
}
}
創建Student對象,程序入口代碼如下:
public static void main(String[] args) {
Student stu1 = new Student("大西瓜");
stu1.age = 10;
stu1.gender = '男';//報錯,private修飾的成員不可繼承
stu1.setGender('男');
stu1.intro();
stu1.sleep();
}
運行結果如下:
Person類無參構造方法執行
我的性別是男
要睡覺...
可以看出,
- Student類通過extends關鍵字繼承Person類后,雖然沒有沒有定義gender屬性和sleep()方法,卻能訪問兩個成員。
- private修飾的變量gender無法訪問。
這就說明,子類繼承父類時,自動擁有父類所有可繼承的成員。而被private修飾的變量gender則屬於不可繼承的成員。
- 創建的是Student對象,為什么Person類的無參構造會被調用?
這就要從內存創建開始說起,創建Student對象,先開辟堆內存空間。不同以往,開辟的不是Student對象的空間,而是先開辟它的父類對象的空間:
再創建子類對象Student,將父類的引用賦值給新增屬性super
這就是為什么Person類構造方法被調用的原因了,
等於說是開辟了兩塊空間,一父一子兩個對象,其中子類對象中的super屬性指向父類,
我們在訪問子類中不存在、父類中存在的成員時,就相當於是通過這個屬性找到父類成員並訪問的。
繼承與權限修飾符的關系
下面通過這個表,為小伙伴們簡單講解繼承的范圍。
修飾符/訪問范圍 | 同一個類中 | 同一個包中 | 子類中 | 全局范圍 |
---|---|---|---|---|
public | v | v | v | v |
protected | v | v | v | |
default | v | v | ||
private | v |
由上圖,只有private修飾的類或類的成員不能被繼承。
可能細心的小伙伴會發現,Person類中的age變量沒有被修飾,修飾符應該屬於default,結果卻可以被子類訪問
這是因為,
age的修飾符屬於(default)默認修飾符,同一個包下可以訪問,而Person類和student類就在同一個包下。
繼承與類的關系
類的繼承也有限制,請注意:
- Java中類僅支持單繼承、不支持多繼承,即一個類只有一個直接父類。
class A{}
class B{}
class C extends A,B{}//不可同時繼承多個類
- 多個類可以繼承一個類
class A{}
class B extends A{}
class c extends A{}//B類和C類都可以繼承A類
- 多層繼承是允許的,即一個類的父類可以再去繼承別的父類。
class A{}
class B extends A{}//B類繼承A類,B類是A類的子類
class C extends B{}//C類繼承B類,B類繼承A類,C類也是A類的子類、C類可以訪問B類和A類所有可繼承的成員
- 子類可以重寫父類的方法。
子類中的重寫方法和父類被重寫的方法應具有相同的方法名、參數列表、返回值類型。
我們在Student類中添加父類的sleep()方法
//與父類相同的方法名、參數列表、返回值類型。
public void sleep(){
System.out.println(name+"要睡覺...");
}
程序入口,代碼如下:
public static void main(String[] args) {
Student stu1 = new Student("大西瓜");
stu1.sleep();
}
結果如下:
Person類無參構造方法執行
大西瓜要睡覺...
此時發現,JVM調用的的是子類的sleep()方法而不是父類的,這就是方法的重寫。
注意一點:子類重寫父類方法時,不能使用比父類更嚴格的訪問權限,
Person類中sleep()方法不變,子類Student中將修飾符改為比public權限更嚴格的private。
private void sleep(){//報錯,不能使用比父類更嚴格的訪問權限
System.out.println(name+"要睡覺...");
}
但是如果父類的sleep()方法被private修飾,子類sleep()方法被比private權限更寬松的public修飾,則能夠實現重寫,順利運行。