编译期常量与运行期常量的区别及数组创建本质分析

助记符补充:

在上一次【http://www.cnblogs.com/webor2006/p/8849520.html】中接触到了一些字节码的助记符,其中说到了“iconst助记符”,如下:

对它的总结如下:

也就是iconst包含iconst_1到iconst_5,其实还落了两个,一个是0,一个是-1,那下面实验一下:

那如果是-2呢?

很显然就不是iconst的啦,所以补充一下。

而其实对于这些助记符在定义在JDK中的rt.jar中,这里以iconst助记符为例,在工具中搜一下:

打开可以发现该类位于一个我们不常用的包“com.sun.org.apache.bcel.internal.generic”中,打开看一下它的注释说明:

而看一下它的具体实现就秒懂了:

另外发现它是继承一个"Instruction"这个类的,从英文意思来讲就是指令的意思嘛,可以看一下它的子类有多少:

好多呀,那我们上节还学有其它的助字符是不是都在其中,无聊找找呗:

哟西~~确实如此~~也就说明对于每个助字符都对应具体的实现类的。

编译期常量与运行期常量的区别:

开始这次的正题,先编写一个新的例子,如下:

那运行结果不跟之前举的例子结果一样嘛,因为打印常量不会导致类的初始化,是不是这样呢?看结果:

呃~~为啥呢?好奇怪的呢,其实这里就涉及到编译期的常量与运行期的常量是有区别的,这里再解释一下什么是编译期的常量和运行期的常量,所以编译期的常量就是其常量值在编译就能确定的,也就是咱们之前的那种,如:

而运行期常量指的当然就是在编译期其常量值是不确定的,回到咱们的这个例子,编译期对于UUID的值我们是完全不知的,那就属于运行期常量了。而如果将build的Myparent3的字节文件删除掉就不会像之前可以正常运行了,如下:

所以这里做一个总结:

当一个常量的值并非编译期间可以确定,那么其值就不会被放到调用类的常量池中,这时程序运行时,会导致主动使用这个常量所在的类,显然会导致这个类的初始化。

 

数组创建本质:

继续新建例子:

那它导致MyParent4的初始化么?编译运行:

很显然是导致了,为啥呢?还得回到导致类的主动使用的七种类型,具体是哪种呢,如下:

接下来改造代码:

那会导致MyParent4的主动使用么?

很显然木有主动使用,那又为什么呢?因为它木有出现在七种主动使用的情况之列嘛,那很显然这是创建实例了呀,都用了new了,那下面打印一下这个实例是什么类型:

这个类型很显然咱们木有去定义,那它是从何而来的呢?不难想象肯定是JVM在运行期创建的嘛,这个类型就叫做“数组类型”, 接着再改造:

那数组类型的父类是什么呢?打印一下:

所以总结如下:

对于数组实例来说,其类型是由JVM在运行期动态生成的,表示为“[Lcom.jvm.classloader.MyParent4”这种形式,动态生成的类型,其父类型就是Obejct,对于数组来说,JavaDoc经常将构成数组的元数称之为Component,实际上就是将数组降低为一个维度后的类型。

下面继续改造代码:

助记符介绍:

anewarray:

好,接下來反编译一下字节码文件看一下对应的助记符,具体内容如下:

xiongweideMacBook-Pro:classes xiongwei$ javap -c com.jvm.classloader.MyTest4
Compiled from "MyTest4.java"
public class com.jvm.classloader.MyTest4 {
  public com.jvm.classloader.MyTest4();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: anewarray     #2                  // class com/jvm/classloader/MyParent4
       4: astore_1
       5: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
       8: aload_1
       9: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      12: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      15: iconst_1
      16: iconst_1
      17: multianewarray #6,  2             // class "[[Lcom/jvm/classloader/MyParent4;"
      21: astore_2
      22: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      25: aload_2
      26: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      29: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      32: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      35: aload_1
      36: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      39: invokevirtual #7                  // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
      42: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      45: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      48: aload_2
      49: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      52: invokevirtual #7                  // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
      55: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      58: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      61: ldc           #8                  // String ====
      63: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      66: iconst_1
      67: newarray       int
      69: astore_3
      70: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      73: aload_3
      74: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      77: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      80: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      83: aload_3
      84: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      87: invokevirtual #7                  // Method java/lang/Class.getSuperclass:()Ljava/lang/Class;
      90: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      93: return
}

下面具体分析一下:

【解释】:anewarray表示创建一个引用类型(如类、接口、数组)的数组,并将其引用值压入栈顶。

newarray:

【解释】:表示创建一个指定的原始类型(如int、float、char等)的数组,并将其引用值压入栈顶。

【总结】:anewarray是新建的引用类型的数组,而newarray是新建的原生类型的数组。

那下面再多打印几个原生数组类型都长啥样,有个印象:

转载于:https://www.cnblogs.com/webor2006/p/8859014.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值