字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串。

常量池主要存放两大类常量:字面量和符号引用

字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等;

符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:

1)类和接口的全限定名

2)字段名称和描述符

3)方法名称和描述符

Ps:符号引用类似间接引用,代表某个对象,某个内存区域,直接引用类似内存的地址,可以直接定位到某个对象或者内存区域。

1、什么是常量?

final修饰的变量

2、class文件中的常量池?

class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

3、方法区的运行时常量池?

运行时常量池是方法区的一部分。

运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法

4、intern()

String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。

 System.out.println(new String("aa").intern() == new String("aa").intern());//true

常量运算发生在编译期间。

String s1 = "a" + "b" + "c"; 经过编译,直接在字符串常量池中存储“abc”,仅仅生成一个对象,而不是三个。