深入理解Java中super關鍵字
之前一直以為super和this是相同的,this指代子類當前物件,super指代父類物件。之前與實驗室師兄還談論過這個問題,當時他說的super只是Java中一個關鍵字,與this並不相同。一直有疑惑,覺得下面這篇部落格分析的比較到位。
Java中關鍵字
super表示的真正物件
java中的super,大家都知道是表示一個父類的引用。上次群裡見到一個網友詢問 super.getClass().getName()的輸出問題,大部分都知道輸出的是當前這個類的類名。而不是父類的名稱。關於這個問題的解釋很多,基本都是說getClass()是一個final方法,說這個方法都是呼叫超父類Object的方法。這個解釋很好,也容易理解,不過,我們從super這個關鍵詞的本質入手,就能更清楚,為什麼super.getClass().getName()會輸出當前類的名稱了。
先定義兩個類,一個父類,一個繼承的子類。
父類:
子類:public class Parent { public String name; private int code; public Parent parent; //定義幾個父類成員屬性,parent將指向this父類物件 public Parent() { //parent指向this,就是當前例項的父類物件,並輸出hashcode和給code屬性賦值 parent=this; code=1001; System.out.println("Parent's code is:"+code); System.out.println("Parent hashcode is:"+this.hashCode()); } //定義一個過載的構造方法,用於測試使用了哪個父類構造方法 public Parent(String name){ parent=this; this.name=name; System.out.println("Parent's name is"+name); code=1002; System.out.println("Parent's code is"+code); System.out.println("Parent hashcode is:"+this.hashCode()); } public int getCode() { //列印父類code屬性值, System.out.println("Parent :print code :"+code); return code; } }
public class Child extends Parent{ public String childName; private int childCode; //定義兩個類的不同修飾符的屬性 public Child(String childName) { //給屬性賦值 this.childName=childName; //輸出屬性值,和類的hashcode值 System.out.println("child's childName is:"+childName); System.out.println("child hashcode is:"+this.hashCode()); } //測試方法 public void test() { //通過super獲取父類中的parent,這個成員就表示了父類物件。 Child testChild=(Child)super.parent; //強轉parent為子類型別。並輸出子類中定義的屬性,和獲取父類getCode()方法 System.out.println("testChild name is:"+testChild.childName); testChild.getCode(); } public static void main(String[] args) { //例項化 Child c=new Child("window"); c.test(); } }
執行結果:
Parent's code is:1001
Parent hashcode is:366712642
child's childName is:window
child hashcode is:366712642
testChild name is:window
Parent :print code :1001
Parent's code is:1001
//表示執行了父類預設的構造器。其實在子類的構造器中,只要沒有顯示呼叫this和super,都會預設呼叫父類無參構造器,即:super(); Parent
hashcode is:366712642
//這裡是父類物件的雜湊值
child's childName is:window
//呼叫子類的構造方法,輸出childName和hashcode碼值,大家可以看到,父類的this物件和子類例項的物件,hashcode碼是相同的。
child hashcode is:366712642
* //這裡執行test()方法的結果。
//使用Child testChild=(Child)super.parent 強制轉換父類中指向父類this物件的parent物件為子類Child物件,並輸出子類childName屬性值。
testChild name is:window
//輸出結果上可以看出,這個parent其實就是子類的例項物件。應該說記憶體中的物件是同一個,只是不同的表示方式。
//執行testChild.getCode(); 呼叫父類的getCode()方法,輸出的和父類構造方法中的code值是相同的。
Parent :print code :1001
從上面可以看出super這個關鍵字所表示的引用父類物件,其實和當前例項化的子類物件在記憶體中是同一個物件,雖然不知道sun 的虛擬機器是如何實現這個關鍵字的,但是這個super的等同效果就是(Parent)this,這裡的this是當前代表當前例項化的子類物件。
通過在父類中新增一個Parent型別的成員,來指向父類例項化的那個this物件,達到引用父類物件的目的,使用super.parent來獲得父類parent物件的引用。
執行的結果表明,這個parent應用的其實就是當前子類例項物件,通過強制轉換為子類型別,這個父類Parent型別的parent也可以讀取成員childName屬性值。就表明了他們在記憶體中是同一個物件。而且他們的hashcode值也是相同的。
java說明中指出,super是代表父類物件的引用,而super()表示應用父類的預設構造方法,看起來這個super和c中的define有點相同作用的效果。在這個例子中,super代表的父類物件的引用,和父類中parent代表的都是父類物件的引用,parent其實就是當前記憶體中子類物件的引用,如同(Parent)this一樣,這樣就可以解釋為什麼使用(Child)super.parent可以得到子類成員childName。
回到開始的問題,super.getClass().getName(),這樣,就很容易解釋他為什麼是輸出當前類的名稱了,因為構造一個例項化物件,其中,在父類和子類構造方法中,引用的物件都是同一個,都是當前例項化的子類物件。super關鍵字應該充當了一個型別轉化的作用。
熟悉c的知道,c中經常使用強制轉換指標型別來引用一些結構或變數的部分資料,如通過強制轉換為不同結構型別,來引用不同資料大小的結構體。這裡的應用效果應該等同,通過(Parent)Child可以通過轉換為父類型別而只引用父類型別的那一部分資料。
在java中new一個物件,和c或c++這些和記憶體打交道的語言一樣,都是會分配記憶體,在c中可能更直觀一點,我們在此不討論到底是分配了多大的記憶體問題。
在new一個子類的時候,上面例子看到,父類的成員同樣也有賦值初始化,說明,同樣在記憶體中也有儲存父類的資訊空間,(Object類的不討論)。
一個抽象點的圖:
-----------------------------------------------------------------JacobGo!--------------------------------------------------------------------------
本文轉載自:http://blog.csdn.net/sujudz/article/details/8034770