Java 中 String 是一个非常特殊的数据类型,在学习 JVM 虚拟机的时候,才真正意识到为了让 String 类型在运行过程中速度更快、更节省内存,才提供了字符串常量池的概念。
字符串常量池(String Pool)保存所欲字符串字面量(literal strings),这些字面量在编译时期就确定,不仅如此,还可以使用 String 的 intern() 方法在运行时添加到常量池中。
常量池的使用主要有两种方法:
这是 String 的另一个知识点,这里只是提一下一笔带过。
这里要特别注意,此处以 JDK1.8 为例,因为在 JDK1.7 之前常量池在 Perm 区,而在 JDK1.7 之后常量池在 Java Heap 区,所以所看到的运行结果会有所不同。
String s1 = "ss"; // 在常量池上创建常量s1
String s2 = "ss"; // 直接放回已存在的常量
System.out.println(s1 == s2); // true
String s1 = new String("ss"); // 在堆上创建对象
String s2 = new String("ss"); // 在堆上创建对象
System.out.println(s1 == s2); // false
String s1 = "ss1" + "ss2" // 在常量池上创建常量 ss1、ss2、ss1ss2
String s2 = "ss1ss2";
String s3 = "ss1" + "ss2";
System.out.println(s2 == s3); // true
String s1 = new String("ss1") + new String("ss2"); // 在堆上创建对象 ss1、ss2 和 ss1ss2,在常量池上创建常量 ss1 和 ss2
s1.intern();
String s2 = "ss1" + "ss2";
System.out.println(s1 == s2); // true
String s1 = new String("ss") + new String("ss1"); // 常量 ss 不存在,所以第一步在常量池中创建了常量 ss
String s2 = new String("s") + new String("s"); // 创建对象 ss
System.out.println(s2 == s2.intern()); // false
System.out.println(s1 == s1.intern()); // true
String s1 = "ss1ss2";
String s2 = "ss1" + new String("ss2");
System.out.println(s1 == s2.intern()); // true
String s1 = "ss1ss2";
String s2 = "ss1" + new String("ss2");
System.out.println(s1 == s2.intern()); // true
System.out.println(s2 == s2.intern()); // false
规律:
1.new String 在堆上创建字符串对象。
2.通过字面量赋值创建字符串(如:String str="1")时,会先在常量池中查找是否存在相同的字符串,若存在,则将栈中的引用直接指向该字符串;若不存在,则在常量池中生成一个字符串,再将栈中的引用指向该字符串。
3.常量字符串的 + "" 操作,编译阶段直接会合成为一个字符串。如 String str="JA"+"VA"
,在编译阶段会直接合并成语句 String str="JAVA"
,于是会去常量池中查找是否存在 "JAVA"
,从而进行创建或引用。