Java内存模型中的实例变量

Java内存模型中的实例变量,java,memory,model,Java,Memory,Model,在网上搜索之后,我还没有找到一个关于实例变量在Java内存模型中的确切位置的好的全面的答案。例如,我们有以下代码(带有变量的阴影声明): 此代码的输出为: 'm()' is called from class B 'var' is called from class A 现在的问题不是继承在Java中如何工作,而是这个实例变量在Java内存模型中的位置?请论证你的答案 谢谢继承时变量与方法不同。方法m()在扩展A时在B类中被覆盖。但是,B不能覆盖其父类的局部变量,因为它对它们没有任何管辖权。一

在网上搜索之后,我还没有找到一个关于实例变量在Java内存模型中的确切位置的好的全面的答案。例如,我们有以下代码(带有变量的阴影声明):

此代码的输出为:

'm()' is called from class B
'var' is called from class A
现在的问题不是继承在Java中如何工作,而是这个实例变量在Java内存模型中的位置?请论证你的答案


谢谢

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

一个对象保留在堆中,但作为一个内存块,等于所有变量的大小加上一些额外字节来存储虚拟方法表(VMT)对象的原型位置(可能更多地取决于JVM实现)

因此,您的示例对象在(32位)内存中看起来像这样(指针值仅用于表示):

在上面的示例中,没有访问任何成员,因此JVM所做的只是定位原型的VMT,跳转到写在那里的函数地址并执行它

如果您的
var=1
代码实际上通过了优化器,那么生成的汇编代码将不知道这个“var”的事情,而是使用直接内存访问。大概是这样的:

set [4924 + 8], 1 
其中4924是实例的内存位置,+8是变量
var
的偏移量。请记住,这是(使人可读的)程序集,而不是字节码,因此基本上是JIT完成后剩下的内容


由于两个对象的大小相同,因此甚至可以将A“向上转换”为B,这是它不起作用的唯一原因,因为Java禁止这种不安全的操作。在其他不安全的语言如C++中,你可以很容易地做到这一点。你可以隐藏一些。可能是“堆在堆里”的复制品。“不,不是。”“不,不是。”“不,不是。”“看,这不是一个论点。”“是的。”“不,不是。”“是的。”“这只是矛盾。”“不,不是。”“是的!“啊,你刚才反驳了我。”“不,我没有。”“你反驳了!“什么时候?”“刚才。”“胡说!”“这是徒劳的!”“不,不是。“在我看来,这不是重复,因为问题不在于继承,而在于JMM。为了理解Java设计者为什么制定这些继承规则,我们需要理解JMM是如何处理这些数据的,以及为什么它会这样工作。@All-我相信这个问题还没有得到回答,并按照最初的要求进行论证。如果有其他人试图回答,请阅读课文两遍,只有当你提供了一个有用且全面的答案时才能回答。否则,我相信我们会有很多对我们所有人都没有附加价值的词语。感谢使用getter/setter的另一个很好的理由。但是var在这里不是局部变量,它是在方法外部声明的。在上面的示例中,B可以从a访问var,因为默认可见性受到保护。所以B可以做
super.var=3
。然而,这仍然是糟糕的编码。@Sentry该变量是类本身的局部变量。它不是所有事物的全局变量。您仍然必须通过类作用域才能访问变量。因此,类A和类B都有它们自己的变量副本,这些变量是它们类的局部变量。@WesleyPorter您在这里混淆了术语。每个变量都是它们的类或对象的局部变量,因为Java中没有全局变量。你的意思是实例变量,非静态字段。局部变量在这里并不重要。你的答案有点难理解。请分解所附的代码,指定每段代码在JMM上的位置。
[0000] 0154  // pointer to prototype
[0004] 3625  // pointer to virtual method table
[0008] 0001  // int var
set [4924 + 8], 1