2013-11-14 61 views
3

在Web上搜索後,我還沒有找到關於實例變量在Java內存模型中的位置的確切答案。例如,我們有這樣的代碼(有陰影的變量聲明):Java內存模型中的實例變量

這段代碼的
class A { 
    int var = 1; 
    void m() { 
     System.out.println("\'m()\' is called from class A"); 
    } 
} 

class B extends A { 
    int var = 5; 
    void m() { 
     System.out.println("\'m()\' is called from class B"); 
    } 
} 

public class Class1 { 
    public static void main(String args[]) { 
     A aref = new B(); 
     aref.m(); 
     String s = (aref.var)==1?"A":"B"; 
     System.out.println("\'var\' is called from class " + s); 
    } 
} 

輸出是:

'm()' is called from class B 
'var' is called from class A 

現在的問題是不能繼承在Java中是如何工作的,但其中的Java內存模型這個實例變量駐留?請說出你的答案。

謝謝

+0

你有一些隱藏在繼續。 –

+0

[隱藏實例變量類的一個可能的重複](http://stackoverflow.com/questions/7794621/hiding-instance-variables-of-a-class) – alfasin

+0

「它在堆中」「不,它不是「。 「是的!」 「不,不是。」 「是的!」 「不,不是。」 「看,這不是一個爭論。」 「是的。」 「不,不是!」 「是的。」 「這只是矛盾!」 「不,不是。」 「它是!」 「啊,你只是反駁我。」 「不,我沒有」「你做到了!」 「什麼時候?」 「現在。」 「廢話!」 「這是徒勞的!」 「不,不是。」 – Taylor

回答

1

變量與繼承時的方法不同。您的方法m()在擴展A時被覆蓋在B類中。但是,B無法覆蓋其父類的局部變量,因爲它對它們沒有任何管轄權。

+1

另一個很好的理由使用getters/setters。 – Cruncher

+0

但var不是一個局部變量,它在方法之外聲明。 – Sentry

+0

編寫正確代碼的另一個極好的理由......;) – TwoThe

4

一個對象保存在堆內部,但作爲一個內存塊等於所有變量的大小合併+一些額外的字節來存儲虛擬方法表(VMT)和對象的原型位置(可能更多取決於JVM實現)。

所以,你的例子中的物體看起來像這樣的(32位)內存(指針值僅供演示):

[0000] 0154 // pointer to prototype 
[0004] 3625 // pointer to virtual method table 
[0008] 0001 // int var 
在你上面的例子

現在,沒有成員訪問,所以所有的JVM的作用是找到原型的VMT,跳轉到寫在那裏的函數地址並執行它。

如果您的var = 1代碼實際上是通過優化器生成的,則生成的彙編代碼不會知道這個「var」事情,而是使用直接內存訪問。事情是這樣的:

set [4924 + 8], 1 

其中4924是實例的存儲位置,+ 8的偏移量爲變量var。請記住,這是(可讀的)程序集而不是字節代碼,所以基本上是一旦JIT完成了它就剩下了什麼。

由於兩個對象的大小相同,所以甚至可以將A上傳到B,這是它不起作用的唯一原因,因爲Java禁止這種不安全的操作。在其他一些不太安全的語言如C++中,你可以很容易地做到這一點,並可能逃避它。

+0

有點難以理解你的答案。請分解附加的代碼,指定JMM上每段代碼的位置。 – danbdf