'this'引用是否存储在Java中的调用堆栈中?

Bri*_*Hsu 13 java callstack this calling-convention

我们已经知道,当我们在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);
    }
} 
Run Code Online (Sandbox Code Playgroud)

当我们调用时,会产生如下所示的调用堆栈obj.test():

|             |
+-------------+
|     z       |
|     y       |  obj.test()
+-------------+
|    obj      |  main()
+-------------+
Run Code Online (Sandbox Code Playgroud)

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

|             |
+-------------+
|   this      |
|     z       |
|     y       |  obj.test()
+-------------+
|    obj      |  main()
+-------------+
Run Code Online (Sandbox Code Playgroud)

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

最后,我也很好奇obj.test()堆栈中的参数/变量的顺序是否有特定的顺序,就像C有调用约定,或者它取决于VM的实现?

更新:

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

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

Joh*_*lph 9

围绕stackmachine模型构建的大多数语言都会像您描述的那样工作.这包括Java,.NET和C++.

以这种方式思考:实例方法的代码最有可能在一个类的所有实例中共享,除了每个实例的数据之外,复制任何东西都没有多大意义,如果那个公共部分(用于实现方法的代码)无论如何,记住它对计算机的所有内存都是相同的.

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

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

在示例代码中要注意的另一件事是你使用变量名'y'两次,因此在方法中,局部变量'y'将影响实例变量,除非你明确地用'this'限定它.