思考了一天终于想出来了这是我思考的结果,希望可以加分哦。
48.B b = B.getInstance(); 49.b.test(); 50.System.out.println("=========="); 51.A a = A.getInstance(); 52.a.test();
主函数先执行48.B b = B.getInstance(); 首先先调用B类中的静态函数,然后打印"B被调用"这个只是表面现象。
①其实在调用之前要加载B类中的静态成员; ②加载B类中的静态成员就要先建立静态的B类对象;即要执行这个语句private static B b = new B(); ③但是在建立B类对象(new B();)之前,就要先执行26.private A a = A.getInstance(); ④所以就要先加载A类中的静态成员, ⑤加载A类中的静态成员就要先建立静态的A类对象,即要先执行这个语句private static A a = new A(); ⑥但是在建立A类对象之前(new A();),就要先执行05.private B b = B.getInstance();但是这时候B类静态对象还没建立,private static B b = new B(); 这句话只执行到private static B b,new B()没有执行,只是定义了一个B类型的变量,并未给变量b赋值,但是 public static B getInstance() { System.out.println("B被调用"); return b; } 已经加载,执行05.private B b = B.getInstance();没有问题,开始打印第一个"B被调用" 此时正在建立中的静态的B类对象中成员静态B类型变量b的值为null,将null赋给正在建立中的静态的A类对象中的成员b后,继续加载A类直到静态的A类对象建立。 然后建立完A类静态对象a之后,此时private static A a = new A(); 已经执行完毕,然后开始执行反回去开始执行第④步,然后在开始执行第③步,此时执行26.private A a = A.getInstance();这时第一个"A被调用"被打印;此时有因为 new A();已经建立,所以付给a的值不是null,而是确确实实在内存中存在的静态的A类对象a的地址。然后静态的B类对象b建立,所以在静态的B类对象b中a是确确实实在内存中存在的静态的A类对象a的地址。因为是静态所以b对象无法在重新建立(只有加载才会建立,但是静态只在初始化的时候加载一次,后面不再加载,因为内存已经有了),所以b对象中的a只能是确确实实在内存中存在的静态的A类对象a的地址。此时静态的A类对象中的b已经是null了,因为是静态,所以a对象无法在重新建立(只有加载才会建立,但是静态只在初始化的时候加载一次,后面不再加载,因为内存已经有了),所以a对象中的b只能为null了。 然后继续返回去执行第②步,然后执行第①步,最后调用B b = B.getInstance();这时第二个"B被调用"被打印。至此48.B b = B.getInstance(); 执行完毕。 开始执行49.b.test();就是打印静态b 对象中的成员变量a,即为静态的 A类对象a的地址。这时 A@35ce36开始打印。 然后执行50.System.out.println("=========="); 打印==========
然后执行51.A a = A.getInstance(); 只是普通的调用和赋值。调用打印函数11.System.out.println("A被调用"); 此时最后一个"A被调用"被打印,然后将内存中的静态对象a的地址传给主函数中的a。 最后执行52.a.test();就是打印静态a对象中的成员变量b,前面已经说明为null,所以此时null被打印。
至于第一个报错是因为内存不断的new对象,因为每次加载都要new对象,new对象后又要重新加载(因为是非静态成员),重新加载又要new对象,所以内存就会溢出。 |