在网上搜索后,我还没有找到一个很好的全面的答案,关于实例变量在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内存模型中的位置?请对你的答案进行论证。
谢谢
发布于 2013-11-15 00:47:31
对象保留在堆中,但作为一个内存块,其大小等于所有变量的总和+一些额外的字节,用于存储虚拟方法表(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++,您可以很容易地做到这一点,并可能逃脱惩罚。
发布于 2013-11-15 00:23:23
继承时,变量与方法不同。当您的方法m()扩展A时,它会在B类中被覆盖。但是,B不能覆盖其父类的局部变量,因为它对它们没有任何权限。
https://stackoverflow.com/questions/19982741
复制相似问题