字符串常量池(String Pool)
- java6:
- 存在于永久代中。
- 字符串常量池保存的是字符串常量。
- java7:
- 转移到了堆中。
- 字符串常量池存的是字符串常量和堆内的字符串对象的引用。
静态常量池(class文件常量池)
- 用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。
-
字面量:文本字符串int long 等基本类型和被声明为final的常量值等。
-
符号引用:是一组符号来描述所引用的目标,符号可以是任何形式的字面量一般包含以下三种:
- 类和接口的全限定名:例如对于String这个类,它的全限定名就是java/lang/String。
- 字段的名称和描述符:这里的字段就是类或者接口中声明的变量。
- 方法的名称和描述符:这里的描述符是方法的参数类型+返回值类型。
-
静态常量池其实就是class文件里的一部分内容。以下图片是编译后的class文件。
-
运行时常量池
- 当类加载到内存中后,jvm就会将静态常量池中的内容存放到运行时常量池中。
- 运行时常量池中的字符串在从静态常量池加载时
- 会先去String Poll中查询此此字符串在String Poll中的引用
- 如果没有则在String Poll中创建此字符串然后返回其引用
- 用返回的引用替换运行时常量池的字符串
- 运行时常量池是全局共享的,多个类共用一个运行时常量池。并且class文件中常量池多个相同的字符串在运行时常量池只会存在一份
String.intern() 方法
-
jdk 6中:在String Poll中创建字符串常量。
-
jdk 7中: 如果字符串在堆中已经存在把堆得引用存入String Poll,不存在则在String Poll中创建字符串常量。
- String str="";双引号会在String poll中直接创建。
- String.valueOf(1);不会在String poll中直接创建。
- (new Long(3l)).toString();不会在String poll中直接创建。
String s = new String("a");
System.out.println(s.intern() == s);// false
// 解析:此时创建了两个对象 1,"a"在字符串常量池中 2,s 在堆中new了新的字符串对象。
// 两个对象一个在String Poll中一个在堆中所以是false
String s = new String("a") + new String("b");// 1
System.out.println(s.intern() == s);//2
// true
// 解析:第1行代码创建了5个对象 字符串常量池中的:"a"和"b" 堆中的:new String("a")和new String("b")和s
// 第二行代码调用s.intern() 由于字符串常量池中并不存在"ab"所以会把s的引用放入String Poll 并返回这个引用 所以会返回true