《Thinking in java》第四版666页有一个示例如下:
package thread;
import java.lang.Runnable;
public class SelfManaged implements Runnable{
private int countDown = 5;
private Thread t = new Thread(this);
public SelfManaged(){
t.start();
}
public String toString(){
return Thread.currentThread().getName() + "(" + countDown + "),";
}
public void run(){
while(true){
System.out.print(this);
if(--countDown == 0){
return;
}
}
}
public static void main(String args[]){
for(int i = 0; i < 5; i++){
new SelfManaged();
}
}
}
当然,这段代码从功能上来看很好理解,其实就是主线程里面开启了5个新线程。
然而我觉得真实有迷惑性的地方在这里:
private Thread t = new Thread(this);
public SelfManaged(){
t.start();
}
按照一般的解释, this是指向当前对象的一个句柄(preference)。但是既然如此,那么为什么在对象还没有创建时,this就可以作为Thread()构造函数的参数给传递过去呢?
这里应该是与JVM相关的内容,于是查阅了很多资料,将研究结果记录如下:
- 反编译代码
将SelfManaged.class文件反编译可得到如下代码:
对应于SelfManaged()构造器的部分:(//汉字 是我加的注释)
// Method descriptor #12 ()V
// Stack: 4, Locals: 1
public SelfManaged();
0 aload_0 [this] //将局部变量区slot 0处的变量this载入栈
1 invokespecial java.lang.Object() [14] //invokespecial指令的作用是以栈顶的reference类型的数据(此处为this)为方法接收者,调用此对象的示例构造器方法、private方法或者它父类的方法。后面的[14]指代的是具体调用哪个方法。
4 aload_0 [this] //将slot 0的变量this入栈
5 iconst_5 //常量5入栈
6 putfield thread.SelfManaged.countDown : int [16] //取操作数栈顶的值存入countDown中
9 aload_0 [this] //将slot 0的变量this入栈
10 new java.lang.Thread [18] //以栈顶数据(此处为this)为接收者,new一个Thread实例
13 dup
14 aload_0 [this]
15 invokespecial java.lang.Thread(java.lang.Runnable) [20]
18 putfield thread.SelfManaged.t : java.lang.Thread [23]
21 aload_0 [this]
22 getfield thread.SelfManaged.t : java.lang.Thread [23]
25 invokevirtual java.lang.Thread.start() : void [25]
28 return
从以上的字节码可以看出,对象的初始化是在构造器里面进行的(从 countDown = 5 赋值可以看出来)。也就是说this虽然是代表当前对象的一个reference,但是没有必要简单的地认为在定义示例变量的时候就不可以用this参数了。