和現實世界中:子女能夠繼承父母的一些特徵(如:基因)、財產等同樣。OOP 中也有提供相似的特性,一個類徹底能夠從其它類裏得到一些屬性和方法,而不須要咱們本身從新定義。這種特性簡單但強大 (Simple and powerful)。java
在 Java 的繼承關係裏:子類能夠從獲取父類的全部的公共和受保護成員(字段、方法和內部類)。固然,構造方法不是成員 (members) ,因此不能被繼承。同時,在 Java 的繼承裏,子類能夠作以下事情:安全
當子類擁有和父類(或接口)一樣方法簽名的方法,這種現象叫作覆蓋。如如下代碼:ide
class Father { public void doSomthing(){ // Father do something } } class Son extends Father{ @Override public void doSomething(){ // Son do something } }
對於實例方法的覆蓋,實際是子類擁有本身的方法。
對於靜態方法的覆蓋,要記住:靜態方法時屬於類的,在多態中,調用的始終是類的方法。接口裏的靜態方法永遠不會被覆蓋。優化
Father father = new Son(); Father.staticMethod(); // 這裏使用的是父類Father的靜態方法
對於接口方法的覆蓋,遵循如下原則:
1.實例方法的優先級大於接口方法 (JDK8+)code
interface Animal{ default void saySomething(){ // Animal say something } } interface Cow extends Animal{ default void saySomething(){ // Cow say something } } class MyCow implements Cow{ @Override public void saySomething(){ // MyCow say something } Animal myCow = new MyCow(); myCow.saySomething(); // MyCow say something }
2.有共同祖先的接口,先被覆蓋的方法(繼承深度低)會被後覆蓋的方法(繼承級別高)覆蓋對象
interface Animal{ default void saySomething(){ // Animal say something } } interface Pig extends Animal{ default void saySomething(){ // Pig say something } } interface BigPig extends Pig{ default void saySomething(){ // BigPig say something } } class MyPig implements Pig, BigPig{ public static void main(String...args){ MyPig myPig = new MyPig(); myPig.saySomething(); // BigPig saySomething() } }
P.S. 若是出現同一繼承級別(上例中 BigPig 和 Pig 都繼承 Animal 接口)或者子類繼承的接口無相關關係,可是接口間有同方法簽名的方法,就會出現覆蓋衝突。須要用 super
關鍵字指明具體實現哪一個接口的方法或者直接覆蓋。繼承
interface Run{ default void run(){ // Run run } } interface Car{ default void run(){ // Car run } } class MyCar implements Run, Car{ @Override public void run(){ Car.super.run(); } }
同時,咱們須要注意,Java 子類覆蓋父類方法,應該:接口
若是子類定義和父類同方法簽名的方法,會有以下結果:ip
x | 父類的實例方法 | 父類的靜態方法 |
---|---|---|
子類的實例方法 | 覆蓋父類方法 | 編譯錯誤 |
子類的靜態方法 | 編譯錯誤 | 隱藏父類方法 |
咱們已經知道,子類能夠覆蓋父類的方法。若是有一個類繼承自另一個類,咱們徹底能夠用一個父類來引用一個子類,如:get
class Person{ public void saySomething(){ // Person say something } } class Father{ @Override public void saySomething(){ // Father say something } } class Test{ pubilc static void main(String...args){ Father father = new Father(); Person person = father; // 父類引用子類對象 } }
像這種父類引用子類對象的現象,Java 裏叫作多態 (Polymorphism)。在 Java 裏,只有知足以下三個條件,才能叫多態:
對於多態方法的運行,編譯器會列舉全部父類和子類符合調用方法簽名(方法名+參數列表)的方法,而後以如下原則編譯、調用方法:
其中,調用 private, final, static 方法的過程叫靜態綁定,不然叫動態綁定。
在使用多態的過程當中,最有效的判斷語句可否經過編譯的方法是:
右邊的類是不是(IS-A)左邊的類
如示例代碼裏的 father(Father) IS-A Person。
有些狀況下,咱們可能不但願子類覆蓋父類的方法,這時候,用 final 關鍵字修飾方法便可實現該目的。編譯器能夠對用final的方法進行內聯操做優化處理。
在多態裏,咱們知道一個父類能夠引用一個子類對象:
Father father = new Son();
可是,反過來就不行了:
Son son = new Father();
若是須要讓編譯器不報錯,咱們就得進行強制類型轉換操做:
Son son = (Son)new Father();
不過,這麼作有風險,咱們通常要使用 instanceof
關鍵字先判斷,可否將父類「安全」轉換成子類:
Father f = ...; if (f instanceof Son){ Son son = (Son)f; }
在繼承體系裏,比較經常使用的就是抽象類和接口。它們比較類似:
然而,它們仍是有不一樣的,例如:
而後,抽象類和接口有不一樣的使用場景:P
抽象類:
接口:
在 Java 裏,咱們通常按照以下規則使用繼承:
is-a
原則