04-繼承
繼承
Java使用extends關鍵字來實現繼承:
Java沒有明確寫extends
的類,編譯器會自動加上extends Object
Java只允許一個class繼承自一個類,因此,一個類有且僅有一個父類。只有Object
特殊,它沒有父類。
class Person {
private String name;
private int age;
}
class Student extends Person {
private String id;
}
子類自動獲得了父類的所有欄位,嚴禁定義與父類重名的欄位!
protect
繼承有個特點,就是子類無法訪問父類的private欄位或者private方法。例如,Student
Person
類的name
和age
欄位
為了讓子類可以訪問父類的欄位,我們需要把private
改為protected
。用protected
修飾的欄位可以被子類訪問
protected
關鍵字可以把欄位和方法的訪問許可權控制在繼承樹內部,一個protected
欄位和方法可以被其子類,以及子類的子類所訪問
class Person { protected String name; protected int age; } class Student extends Person { public String hello() { return "Hello, " + name; // OK! } }
super
super
關鍵字表示父類(超類)。子類引用父類的欄位時,可以用super.fieldName
class Student extends Person {
public String hello() {
return "Hello, " + super.name;
}
}
在Java中,任何class
的構造方法,第一行語句必須是呼叫父類的構造方法。如果沒有明確地呼叫父類的構造方法,編譯器會幫我們自動加一句super()
;,所以,Student
類的構造方法實際上是這樣:
class Student extends Person { protected int score; public Student(String name, int age, int score) { super(); // 自動呼叫父類的構造方法 this.score = score; } }
如果父類沒有預設的構造方法,子類就必須顯式呼叫super()
並給出引數以便讓編譯器定位到父類的一個合適的構造方法。
這裡還順帶引出了另一個問題:即子類不會繼承
任何父類的構造方法。子類預設的構造方法是編譯器自動生成的,不是繼承的。
class Student extends Person {
protected int score;
public Student(String name, int age, int score) {
super(name, age); // 呼叫父類的構造方法Person(String, int)
this.score = score;
}
}
阻止繼承
正常情況下,只要某個class沒有final
修飾符,那麼任何類都可以從該class繼承。
向上轉型
Person p = new Student(); //
這是因為Student繼承自Person,因此,它擁有Person的全部功能
這種把一個子類型別安全地變為父類型別的賦值,被稱為向上轉型(upcasting)
向上轉型實際上是把一個子型別安全地變為更加抽象的父型別:
注意到繼承樹是Student > Person > Object
,所以,可以把Student
型別轉型為Person
,或者更高層次的Object
向下轉型
和向上轉型相反,如果把一個父類型別強制轉型為子類型別,就是向下轉型(downcasting)
Person p1 = new Student(); // upcasting, ok
Person p2 = new Person();
Student s1 = (Student) p1; // ok
Student s2 = (Student) p2; // runtime error! ClassCastException!
子類功能比父類多,多的功能無法憑空變出來。因此,向下轉型很可能會失敗。失敗的時候,Java虛擬機器會報ClassCastException。
為了避免向下轉型出錯,Java提供了instanceof操作符,可以先判斷一個例項究竟是不是某種型別:
Person p = new Person();
System.out.println(p instanceof Person); // true
System.out.println(p instanceof Student); // false
instanceof
實際上判斷一個變數所指向的例項是否是指定型別,或者這個型別的子類。如果一個引用變數為null
,那麼對任何instanceof
的判斷都為false