前文咱們瞭解了面向對象的三大特徵:封裝、繼承、多態。html
那麼在Java中是如何展示繼承的特性呢?對於子類繼承於父類時,又有什麼限制呢?數據結構
在此解答這些問題以後,咱們再瞭解下類的加載過程,加深對繼承的瞭解。ide
(若文章有不正之處,或難以理解的地方,請多多諒解,歡迎指正)this
假如咱們有兩個類:生物類、貓類。spa
生物類:.net
class Animal{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return this.name; } }
貓類:code
class Cat{ private String name; private String sound; public void setName(String name){ this.name = name; } public void setSound(String sound){ this.sound = sound; } public String getName(){ return this.name; } public String getSound(){ return this.sound; } }
咱們知道,貓也是屬於生物中的一種,生物有的屬性和行爲,貓按理來講也是有的。但此時沒有繼承的概念,那麼代碼就得不到複用,長期發展,代碼冗餘、維護困難且開發者的工做量也很是大。htm
繼承就是子類繼承父類的特徵和行爲,使得子類對象(實例)具備父類的實例域和方法,或子類從父類繼承方法,使得子類具備父類相同的行爲。
簡單來講,子類能吸取父類已有的屬性和行爲。除此以外,子類還能夠擴展自身功能。子類又被稱爲派生類,父類被稱爲超類。對象
在Java中,若是要實現繼承的關係,可使用以下語法:blog
class 子類 extends 父類{}
繼承的基本實現以下:
class Animal{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return this.name; } } class Cat extends Animal{} public class Test{ public static void main(String[] args){ Cat cat = new Cat(); cat.setName("貓"); System.out.println(cat.getName()); } }
運行結果爲:
貓
咱們能夠看出,子類能夠在不擴展操做的狀況下,使用父類的屬性和功能。
繼承的基本實現以下:
class Animal{ private String name; public void setName(String name){ this.name = name; } public String getName(){ return this.name; } } class Cat extends Animal{ private String sound; public void setSound(String sound){ this.sound = sound; } public String getSound(){ return this.sound; } } public class Test{ public static void main(String\[\] args){ Cat cat = new Cat(); cat.setName("NYforSF") cat.setSound("我不是你最愛的小甜甜了嗎?"); System.out.println(cat.getName()+":"+cat.getSound()); } }
運行結果爲:
NYforSF:我不是你最愛的小甜甜了嗎?
咱們能夠看出,子類在父類的基礎上進行了擴展,並且對於父類來講,子類定義的範圍更爲具體。也就是說,子類是將父類具體化的一種手段。
總結一下,Java中的繼承利用子類和父類的關係,能夠實現代碼複用,子類還能夠根據需求擴展功能。
爲何子類不能多繼承?舉個栗子。
class ACat{ public void mewo(){...} } class BCat{ public void mewo(){...} } class CCat extends ACat, BCat{ @Override public void mewo(){...?} //提問:這裏的mewo()是繼承自哪一個類? }
雖然說Java只支持單繼承,可是不反對多層繼承呀!
class ACat{} class BCat extends ACat{} class CCat extends BCat{}
這樣,BCat就繼承了ACat全部的方法,而CCat繼承了ACat、BCat全部的方法,實際上CCat是ACat的子(孫)類,是BCat的子類。
總結一下,子類雖然不支持多重繼承,只能單繼承,可是能夠多層繼承。
對於子類來講,父類中用private修飾的屬性對其隱藏的,但若是提供了這個變量的setter/getter接口,仍是可以訪問和修改這個變量的。
class ACat { private String sound = "meow"; public String getSound() { return sound; } public void setSound(String sound) { this.sound = sound; } } class BCat extends ACat { } public class Test { public static void main(String[] args) { BCat b = new BCat(); b.setSound("我不是你最愛的小甜甜了嗎?"); System.out.println(b.getSound()); } }
父類已經定義好的final修飾變量(方法也同樣),子類能夠訪問這個屬性(或方法),可是不能對其進行更改。
class ACat { final String sound = "你是我最愛的小甜甜"; public String getSound() { return sound; } public void setSound(String sound){ this.sound = sound; //這句執行不了,會報錯的 } } class BCat extends ACat { }
總結一下,用private修飾的變量能夠經過getter/setter接口來操做,final修飾的變量就只能訪問,不能更改。
在實例化子類對象時,會調用父類的構造方法對屬性進行初始化,以後再調用子類的構造方法。
class A { public A(){ System.out.println("我不是你最愛的小甜甜了嗎?"); } public A(String q){ System.out.println(q); } } class B extends A { public B(){ System.out.println("你是個好姑娘"); } } public class Test { public static void main(String[] args) { B b = new B(); } }
運行結果爲:
我不是你最愛的小甜甜了嗎? 你是個好姑娘
從結果咱們能夠知道,在實例化子類時,會默認先調用父類中無參構造方法,而後再調動子類的構造方法。
那麼怎麼調用父類帶參的構造方法呢?只要在子類構造方法的第一行調用super()方法就好。
class A { public A(String q){ System.out.println(q); } } class B extends A { public B(){ super("我是你的小甜甜?"); System.out.println("你是個好姑娘"); } } public class Test { public static void main(String\[\] args) { B b = new B(); } }
運行結果爲:
我是你的小甜甜? 你是個好姑娘
在子類實例化時,默認調用的是父類的無參構造方法,而若是沒有父類無參構造方法,則子類必須經過super()來調用父類的有參構造方法,且super()方法必須在子類構造方法的首行。
總結一下,Java繼承中有三種繼承限制,分別是子類只能單繼承、父類中private修飾的變量不能顯式訪問和final修飾的變量不能改變,以及實例化子類一定會先調用父類的構造方法,以後才調用子類的構造方法。
(此處只是粗略介紹類加載的過程,想了解更多可參考《深刻理解Java虛擬機》)
類加載過程包括三個大步驟:加載、鏈接、初始化。
這三個步驟的開始時間仍然保持着固定的前後順序,可是進行和完成的進度就不必定是這樣的順序了。
總結一下,類加載的過程當中,首先會對Class文件中的類提取並轉換成運行時數據結構,而後對類的父類和這個類的數據信息進行檢驗以後,爲類中的類變量分配內存而且設置初始值,接着將Class文件中與這個類有關的符號引用轉換成直接引用,最後再執行類構造器。
並且咱們能夠從第二步看出,在加載類的時候,會先去檢查這個類的父類的信息,而後再檢查這個類的方法體,也就是說,在加載類的時候,會先去加載它的父類。
初學Java的時候知道這些概念,但只是淺嘗而止。如今跟着Hollis大佬的《Java 工程師成神之路!》,從新回顧這些知識的時候,發現若是本身只是像之前同樣片面瞭解,那豈不是沒有成長?因此在寫文章的過程當中,嘗試寫得更加深刻且儘可能易懂。固然,本人水平有限,若有不正之處,歡迎指正。
若是本文對你有幫助,請點一個贊吧,這對我來講是最大的動力~
參考資料: