美文网首页Android技术知识程序员Java 杂谈
JVM 类加载器(2)类的初始化

JVM 类加载器(2)类的初始化

作者: zidea | 来源:发表于2019-04-09 07:33 被阅读17次
    core-java.jpg

    对于静态字段来说,只有直接定义了该字段的类才会被初始化,当一个类在初始化时,要求其父类全部都已经初始化完毕了。

    class MParent{
        public static final String mString = "hello jvm";
    
        static {
            System.out.println("call MParent static block");
        }
    
    }
    public class ZiClientA {
        public static void main(String[] args) {
            System.out.println(MParent.mString);
        }
    }
    

    常量在编译阶段存入到调用这个常量的方法所在的类的常量池中。从上面代码来看就是 ZiClientA 会把 MParent 中的 mString 这个常量值保存到自己的常量池,而不是去引用 MParent 类的常量 mString

     public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: (0x0009) ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=1, args_size=1
             0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
             3: ldc           #4                  // String hello jvm
             5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
             8: return
          LineNumberTable:
            line 14: 0
            line 15: 8
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       9     0  args   [Ljava/lang/String;
    }
    
    
    java_bean.jpg
    3: ldc           #4                  // String hello jvm
    

    助记符中 ldc 是将 ZiClientA 自己常量池 #4(看下面 ZiClient.class 常量池表)
    如何读懂这个常量表参见
    读懂 java 字节码(1)
    读懂 java 字节码(2)
    读懂 java 字节码(3)

     #1 = Methodref          #7.#21         // java/lang/Object."<init>":()V
       #2 = Fieldref           #22.#23        // java/lang/System.out:Ljava/io/PrintStream;
       #3 = Class              #24            // com/zidea/jvm/demo/MParent
       #4 = String             #25            // hello jvm
       #5 = Methodref          #26.#27        // java/io/PrintStream.println:(Ljava/lang/String;)V
       #6 = Class              #28            // com/zidea/jvm/demo/ZiClientA
       #7 = Class              #29            // java/lang/Object
       #8 = Utf8               <init>
       #9 = Utf8               ()V
      #10 = Utf8               Code
      #11 = Utf8               LineNumberTable
      #12 = Utf8               LocalVariableTable
      #13 = Utf8               this
      #14 = Utf8               Lcom/zidea/jvm/demo/ZiClientA;
      #15 = Utf8               main
      #16 = Utf8               ([Ljava/lang/String;)V
      #17 = Utf8               args
      #18 = Utf8               [Ljava/lang/String;
      #19 = Utf8               SourceFile
      #20 = Utf8               ZiClientA.java
      #21 = NameAndType        #8:#9          // "<init>":()V
      #22 = Class              #30            // java/lang/System
      #23 = NameAndType        #31:#32        // out:Ljava/io/PrintStream;
      #24 = Utf8               com/zidea/jvm/demo/MParent
      #25 = Utf8               hello jvm
      #26 = Class              #33            // java/io/PrintStream
      #27 = NameAndType        #34:#35        // println:(Ljava/lang/String;)V
      #28 = Utf8               com/zidea/jvm/demo/ZiClientA
      #29 = Utf8               java/lang/Object
      #30 = Utf8               java/lang/System
      #31 = Utf8               out
      #32 = Utf8               Ljava/io/PrintStream;
      #33 = Utf8               java/io/PrintStream
      #34 = Utf8               println
      #35 = Utf8               (Ljava/lang/String;)V
    
    

    助记符

    • ldc 表示将 int、float 或是 String 类型的常量值推送至栈顶
    • bipush 表示将单字节 (-128 ~ 127)的常量值推送至栈顶
    • sipush 表示将一个短整型常量值推送至栈顶
    • iconst_1 表示将 int 类型 (iconst_m1 - iconst_5)推送至栈顶

    静态变量

    public static final short P_SHORT = 1000;
    
     stack=2, locals=1, args_size=1
             0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
             3: sipush        1000
             6: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
             9: return
    
    public static final int P_MINUS_COUTER = -1;
    
    Code:
          stack=2, locals=1, args_size=1
             0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
             3: iconst_m1
             4: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
             7: return
    

    在 ICONST 中源码查看一下,从源码中可以看出 iconst_1 将几个特殊整形的数值加载到栈顶,((i >= -1) && (i <= 5)) 对这几个特殊字符进行了处理。

     public ICONST(final int i) {
            super(com.sun.org.apache.bcel.internal.Const.ICONST_0, (short) 1);
            if ((i >= -1) && (i <= 5)) {
                super.setOpcode((short) (com.sun.org.apache.bcel.internal.Const.ICONST_0 + i)); // Even works for i == -1
            } else {
                throw new ClassGenException("ICONST can be used only for value between -1 and 5: " + i);
            }
            value = i;
        }
    
    i263315.jpg

    相关文章

      网友评论

        本文标题:JVM 类加载器(2)类的初始化

        本文链接:https://www.haomeiwen.com/subject/vtesiqtx.html