zoukankan      html  css  js  c++  java
  • 编译期常量与运行期常量的区别及数组创建本质分析

    助记符补充:

    在上一次【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是新建的原生类型的数组。

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

  • 相关阅读:
    3.25Java常量
    3.26Java逻辑运算符
    3.26Java关系运算符
    Java标识符
    3.27Java位运算符
    3.26Java运算符(operator)
    3.26Java字符型(char)变量、常量
    3.26Java布尔类型(boolean)变量、常量
    《算法导论》第9章 顺序统计学 (1)最小值和最大值
    《算法导论》第8章 线性时间排序 (1)计数排序
  • 原文地址:https://www.cnblogs.com/webor2006/p/8859014.html
Copyright © 2011-2022 走看看