对于静态字段来说,只有直接定义了该字段的类才会被初始化,当一个类在初始化时,要求其父类全部都已经初始化完毕了。
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
网友评论