触发类初始化的几个面试点
上一篇文章谈到了类的加载过程,初始化是在最后一步触发的。那么在什么情况下一个类会触发初始化过程呢?
简言之,jvm对类的使用可以分为两种类型:主动使用和被动使用。每个类或接口在第一次被java程序主动使用时都会被初始化。请记住第一次,也就是说,该类将只初始化一次。
主动使用分为以下六种情况:
1)当遇到四个字节码指令:new、getstatic、putstatic或invokestatic时,相应的java场景是新实例化一个对象,读取或设置一个静态字段(final不能修改,但稍后会验证),并调用一个静态方法。
2)当使用java.lang.reflect包的方法对类型(如class . for name(& # 34;test.java & # 34).
3)初始化子类。如果父类没有初始化,父类将首先被初始化。
4)当虚拟机启动时,用户需要指定要执行的主类(包含main()方法的类),虚拟机将首先初始化这个主类。
5)当使用jdk 7的新动态语言支持时,如果一个实例的最终解析结果是四种类型的方法句柄:ref_getstatic、ref_putstatic、ref_invokestatic和ref_newinvokespecial,并且对应于这个方法句柄的类还没有被初始化,那么有必要首先触发它的初始化。
6)当一个接口中定义了一个新剑灵同居日记最新章节的默认方法(默认关键字修改的接口方法)时,如果接口的实现类被初始化,那么接口应该在它之前被初始化。
除了以上六种情况,它们都是被动使用的,不会初始化类。记住,这是第一次主动使用它。如果类已经被初始化,在上述情况下将不会被初始化!
这里不描述静态场中的常见凹坑,而是为了验证一些不寻常的凹坑!首先,第一个坑,我建议你先看代码,然后看打印结果,代码如下:
从上一篇文章中,我们知道类的静态代码块将在类初始化结束时执行。从上图中,我们可以看到子类的静态代码块没有被承诺,也就是说,子类没有被初始化,因为对于静态字段,只有直接定义字段的类才会被初始化。
接下来,看看下面的代码。不要先看打印的结果。代码如下:
这次只打印字符串,因为我用final修改了字符串,这也是一个凹坑。对final修改的静态字段的访问不会触发类的初始化。通过javap -verbose检查测试类的主方法的字节码,如下所示:
您可以看到字符串“str str str”已经在测试类的常量池中被引用,也就是说,被编译的最终代码修改的静态字段,它将在与该方法对应的常量池中。
但是,应该考虑以下情况,如下图所示:
上面的代码仍然会触发父类的初始化。这里,有必要区分编译时常数和运行时常数。无法在编译时确定的值只能在运行时确定,这将触发类的初始化。
界面验证
由于接口没有静态代码块验证,我们可以通过创建一个新线程来验证它。代码如下:
当一个类被初始化时,要求它的所有父类都已经被初始化,但是当一个接口被初始化时,不要求它的所有父接口都已经被初始化,并且只有当父接口被实际使用时(例如引用接口中定义的常数)。
但是,当在接口中定义了由jdk 8添加的新的默认方法(默认关键字修改的接口方法)时,如果该接口的实现类被初始化,则该接口应该在它之前被初始化。如果默认修改的方法在上图中被标注,接口将不会被初始化!
还有一种常见的情况是,数组验证将不会被初始化。代码如下:
数组的初始化不会初始化的类。您可以看到对应于数组的类是“[lcom . dggcc . test . classiinit . parent]”,这是由jvm生成来表示数组类型的,与原始类无关!
总结采访,最常见的是静态场末日大世界最新章节的呼叫和调查。以下是一些常见的凹坑,可能会在面试中综合出现。然而,记住这些坑,同时不要忘记正常的情况,所以我们应该更多地了解积极使用的六种情况!
如果被误解,欢迎java程序员交流和讨论他们的日常学习笔记!
文章来源:www.atolchina.com