写点什么

读 Java 虚拟机类加载引发的血案,阿里 P8 大牛手把手教你

用户头像
极客good
关注
发布于: 刚刚

}


public class TestSingleton {


public static void main(String args[]){


Singleton.forTest();


}


}


看完资料的我,逐渐膨胀,毕竟 100 多斤的胖子,我想的输出应该是:


Singleton static block


Singleton block !!!


Singleton new instance


然后运行一看,懵逼了,结果是:


Singleton block !!!


Singleton new instance


Singleton static block


咋回事啊,小老弟,结果乱套了…为什么不是先执行 static 代码块先了。认真想了一波,也不知道对不对,只能疯狂测试这样子…


经过一番测试,查看资料…最终…我觉得是这样子的。整个的流程详解应该是执行的第一步:Singleton.forTest();这时候,对 Singleton 类进行加载和连接,所以首先需要对它进行加载和连接操作。在连接-准备阶段,要讲给静态变量赋予默认初始值,这里还没到执行 forTest;初始值是 singleton = null。加载和连接完毕之后,再进行初始化工作:


private static Singleton singleton = new Singleton();


所以执行去到了 new Singleton(); 这里因为 new 会引起 Singleton 的初始化。需要执行 Singleton 构造函数里面的内容。但是又因为非 static 初始化块,这里面的代码在创建 java 对象实例时执行,而且在构造器之前!!!!就是这东西…所以输出应该是:


Singleton block !!!


Singleton new instance


而根据类的初始化顺序,要执行 static 代码块,应该输出:


Singleton static block


完成初始化后。接下来就到真正调用 forTest 方法了,方法什么都不做,没输出。所以,总的答案就是:


Singleton block !!!


Singleton new instance


Singlet


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


on static block


这里最大的原因就是,连接加载的时候,要给属性初始化,而这里的初始化又刚好是 创建 java 实例,需要执行构造,执行构造的前面又必须先执行 {} 大括号非 static 块。而不是和第一个测试例子那样,static 属性不需要初始化,所以…


IG 永不加班,但我需要哇,继续测试吧…继续测试验证:


class Singleton {


private static Singleton singleton = new Singleton();


private Singleton() {


System.out.println("Singleton new instance");


}


public static Singleton getSingleton() {


return new Singleton();


}


static {


System.out.println("Singleton static block");


}


{


System.out.println("Singleton block !!! ");


}


}


public class TestSingleton {


public static void main(String args[]){


Singleton singleton = Singleton.getSingleton();


}


}


输出结果如下所示。emm, 再次根据上面自己的理解,走一遍,应该是:


Singleton block !!!


Singleton new instance


Singleton static block


Singleton block !!!


Singleton new instance


这里后面第二次 new 为啥不引起第二次 类的初始化?? 因为一个类只能初始化一次啊!new 只是创建实例,不再初始化了。所以在调用 getSingleton 的时候,只创建实例就好了,而创建实例就是:


Singleton block !!!


Singleton new instance


在同一个类加载器下面只能初始化类一次,如果已经初始化了就不必要初始化了。为什么只初始化一次呢?类加载的最终结果就是在堆中存有唯一一个 Class 对象,我们通过 Class 对象找到的那个唯一的。噢?运行看一手,丢,对了…还有存在 final 的时候,和存在父类的时候,下面慢慢再测试验证…继续测试:


class Singleton extends ParentSingleton {


public Singleton() {


System.out.println("Singleton new instance");


}


static {


System.out.println("Singleton static block");


}


{


System.out.println("Singleton block !!! ");


}


}


class ParentSingleton{


public ParentSingleton(){


System.out.println("ParentSingleton new instance");


}


static {


System.out.println("ParentSingleton static block");


}


{


System.out.println("ParentSingleton block !!! ");


}


}


public class TestSingleton {


public static void main(String args[]){


Singleton singleton = new Singleton();


}


}


输出结果如下所示。这个,很明了,还是按照上面的类的初始化,有父类的情况按顺序调用,输出如下:


ParentSingleton static block


Singleton static block


ParentSingleton block !!!


ParentSingleton new instance


Singleton block !!!


Singleton new instance


继续测试如下所示。那个人,又来了…改成和上面没有父类一样的情况:


class Singleton extends ParentSingleton {


private static Singleton singleton = new Singleton();


private Singleton() {


System.out.println("Singleton new instance");


}


public static Singleton getSingleton() {


return singleton;


}


static {


System.out.println("Singleton static block");


}


{


System.out.println("Singleton block !!! ");


}


}


class ParentSingleton{


public ParentSingleton(){


System.out.println("ParentSingleton new instance");


}


static {


System.out.println("ParentSingleton static block");


}


{


System.out.println("ParentSingleton block !!! ");


}


}


public class TestSingleton {


public static void main(String args[]){


Singleton singleton = Singleton.getSingleton();


}


}


输出结果如下所示。这里,就开始懵了…有点。先看结果:


ParentSingleton static block


ParentSingleton block !!!


ParentSingleton new instance


Singleton block !!!


Singleton new instance


Singleton static block


其实,很容易看清了,现在,再走一遍流程吧!执行到 Singleton.getSingleton() 时,先加载 Singleton ,这时因为 Singleton 有父类,需要需要加载父类先,加载父类 ParentSingleton,根据加载流程,在连接-准备阶段,要讲给静态变量赋予默认初始值,但父类没有 static 属性需要赋值初始化什么的,但是根据顺序,需要初始化 static 代码块:


ParentSingleton static block


这时候回到子类的加载流程。根据连接-准备阶段,子类有需要处理的属性 private static Singleton singleton = new Singleton();赋值默认值先,singleton = null;然后初始化 singleton = new Singleton();根据上面的经验,这里是创建实例 ,并引起初始化,正常应该是:


Singleton block !!!


Singleton new instance


Singleton static block


但是,重点来了 !! 类实例创建过程:按照父子继承关系进行初始化,首先执行父类的初始化块部分。然后是父类的构造方法;再执行本类继承的子类的初始化块,最后是子类的构造方法,也就是:


ParentSingleton block !!!


ParentSingleton new instance


同时子类的初始化,因为初始化子类它有父类,所以需要先初始化父类(但是这里因为父类已经初始化了,就不再初始化了)。所以结果是:


ParentSingleton static block


ParentSingleton block !!!


ParentSingleton new instance


Singleton block !!!


Singleton new instance


Singleton static block


最终测试如下所示:


class Singleton extends ParentSingleton {


private static Singleton singleton = new Singleton();


private Singleton() {


System.out.println("Singleton new instance");


}


public static Singleton getSingleton() {


return singleton;


}


static {


System.out.println("Singleton static block");


}


{


System.out.println("Singleton block !!! ");


}


}


class ParentSingleton{


private static ParentSingleton parentSingleton = new ParentSingleton();


public ParentSingleton(){


System.out.println("ParentSingleton new instance");


}


static {


System.out.println("ParentSingleton static block");


}


{


System.out.println("ParentSingleton block !!! ");


}


}


public class TestSingleton {


public static void main(String args[]){

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
读Java虚拟机类加载引发的血案,阿里P8大牛手把手教你