JVM第三记常量的本质含义与反编译及助记符详解+编译期常量与运行期常量的区别及数组创建本质分析

一、第二记问题解答

类在JVM中被程序主动使用的第二种场景指的是当类或接口的静态变量,静态方法被调用或者静态变量被赋值时初始化该类或接口,这里的 类或接口是指定义该静态变量、静态方法的类或接口,故上篇文章的实例二MyChild不算被主动使用不被初始化。但是他会不会被加载呢?
我们可以在运行实例二之前给JVM添加参数 -XX:+TraceClassLoading用于追踪类的加载信息并打印 操作及运行结果如下图:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
由上图可知Object类型为所以类型的父类故首先被加载符合主动使用的第四场景,
同事也得到了答案MyChid随没有被初始化但是还是被JVM加载到了内存(某个类型被初始化肯定被加载和连接,没被初始化不一定被加载和连接也不一定没被加载和连接这个没有明确规定);

二、虚拟机参数补充

JVM的参数一共可以分为三大类。因为JVM有很多功能选项,有的是默认关闭的,有的是默认开启的。

  • 第一类开启option选项-XX:+option:
    1.-XX:+TraceClassLoading :用于追踪类的加载信息并打印功能开启
    2.-XX:+TraceClassUnLoading :用于追踪类的卸载信息并打印功能开启
  • 第二轮关闭option选项-XX:-option:
    1.待补充…
  • 第三类为option设置值-XX:option=value:
    1.待补充…
三、助记符(使用javap命令将class文件反编译后的内容)

1.getstatic 表示访问类的静态变量
2. putstatic 表示对类的静态变量赋值
3. invokestatic 表示调用类的静态方法
4. ldc表示将int,float或是String类型的常量值从常量池推送至栈顶。
5. bipush表示将单字节(-128—127)的常量值推送至栈顶。
6. sipush 表示将一个短整型常量值(-32768—32767)推送至栈顶。
7.iconst_1 表示将int类型的1推送至栈顶。(JVM为1-5这几个常见的int类型常量提供了特殊的助记符iconst_num num=-1-5)
8.anewarray表示创建一个引用类型的(如类、接口、数组)数组,并将其引用压入栈顶。
9.newarray表示创建一个指定的原始类型(如int、float、char等)的数组,并将其引用值压入栈顶。

四、代码解释编译期常量和运行期常量区别
实例一:编译期常量

在这里插入图片描述
运行结果:hello world

解释:看了上篇文章的小伙伴可能会有疑问这不是符合主动使用的第二个场景嘛,访问类的静态变量,等于主动使用定义变量的类,初始化该类。但上图所示的调用的str为静态常量final,常量是不可以被重新赋值改变的,而且这个静态常量的值在编译期间就可以知道是hello world,所以在“编译阶段”会被存入到调用这个常量str的方法main所在的类Demo的常量池中。本质上调用类并没有直接引用到定义常量str的类MyParent,因此并不会触发定义常量str的类MyParent的初始化。 注意:这里指的是将常量存放到了Demo的常量池中,之后Demo和MyParent就没有任何关系了。 编译过后甚至我们可以将MyParent的class的文件删除。

实例二:运行期常量

在这里插入图片描述
运行结果:
MyParent1 static block
5f19707a-7871-474c-9df4-75e0f8506cb4

解释:相比于实例一str的值要在运行期才能确定是什么,要运行就必须要初始化,当一个静态常量的值并非编译期可以确定的,那么其值就不会被放到调用该静态常量的方法所属的类的常量池中, 这时在程序运行时,main方法里会调用静态变量(常量)str,会导致程序主动使用定义这个常量的类MyParent1,故MyParent1会被初始化。

五、数组创建本质分析

:对于数组来说,javaDoc经常将构成数组的元素称为Component,实际上就是将数组降一个维度后的类型

实例一:

在这里插入图片描述
运行结果:
MyParent1 static block
182ade28-1006-4404-b61f-426c851aed50
class [Lyang.jvm.disanjiang.MyParent2;
class java.lang.Object
class [[Lyang.jvm.disanjiang.MyParent2;
class java.lang.Object
class [I
class java.lang.Object

解释:

创建MyParent2[] 和MyParent2[][] 和int[] 时不会主动使用MyParent2类型个int类型,故不会初始化MyParent2类和int类,创建数组时主动使用的类型使用JVM在运行期动态生成(加载+连接[验证-准备-解析]+初始化)的;如[Lyang.jvm.disanjiang.MyParent2 、[[Lyang.jvm.disanjiang.MyParent2、 [I 。而且他们都直接继承Object类型。
;

猜你喜欢

转载自blog.csdn.net/yangxiaofei_java/article/details/103396456