13

我们已经知道,当我们在 Java 中调用一个方法时,参数和局部变量会存储在堆栈中。

例如下面的代码:

public class Test
{
    int x = 10;
    int y = 20;

    void test(int y)
    {
        int z = y;
        this.x = y; // How JVM knows where is our current object?
    }

    public static void main(String [] args)
    {
        Test obj = new Test();
        obj.test(3);
    }
} 

当我们调用时会产生如下调用栈obj.test()

|             |
+-------------+
|     z       |
|     y       |  obj.test()
+-------------+
|    obj      |  main()
+-------------+

但我想知道存储中this的引用在哪里method?它是否也存储在堆栈中,如下所示:

|             |
+-------------+
|   this      |
|     z       |
|     y       |  obj.test()
+-------------+
|    obj      |  main()
+-------------+

或者它存储在内存中的其他区域?还是由JVM在运行时计算?

最后,我也很好奇obj.test()栈中参数/变量的顺序是否有特定的顺序,就像C有调用约定一样,还是依赖于VM的实现?

更新

我知道this是关键字而不是普通的引用变量,但我对这个示例的主要关注点是 JVM 如何知道对象在堆中的位置?

或者换句话说,JVM 如何在运行时知道成员方法的当前对象是什么,以便他们可以访问那些实例变量?

4

2 回答 2

9

围绕 stackmachine 模型构建的大多数语言都将与您描述的完全一样。这包括 Java、.NET 和 C++。

可以这样想:实例方法的代码很可能在类的所有实例之间共享,复制每个实例的数据以外的任何内容都没有多大意义,如果那个公共部分(方法实现的代码,记住它只是计算机的内存)无论如何在所有实例中都是相同的。

因此,实例方法与静态(在 Java 和 .NET 中)方法的区别在于添加到每个方法签名中的隐式 this 参数。隐含的 this 参数表示该方法应该操作的实例。而且由于传递给方法的参数很可能发生在堆栈上,是的,这个参数将存储在堆栈上。(参见http://zeroturnaround.com/articles/java-bytecode-fundamentals-using-objects-and-calling-methods/#objects对于 Java,它在 .NET 中非常相似)。this 参数在调用方法之前作为第一个参数压入堆栈,然后是所有其他参数。

现在,这描述了虚拟机的模型。如果 JITed 机器代码真的会通过堆栈或寄存器(或以任何其他方式)传递 this 参数,则完全特定于实现并对 VM 透明。

在您的示例代码中要注意的另一件事是您两次使用了变量名“y”,因此在该方法中,局部变量“y”将隐藏实例变量,除非您使用“this”明确限定它。

于 2012-04-20T06:05:32.273 回答
2

您的问题是: -JVM 如何在运行时知道成员方法的当前对象是什么,以便他们可以访问这些实例变量。

What i know is , when u call a method with its object then implicitly
your object reference is passed to your method. like....

obj.test(obj,3);

And at run time this object is cached in this keyword..  that means this is local
for that method and must be get m/m in stack.
于 2012-04-20T06:15:33.907 回答