=====================================================================
在刚开始学习Java的时候,大家肯定都接触过this
关键字,尤其是在构造函数赋值的时候,如下示例:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
// 必须加this关键字,否则无法完成成员变量的赋值
this.name = name;
this.age = age;
}
}
在构造函数中,如果成员变量名称和参数名称相同时,必须加this
关键字,否则你只是将参数name赋值给它本身,并没有赋值给Person.name
,因为局部变量的优先级高于成员变量。一旦加上this
关键字,由于this
指向的是当前实例,就可以完成对象的成员变量赋值。
那为什么可以通过this
关键字访问到当前对象呢?
=====================================================================
要弄清这个问题,首先要了解JVM在执行方法时,方法栈的栈帧结构。
Java虚拟机以【方法】作为最基本的运行单元,【栈帧】就是用于支持JVM进行方法调用背后的数据结构,它也是JVM运行时数据区中【虚拟机栈】中的栈元素。
简单点说,方法的执行过程可看作是一个个栈帧从入栈到出栈的过程。
栈帧中存储了方法的:局部变量表、操作数栈、动态连接和方法返回地址等信息。
当使用javac
程序将源码编译成字节码后,一个方法的栈帧需要多大的局部变量表,多深的操作数栈就已经被计算出来,并且写入到方法表的【Code】属性中了,这一切和程序运行时无关。
换言之,一个方法它有多少个局部变量,在编译时就已经确定,不会随着程序的运行而改变。今天我们要探究的【this】问题,就在方法栈的局部变量表中。
=====================================================================
我们仍然用javap
命令来分析编译后的Class文件,这是最有说服力的。
public class Person {
public void say() {
}
public static void staticSay() {
}
}
如上一段代码,分别有一个实例方法和静态方法,我们已经知道,在静态方法中,是无法访问【this】的,但是在实例方法中可以。
先javac Person.java
再javap -verbose Person
,得到的信息有点长,我只贴这两个方法的信息。
public void say();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 8: 0
public static void staticSay();
ck=0, locals=1, args_size=1
0: return
LineNumberTable:
line 8: 0
public static void staticSay();
[外链图片转存中…(img-7S7iR9N5-1635266816742)]