日期:2014-05-20  浏览次数:20714 次

关于函数参数是对象,生存期问题
.......
{
   private BufferedReader br = new BufferedReader(...);

   new testThread(br).start;
}
.......

有个问题请教一下,程序执行到了}后,对象变量br的生存期就结束了,为什么testThread可以继续使用br呢?
传对象本质应该是传地址,生存期结束后,br的占用的内存空间是无效了,但是testThread却可以一直使用br,看起来是一直有效的,为什么会这样,请各位高手指教,多谢。

------解决方案--------------------
在方法调用时,是复制引用。
因此在br生存期结束后,使用的是在构造方法中声明的形参,而不是原来的br。

------解决方案--------------------
我觉得无效的只是存在于栈区的那个对象声明,
而存在于堆区的对象地址应该是一直存在的,
而Thread中是新的对象声明指向了这个地址。
------解决方案--------------------
引用:
我觉得无效的只是存在于栈区的那个对象声明,
而存在于堆区的对象地址应该是一直存在的,
而Thread中是新的对象声明指向了这个地址。

正解,堆中的对象如果还有可用引用就依然有效
------解决方案--------------------
引用:
.......
{
   private BufferedReader br = new BufferedReader(...);

   new testThread(br).start;
}
.......

有个问题请教一下,程序执行到了}后,对象变量br的生存期就结束了,为什么testThread可以继续使用br呢?
传对象本质应该是传地址,生存期结束后,br的占用的内存空间是无效了,但是testThread却可以一直使用br,看起来是一直有效的,为什么会这样,请各位高手指教,多谢。


关键要理解private BufferedReader br = new BufferedReader(...);包含的内容!
首先,在在栈区创建了一个br引用,然后,打开操作栈,将操作数的引用放进来,此时,br变成了指向了被开辟数的一个引用!【PS:可能会觉得为什么br不是在堆区,因为声明的缘故,c++里面,称作为正所谓“引用于栈”,你可以整么理解】
所以,当把br作为参数传入tesThread时,传的并非原本声明的那个br 。
我举个简单例子你看下:
//例子
import java.io.*;
public class testThread{
public testThread(BufferedReader br){}
public void start(){}
}
//测试例
import java.io.*;
public class Test {
public static void main(String[]args){
try{
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream(
"E://Test.java"
)
));
new testThread(br).start();
}catch(Exception err){/**举例子,撒也不做*/}
}
}
--------------------------
我们来看看Java的class文件里面的编译:
public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   new     #2; //class java/io/BufferedReader
   3:   dup
   4:   new     #3; //class java/io/InputStreamReader
   7:   dup
   8:   new     #4; //class java/io/FileInputStream
   11:  dup
   12:  ldc     #5; //String E://Test.java
   14:  invokespecial   #6; //Method java/io/FileInputStream."<init>":(Ljava/lan
g/String;)V
   17:  invokespecial   #7; //Method java/io/InputStreamReader."<init>":(Ljava/i
o/InputStream;)V
   20:  invokespecial   #8; //Method java/io/BufferedReader."<init>":(Ljava/io/R
eader;)V
   23:  astore_1
   24:  new     #9; //class testThread
   27:  dup
   28:  aload_1
   29:  invokespecial   #10; //Method testThread."<init>":(Ljava/io/BufferedRead
er;)V
   32:  invokevirtual   #11; //Method testThread.start:()V
   35:  goto    39
   38:  astore_1
   39:  return
  Exception table:
   from   to  target type
     0    35    38   Class java/lang/Exception
}
-------------------------------
看不懂?不要紧,我就把最关键的一句拿给你看:
   28:  aload_1
   29:  invokespecial   #10; //Method testThread."<init>":(Ljava/io/BufferedRead
er;)V
   32:  invokevirtual   #11; //Method testThread.start:()V
28:将一个引用类型变量至于栈顶
29:初始化构造函数(类testThread被构造了)
30:启动start方法。
------------------
联合28、29、30这3句可知,被传入的,可不是一个普通变量,而是引用了某个具体地址空间的引用类型!

所以,不必担心"}"了,br消失了,就不能运行了

----------------------------------------------------