学习java时,理解的this关键字的实质是用来指向当前对象的一个指针。按照之前所学,理解它有以下三种用法加一个性质。
1.在构造方法中使用this
关键字this可以出现在类的构造方法中,代表使用该构造方法所创建的对象。
public class Tom {
int leg;
Tom(int n) {
this.cry(); //可以省略this,将this.cry();写成cry();
leg = n;
this.cry();
}
void cry() {
System.out.println("I'm Tom,I have " + leg +" legs");
}
public static void main(String[] args) {
Tom cat = new Tom(4); //当调用构造方法Tom时,其中的this对象就是cat
}
}
2.在实例方法中使用this
关键字this可以出现在类的实例方法中,代表使用使用该方法的当前对象。
实例方法中可以利用this操作成员变量和成员方法,默认格式如下:
this.成员变量
this.方法
public class Tom {
int leg;
void evolution() {
this.leg = 2;
this.cry();
}
void cry() {
System.out.println("I'm Tom,I have " + leg +" legs");
}
public static void main(String[] args) {
Tom cat = new Tom();
cat.leg = 4;
cat.cry();
cat.evolution(); //对象调用本方法时,修改了leg并调用类cry()方法
}
}
3.区分成员变量和局部变量
如果在方法内局部变量的命名与实例变量的命名相同,根据内部屏蔽外部的原则,实例变量在这个方法内暂时失效。这是如果想在该方法中使用实例变量,则需要在变量名前显示的加上"this.",用来指明此变量是实例变量。默认格式如下(前者指示的是实例变量,后者指示的是局部变量):
this.变量名= 变量名;
public class Tom {
int leg;
void setleg(int leg){
this.leg = leg; //此处利用this区分了实例变量与局部变量。
}
void cry() {
System.out.println("I'm Tom,I have " + leg +" legs");
}
public static void main(String[] args) {
Tom cat = new Tom();
cat.setleg(4);
cat.cry();
}
}
4.类方法中不能使用this
类方法(或有static修饰的静态方法)中不能使用this关键字。因为这些方法是静态的,常驻内存。当程序执行,为这些方法在内存中开辟存储空间的时候,可能还没有任何对象诞生。this关键字也就失去了意义。
一直以来,我都以为this的作用都较为基础的止步于此。但在今天学习数据结构的过程中,我看到了这样的代码。
public class SeqList implements LList {
private Object [] element; //对象数组
private int len; //顺序表长度
/**初始化顺序表*/
public SeqList(int size) {//size:顺序表大小
element = new Object[size];
this.len = 0;
}
/**默认初始化顺序表*/
public SeqList(){
this(64); //this.SeqList(size);
}
}
public class SeqListTest {
public static void main(String[] args) {
SeqList sList = new SeqList();
}
}
在第二个构造方法中,可见 this(64); 这样的语句。
这是JDK1.7以上新支持的功能。但初见时我并不理解这样的语法,因为this语句在我的印象中只是用来指示当前对象的一个关键字。单纯的指示当前对象,如果在实例化执行构造方法的同时又调用另一个构造方法,是否会生成一个新的对象?然而结果又是显而易见的——只有一个对象生成,并具有设想中应该有的和内容。
那么这样的语法的底层又是怎样去实现的呢?这让我陷入了疑惑。
思索良久,看了一些别人的理解和想法,再利用一些小小的测试代码。我将我对这个问题的一些设想写在这里。
话不多说,先来复习一下构造方法执行时底层发生了什么。
1.构造方法入栈。在堆区为对象开辟存储空间,并为实例变量赋默认值。
2.执行构造代码块(静态或动态)、实例变量赋值赋值语句。在堆区为实例变量初始化。
3.执行构造方法剩余语句,修改堆区实例变量的初始值。
4.构造方法弹栈。
以上是一般构造方法执行时的底层表现,那么按我的理解叙述一下以下代码在执行时的底层表现。
public class Tom {
int head = 0;
int leg;
public Tom(int leg){
this.leg = leg;
}
public Tom() {
this(6);
this.head = 3;
}
public static void main(String[] args) {
Tom cat = new Tom();
System.out.println("I'm Tom,I have " + cat.head +" head");
System.out.println("I'm Tom,I have " + cat.leg +" legs");
}
}
0. JVM生成字节码并加载到方法区blablabla...
1.main方法入栈;
2.无参构造方法Tom入栈。JVM在堆区开辟存储空间,为实例变量head、leg赋初值0;
3.执行构造代码块(这里没有),以及初始化语句。为head赋初值0;
4.执行构造方法体。并在第一句通过this转入带参构造方法Tom(int leg),Tom(int leg)入栈;
5.因为this指向当前对象,所以执行构造器为leg赋值6,Tom(int leg)出栈。返回无参构造方法断点处继续执行,为head赋值3,Tom()出栈;
6.继续执行main方法,直至程序结束,main出栈。
可见,this(参数)这种语法可以完成对构造方法的调用~
这里附上构造方法中使用this调用另一构造方法的相关规则:
(1)假如在一个构造方法中使用了this语句,那么它必须作为构造方法的第一条语句(不考虑注释语句)。
(2)只能在一个构造方法中使用this语句来调用类的其他构造方法,而不能在实例方法中用this语句来调用类的其他构造方法。
(3)只能用this语句来调用其他构造方法,而不能通过方法名来直接调用构造方法。
以上是本人对这个问题的一些理解。若有不正确,请各位dalao斧正。感谢~