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
来源: http://www.jianshu.com/p/239e4ec1da71