在学习Java一段时间之后,它第一次使用this关键字让我如此困惑.
这是我如何感到困惑.我写了以下代码:
class BasicInheritanceTest3Base{
private int x = 0;
public int y;
public void a() {
x++;
this.x++;
System.out.println("BasicInheritanceTest3Base.a()");
b();
this.b();
System.out.println(x);
System.out.println(y);
}
public void b(){
System.out.println("BasicInheritanceTest3Base.b()");
}
}
public class BasicInheritanceTest3 extends BasicInheritanceTest3Base {
private int x = 3;
public int y = 2;
public void b() {
System.out.println("BasicInheritanceTest3.b()");
}
public static void main(String[] args){
BasicInheritanceTest3 bit2 = new BasicInheritanceTest3();
bit2.a();
}
}
Run Code Online (Sandbox Code Playgroud)
我得到以下输出:
BasicInheritanceTest3Base.a()
BasicInheritanceTest3.b()
BasicInheritanceTest3.b()
2
0
Run Code Online (Sandbox Code Playgroud)
现在第一个问题是:为什么x并this.x指向x基类而不是Child类?如果this.x指向x基类,为什么要this.b()调用b()子类?字段和方法的行为是否不同?
但是,主要关注的是this关键字的机制.我的意思是你知道,this指向(引用)当前对象.如果你想一想,它不是一个神奇的行为.在this某个地方必须有场地.例如,.class类的文字是不可见的,但存在于发出的字节码中.同样,此引用应存在于字节码中.
好吧,假设上面是真的,this应该是public final(一个空白的最终),每次构造对象并实例化其字段时,它都会被实例化.这意味着它是一个实例变量而不是静态变量.
现在,如果将其实例化为当前对象的引用(仅限于特定对象),this对于字段和方法,上面的使用方法有何不同?总而言之,背后的机制是this什么?该机制是否也适用于super关键字?
编辑:每个人都在阅读问题,然后是评论,我想问一下,this编译器声明的字段在哪里以及它的限定符是什么.结果行为是如何在幕后发生的?
其他答案和评论解释了字段如何不是多态的,以及如何根据实例引用的编译时类型解析字段访问表达式。下面,我将解释字节码如何处理this引用。
在关于接收参数的章节中,Java 虚拟机规范指出
如果将 n 个参数传递给实例方法,则按照约定,它们将在为新方法调用创建的框架的编号为 1 到 n 的局部变量中接收。参数按传递的顺序接收。例如:
Run Code Online (Sandbox Code Playgroud)int addTwo(int i, int j) { return i + j; }编译为:
Run Code Online (Sandbox Code Playgroud)Method int addTwo(int,int) 0 iload_1 // Push value of local variable 1 (i) 1 iload_2 // Push value of local variable 2 (j) 2 iadd // Add; leave int result on operand stack 3 ireturn // Return int result按照惯例,实例方法在局部变量 0 中传递对其实例的引用。在 Java 编程语言中,该实例可通过
this关键字访问。类(静态)方法没有实例,因此对于它们来说,不需要使用局部变量 0。类方法在索引 0 处开始使用局部变量。如果 addTwo 方法是类方法,则其参数将以与第一个版本类似的方式传递:
Run Code Online (Sandbox Code Playgroud)static int addTwoStatic(int i, int j) { return i + j; }编译为:
Run Code Online (Sandbox Code Playgroud)Method int addTwoStatic(int,int) 0 iload_0 1 iload_1 2 iadd 3 ireturn唯一的区别是方法参数出现在局部变量 0 而不是 1 中。
换句话说,您可以将其this视为未在任何地方声明,也可以视为被声明为每个实例方法的第一个参数。为每个实例方法创建一个局部变量表条目,并在每次调用时填充。
调用方法一章指出
实例方法的正常方法调用在对象的运行时类型上分派。(它们是虚拟的,在 C++ 术语中。)这样的调用是使用
invokevirtual指令实现的,该指令将运行时常量池条目的索引作为其参数,给出对象的类类型的二进制名称的内部形式,要调用的方法的名称,以及该方法的描述符(第 4.3.3 节)。要调用addTwo之前定义为实例方法的方法,我们可以编写:Run Code Online (Sandbox Code Playgroud)int add12and13() { return addTwo(12, 13); }这编译为:
Run Code Online (Sandbox Code Playgroud)Method int add12and13() 0 aload_0 // Push local variable 0 (this) 1 bipush 12 // Push int constant 12 3 bipush 13 // Push int constant 13 5 invokevirtual #4 // Method Example.addtwo(II)I 8 ireturn // Return int on top of operand stack; // it is the int result of addTwo()通过首先将当前实例 的引用推
this送到操作数堆栈来设置调用。int然后推送方法调用的参数值 12 和 13。addTwo创建方法的框架时,传递给方法的参数成为新框架局部变量的初始值。也就是说,this被调用者压入操作数栈的for和两个参数的引用将成为被调用方法的局部变量 0、1 和 2 的初始值。
| 归档时间: |
|
| 查看次数: |
1488 次 |
| 最近记录: |