Java内存模型中的实例变量

时间:2013-11-14 16:17:18

标签: java memory model

在网上搜索之后,我还没有找到关于实例变量在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实例变量所在的Java内存模型中的位置?请说明你的答案。

由于

2 个答案:

答案 0 :(得分:4)

一个Object保存在堆内,但是作为一个内存块等于所有变量组合的大小+一些额外的字节来存储虚拟方法表(VMT)和Object的原型位置(可能更多取决于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 ++,你可以很容易地做到这一点并且可能会侥幸逃脱。

答案 1 :(得分:1)

变量与继承时的方法不同。你的方法m()在扩展A时会在你的B类中被覆盖。但是,B不能覆盖其父类的局部变量,因为它对它们没有任何管辖权。