一些概念
- 对于class字节码,紧接着魔数和大小版本信息后就是常量池了,与其他项目关联最多,同时也是第一个出现的表类型数据项目。
- 由于常量池是多个表,所以前置了一个数量计数器,而且是从1开始计数的,所以需要-1。
- 空出索引值0是为了后面的数据需要表示“不引用任何一个常量池项目”,这样就可以把索引值置为0
常量池大分类
- 自己理解:其实这里的两大分类是一种概念的总结
- 字面量(Literal)
- 字面量比较接近于Java语言层面的常量概念:文本字符串、申明为final的常量值(整型、浮点型、长整型、双精度浮点型、字符串类型)
- todo 请问,申明为final的对象常量是怎样表示的?写个例子查看javap。常量类
- 符号引用
- 符号引用则属于编译原理方面的概念
- 包含:类和接口的全限定名(Fully Qualified Name)、字段的名称和描述符(Descriptor)、方法的名称和描述符
- 具体:类或接口的符号引用、字段的符号引用、类中方法的符号引用、接口中方法的符号引用、字段或方法的部分符号引用
- Java代码在进行Javac编译的时候,并不像C和C++那样有“连接”这一步骤(最终内存布局信息),而是进行动态连接。当虚拟机运行时:从常量池获取符号引用(最终是字面量)==>解析并翻译到具体的内存地址中。
常量池项目类型
注:Utf8 ==> CONSTANT_Utf8_info,其他雷同
常量 | 项目 | 类型 | 描述 |
---|---|---|---|
Utf8 UTF-8编码的字符串 |
tag | u1 | 值为1 |
length | u2 | UTF-8编码的字符串占用了字节数 | |
bytes | u1 | 长度为length的UTF-8编码的字符串 | |
Integer 整型字面量 |
tag | u1 | 值为3 |
bytes | u4 | 按照高位在前存储的int值 | |
Float 浮点型字面量 |
tag | u1 | 值为4 |
bytes | u4 | 按照高位在前存储的float值 | |
Long 长整型字面量 |
tag | u1 | 值为5 |
bytes | u8 | 按照高位在前存储的long值 | |
Double 双精度浮点型字面量 |
tag | u1 | 值为6 |
bytes | u8 | 按照高位在前存储的double值 | |
Class 类或接口的符号引用 |
tag | u1 | 值为7 |
index | u2 | 指向全限定名常量项的索引 | |
String 字符串类型字面量 |
tag | u1 | 值为8 |
index | u2 | 指向字符串字面量的索引 | |
Fieldref 字段的符号引用 |
tag | u1 | 值为9 |
index | u2 | 指向声明字段的类或接口描述符Class的索引项 | |
index | u2 | 指向字段描述符NameAndType的索引项 | |
Methodref 类中方法的符号引用 |
tag | u1 | 值为10 |
index | u2 | 指向声明方法的类描述符Class的索引项 | |
index | u2 | 指向名称及类型描述符NameAndType的索引项 | |
InterfaceMethodref 接口中方法的符号引用 |
tag | u1 | 值为11 |
index | u2 | 指向声明方法的接口描述符Class的索引项 | |
index | u2 | 指向名称及类型描述符NameAndType的索引项 | |
NameAndType 字段或方法的部分符号引用 |
tag | u1 | 值为12 |
index | u2 | 指向该字段或方法名称常量项的索引 | |
index | u2 | 指向该字段或方法描述符常量项的索引 |
补充
- “I”、“V”、“<init>”、“LineNumberTable”、“LocalVariableTable”等这些没有在代码出现过的常量从哪来?
- 后面的字段表、方法表、属性表会用到,用于描述一些不方便使用“固定字节”来表达的内容:方法的返回值是什么?有几个参数?每个参数的类型是什么?因为Java的类是无穷无尽的,无法只通过简单的无符号字节描述一个方法用到了哪些类,因此在描述方法的这些信息时,需要引用常量表中的符号引用进行表达。
- 注意,如果依赖的其他类有常量,也会编译到当前类所在的静态常量池中,在类加载的时候会进入运行时常量池。
- 总之,编译成字节码的过程,会把用到的所有属性和方法以及代码中涉及到的类、方法、变量的字面量和符号引用编译到常量池中,而引用类型会把类的常量编译进来。这里与类加载无关。
示例
public class StringByteCode {
private final String finalStr = "finalStr";
private static String staticStr1;
private static final String staticFinalStr1;
private static String staticStr2 = "staticStr2";
private static final String staticFinalStr2 = "staticFinalStr2";
private final String finalObjStr = new String("finalObjStr");
private static String staticObjStr1;
private static final String staticFinalObjStr1;
private static String staticObjStr2 = new String("staticObjStr2");
private static final String staticFinalObjStr2 = new String("staticFinalObjStr2");
static {
staticStr1 = "staticStr1";
staticFinalStr1 = "staticFinalStr1";
staticObjStr1 = new String("staticObjStr1");
staticFinalObjStr1 = new String("staticFinalObjStr1");
}
public static void main(String[] args) {
String s1 = "s1";
String s2 = "s2";
String s3 = s1 + s2;
String os1 = new String("s1");
String os2 = new String("s2");
String os3 = os1 + os2;
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(os1);
System.out.println(os2);
System.out.println(os3);
}
}
字节码部分我就不贴出来了,可以使用javap -c -verbose自己打印看看
网友评论