我们说我们有一个班级
public class ThisTest {
String username;
ThisTest(String s) {
this.username = s;
}
public void sayHello() {
System.out.println("Hello " + this.username);
}
public static void main(String args[]) {
ThisTest a = new ThisTest("Jack");
ThisTest b = new ThisTest("George");
a.sayHello();
b.sayHello();
}
}
输出(如预期):
Hello Jack
Hello George
我的问题是:在sayHello方法中,运行时如何确定堆上的哪个对象实例"这个"是指。
在编译时,方法调用传递了对调用对象(a或b)的隐藏引用,然后使用" this"关键字? - 这就是C ++的作用。
或者,是"这个"构造对象时创建的堆上对象的隐藏实例变量?
或是否有一些其他机制,sayHello方法通过这种机制知道哪个对象"这个"是指?
基本上,"这是怎样的"在Java中的编译器级别实现。
答案 0 :(得分:1)
从Java编程语言来看,没有强制实现,因为即使编译为Java字节代码也被认为是“正常”,但不是必需的。
Java Language Specification, Chapter 1. IntroductionJava编程语言通常编译为 Java虚拟机规范,Java SE 8 Edition 中定义的字节码指令集和二进制格式。
要了解在编译Java虚拟机时如何实现this
引用,我们必须参考上面提到的The Java Virtual Machine Specification:
2.6.1。局部变量
每个帧(第2.6节)包含一个称为局部变量的变量数组。帧的局部变量数组的长度在编译时确定,并以类或接口的二进制表示形式提供,同时提供与帧相关的方法的代码(§4.7.3)。
...
通过索引来解决局部变量。第一个局部变量的索引为零。 [...]
...Java虚拟机使用局部变量在方法调用上传递参数。在类方法调用中,任何参数都从连续的局部变量传递,从局部变量 0 开始。在实例方法调用中,局部变量 0 始终用于将引用传递给调用实例方法的对象(Java编程语言中为
this
)。随后,任何参数都会在从局部变量 1 开始的连续局部变量中传递。
换句话说,在Java字节代码中,this
被编译为局部变量(索引为零),在进入方法时使用对象引用进行预初始化。可以使用用于访问参数变量或显式声明的局部变量的相同字节代码指令来访问它。