参考链接
Class文件常量池
每一个Java类被编译后,就会形成一份class文件
class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table)
每个class文件都有一个class常量池
主要存放两大 常量:字面量 符号引用
字面量
- 接近java语言层面的常量概念
- 包括:文本字符串、八种基本类型的值、final修饰的成员变量
- 对于基本类型数据(甚至是方法中的局部变量),也就是上面的private int value = 1
- 常量池中只保留了他的的字段描述符I和字段的名称value,他们的字面量不会存在于常量池
符号引用
- 主要设涉及编译原理方面的概念
- 包括:类和接口的全限定名、字段的名称和描述符、方法中的名称和描述符
字符串常量池
String s0 = "abc";
String s1 = new String("abc");
第一种方式声明的字面量hellow是在 编译期 就已经确定的,它会直接进入class文件常量池中
- 先 在栈中 创建一个对String类的对象引用变量str0
- 然后通过符号引用去 字符串常量池 里找有没有”abc”
- 如果没有,则将”abc”存放进字符串常量池,并令str2指向”abc”
- 如果已经有”abc” 则直接令str2指向“abc”。“abc”存于常量池在 编译期间完成
⭐ 这条语句创建了几个对象? 2个
第 1 个对象:”abc”字符串存储在常量池中
第 2 个对象:在JAVA Heap中的 String 对象
( s是放在栈里面:指向了Heap堆中的String对象
第二种方式方式使用了new String(),也就是调用了String类的构造函数
- new指令是创建一个类的实例对象并完成加载初始化的
- 因此这个字符串对象是在 运行期 才能确定的,创建的字符串对象是在堆内存上
⭐ 这条语句创建了几个对象? 1个
运行时常量池
类加载完成之后,将每个class常量池中的 符号引用值 转存到运行时常量池中
作用:存储java class文件常量池中的 符号信息
每个class都有一个运行时常量池,不同的类共用一个运行时常量池,类在解析后,符号引用替换成直接引用,与全局常量池的引用值保持一致
运行时常量池相对于class常量池一大特征就是 具有动态性
- java规范并不要求常量只能在运行时才产生,也就是说运行时常量池的内容并不全部来自class常量池
- 在运行时可以通过代码生成常量并将其放入运行时常量池中,这种特性被用的最多的就是String.intern()
在JDK7.0版本以后,字符串常量池被移到 堆
- 运行时常量池大小 受方法区大小 的影响
运行时常量池也是每个类都有一个
符号引用 直接引用
- 符号引用:自己定义,看得懂的
- 直接引用:内存地址,看不懂的