我发现了个Java陷阱,虽说我自己知道了这是为什么,但是,在CSDN群里发布下,有兴趣的可回答,
答对给分:
public class A{
    private A a = new A();
    public A(){
         System.out.println("你好!");
    }
}
//测试类
public class test {
    public static void main(String[] args) {
     A s = new A();
    }
}请问,1、程序的结果是什么?2、为什么?

解决方案 »

  1.   

    你的意思是无限的创建A对象,然后stackOverFlow了?我没看出奇怪的地方,无限调用private A a = new A();
      

  2.   


    class A{
     A a = null;
    public A() throws InterruptedException{
    Thread.sleep(1000);
    System.out.println("-----");
    a = new A();
    System.out.println("hello");
    }
    }public class Test {
    public static void main(String[] args) throws InterruptedException {
    A a = new A();
    }
    }改成了这样。成员变量初始化赋值相当于是在构造方法中赋值。构造方法不断调用构造方法,成了死循环,然后栈溢出了。。
      

  3.   


    兄弟,我知道你厉害!
    我可以告诉你我是故意这么写的么?
    如果你真有这么强,这个简单的问题应该小case,那请问,为什么呢 ?
      

  4.   

    这是什么陷阱,完全是对类对象实例化的过程不了解所致,对象在实例化的时候,会先初始化所有的成员变量,当然如果有父类的话,父类的成员是会先初始化的再初始化自身的成员变量,如果成员变量的初始化调用了方法,那么也会调用其方法,接着是成员代码块,接着才是执行构造函数(如果有父类还要执行父类的构造函数)。
    放到楼主这里的运行顺序就是new A的时候初始化里面的成员变量a,但a又进行了A的实例化那么又要来一遍初始化A,也是一样的先初始化成员变量a,但a又进行了A的实例化那么又要来一遍初始化A。就这样无限递归下去了
      

  5.   

    问题被你回答出来了。
    不过,作为发问者,我自己提出个跟你不一样的结论:VM在处理时,有如下方式,请看
    Compiled from "test.java"
    public class test extends java.lang.Object{
    public test();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   returnpublic static void main(java.lang.String[]);
      Code:
       0:   new     #2; //class Singleton
       3:   dup
       4:   invokespecial   #3; //Method Singleton."<init>":()V
       7:   astore_1
       8:   return}
    执行到astore_1时,从栈顶弹出一个引用类型,或某个引用的地址弹出,然后存入索引为1的指定的局部变量中,并即将开始,引用该局部。所以会发生无限递归,却又无法进入构造块里面,无法结束构造!所以看似简单的构造函数,却因为如此,进入了死循环!很多人说进入了无限递归,我不赞同,个人认为,因为根本没有进入函数内部,只是简单的加载而已,何来递归?就是个死循环!