1.問(wèn)題描述:
子類對(duì)象是包含整個(gè)父類對(duì)象仍是僅僅擁有父類對(duì)象的引用小腊?
個(gè)人描述:擴(kuò)展類的實(shí)例對(duì)象在內(nèi)存中包含的是基類的一個(gè)實(shí)例還是實(shí)例的引用?
2.問(wèn)題解釋:
首先,這個(gè)問(wèn)題有一個(gè)假設(shè):任意一個(gè)類的實(shí)例必定至少有一個(gè)或多個(gè)對(duì)象組成;
第二久窟,其結(jié)構(gòu)方式類似于列表(包含基類對(duì)象)或者鏈表(持有引用);
總結(jié),擴(kuò)展類對(duì)象與基類對(duì)象的關(guān)系就是 ExtendsClassObj has a BaseClassObj
3.個(gè)人回答:
首先秩冈,類的擴(kuò)展關(guān)系和基類實(shí)例與擴(kuò)展類實(shí)例的關(guān)系是不具有相關(guān)性的,類的擴(kuò)展目的在于代碼的復(fù)用,而擴(kuò)展類的對(duì)象與基類的對(duì)象之間沒有任何關(guān)系(除非擴(kuò)展類顯式的聲明擴(kuò)展類對(duì)象持有一個(gè)基類對(duì)象的引用)斥扛。
所以擴(kuò)展類實(shí)例化并不會(huì)實(shí)例化一個(gè)基類的對(duì)象入问,但是會(huì)加載基類并對(duì)基類初始化,原因很簡(jiǎn)單:需要復(fù)用基類的屬性和方法稀颁。
第二芬失,擴(kuò)展類實(shí)例在進(jìn)行實(shí)例方法調(diào)用或者對(duì)實(shí)例屬性讀寫(方法或者屬性來(lái)自于基類)的時(shí),如果ExtendsClass沒有重寫B(tài)aseClass的方法,那么是不會(huì)包含BaseClass的方法信息(可以javap -c ExtendsClass 反編譯字節(jié)碼),那么他是怎么執(zhí)行的呢峻村?每個(gè)類在JVM內(nèi)有自己的Class(Java用于描述類的類)對(duì)象(這個(gè)class對(duì)象里邊有所屬父類索引信息,自己的方法表,屬性表等信息):在方法執(zhí)行的時(shí)候麸折,會(huì)首先檢測(cè)引用的類型再檢測(cè)其所指向?qū)ο蟮膶?shí)際類型(Base base = new ExtendsBase()或者BaseExtends baseExtends = new BaseExtends())1,如果方法在擴(kuò)展類的方法區(qū)里找到就執(zhí)行擴(kuò)展類的,2,如果在擴(kuò)展類的方法中沒有找到就會(huì)自動(dòng)尋找它的基類的方法區(qū)3,重復(fù)1/2步驟;
tip: JVM對(duì)于靜態(tài)方法和實(shí)力方法的invoke指令有區(qū)分粘昨,分別為invokestatic和invokevirtual垢啼;
4.關(guān)于this(aload_0)和super:
tip1:this指代當(dāng)前線程操作的本類實(shí)例窜锯。由編譯器在后臺(tái)默認(rèn)的的加在形參列表第一個(gè)位置上) obj.test(Object...objs) 可以理解為Class.test(obj,..objs) 在方法內(nèi)用this指代obj(由JVM aload_0 載入);
tip2芭析;super指代基類鏈表锚扎,super.getClass().getName()可以翻譯為:從基類鏈的各自的方法區(qū)找到getClass()方法(Object final的不可被重寫)然后執(zhí)行,返回Class對(duì)象再getName();
//源代碼:
public class Base {
private String name;
public Base() {
super();
// TODO Auto-generated constructor stub
}
public Base(String aname) {
super();
name = aname;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Base getInstance(){
return this;
}
public static void test(Base base,String s,int i){
System.out.println("test Base");
}
}
//反編譯:
Compiled from "Base.java"
public class oop.Base {
public oop.Base();
Code:
0: aload_0 //將在本類construtor前的全部局部變量壓入棧頂(this) 請(qǐng)注意getInstance方法的反編譯
1: invokespecial #10 // Method java/lang/Object."<init>":()V
4: return
public oop.Base(java.lang.String);
Code:
0: aload_0
1: invokespecial #10 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1 //構(gòu)造參數(shù)壓入棧頂
6: putfield #17 // Field name:Ljava/lang/String;
9: return
public java.lang.String getName();
Code:
0: aload_0
1: getfield #17 // Field name:Ljava/lang/String;
4: areturn
public void setName(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #17 // Field name:Ljava/lang/String;
5: return
public oop.Base getInstance();
Code:
0: aload_0
1: areturn
public static void test(oop.Base, java.lang.String, int);
Code:
0: getstatic #27 // Field java/lang/System.out:Ljava/io/PrintStream; 獲取靜態(tài)方法
3: ldc #33 // String test Base 載入字符串
5: invokevirtual #35 // Method java/io/PrintStream.println:(Ljava/lang/String;)V執(zhí)行實(shí)例方法
8: return
}
//源代碼:
public class BaseExtends extends Base{
private String sex;
public BaseExtends() {
super();
sex = "ChildSex";
}
public BaseExtends(String asex) {
super();
sex = asex;
}
public BaseExtends(String aname,String asex) {
super(aname);
sex = asex;
}
public String getSex() {
return sex;
}
public void setSex(String asex) {
sex = asex;
super.getName();
}
public void test(String s){
String str = sex;
}
public static void test(Base base ,String s,int i){
System.out.println("test BaseExtends");
}
}
//反編譯
public class oop.BaseExtends extends oop.Base {
public oop.BaseExtends();
Code:
0: aload_0
1: invokespecial #10 // Method oop/Base."<init>":()V 在執(zhí)行基類的初始化代碼
4: aload_0
5: ldc #12 // String ChildSex
7: putfield #14 // Field sex:Ljava/lang/String;
10: return
public oop.BaseExtends(java.lang.String);
Code:
0: aload_0
1: invokespecial #10 // Method oop/Base."<init>":()V
4: aload_0
5: aload_1
6: putfield #14 // Field sex:Ljava/lang/String;
9: return
public oop.BaseExtends(java.lang.String, java.lang.String);
Code:
0: aload_0
1: aload_1
2: invokespecial #23 // Method oop/Base."<init>":(Ljava/lang/String;)V
5: aload_0
6: aload_2
7: putfield #14 // Field sex:Ljava/lang/String;
10: return
public java.lang.String getSex();
Code:
0: aload_0
1: getfield #14 // Field sex:Ljava/lang/String;
4: areturn
public void setSex(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #14 // Field sex:Ljava/lang/String;
5: aload_0
6: invokespecial #29 // Method oop/Base.getName:()Ljava/lang/String;
9: pop
10: return
public void test(java.lang.String);
Code:
0: aload_0
1: getfield #14 // Field sex:Ljava/lang/String;
4: astore_2
5: return
public static void test(oop.Base, java.lang.String, int);
Code:
0: getstatic #36 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #42 // String test BaseExtends
5: invokevirtual #44 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
5.實(shí)例的構(gòu)造過(guò)程(JVM 指令大體順序):
new someClass //根據(jù)someClass的屬性表開辟內(nèi)存空間馁启,并對(duì)各個(gè)屬性初始化(賦予JVM默認(rèn)值0啊,null啊等等 )返回內(nèi)存空間的對(duì)應(yīng)的“地址”驾孔。對(duì)于基類和擴(kuò)展類有重復(fù)的屬性這種情況(比如都分別聲明了private String name這個(gè)屬性,雖然是不合理不應(yīng)該的設(shè)計(jì)),擴(kuò)展類的實(shí)例在開辟內(nèi)存空間時(shí)惯疙,name會(huì)分別的開辟不同的地址(基類和擴(kuò)展類)翠勉。name對(duì)應(yīng)的兩個(gè)地址是JVM 指令getField或者putField的參數(shù))
invokespecial //調(diào)用自己寫的初始化代碼
retunr aload_0的值;