这一篇写的很好了,我只是简化并且扩展一下,侵删
https://www.journaldev.com/797/what-is-java-string-pool
这一篇分析的有深度,参考
https://explainjava.com/java-string-pool/
这一篇是中文的,也不错
https://www.cnblogs.com/fangfuhai/p/5500065.html
字符串是不可变的
- Java 的设计者认为,共享字符串(比如用于字符串的比较)的效率要比修改字符串的效率更加重要,所以把String设计为不可变的。
字符串池
- Java字符串池存储在堆内存中,它可以被垃圾回收
- 当使用引号创建字符串时,会先查找字符串池看是否有相同值的字符串,如果有了就返回只字符串池中的引用,没有就新创建一个再返回 新创建字符串的引用
- 当然我们可以使用new在堆中开辟新的空间,开辟完成之后又可以使用intern()方法让其进入字符串池
- 要注意的是,只有字符串常量是共享的,而字符串运算的操作的结果如+,subString()等不是共享的
下面的例子可以证明上面的几条观点
/**
* test
*/
public class Test {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2); // true
System.out.println(new String("hello") == str1); // false
System.out.println(new String("hello").intern() == str1); // true
}
}
+的执行时期
看一下这一条
/**
* test
*/
public class Test {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
System.out.println((str1 + "") == str2); // false
System.out.println("hello" + "" == str2); // true
}
}
为什么用引用与字符串常量进行+运算和字符串常量之间直接进行+运算结果不同呢?
因为两个+的执行时间不同!
字符串量"+“拼接是在编译期间进行的,拼接后的字符串存放在字符串池中,而字符串引用的”+"拼接运算实在运行时进行的,新创建的字符串存放在堆中的其他地方。
这样下面这一条也能解释了
/**
* test
*/
public class Test {
public static void main(String[] args) {
System.out.println("helloo".substring(0, 5) == "hello"); // false
System.out.println("hello" + "" == "hello"); // true
}
}
自然也是因为方法和+执行的时间不同
字符串池的优点
- 字符串池最主要的优点就是节省了内存的开销
字符串池的实现
- Hashmap
字符串池欺骗
如果你用的是JDK8, 看个厉害的…(没啥用)
import java.lang.reflect.Field;
public class StringPool {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
// add "Hello" to pool
String hello = "Hello";
Field value = hello.getClass().getDeclaredField("value");
value.setAccessible(true);
value.set(hello, "Buy buy".toCharArray());
System.out.println("Hello"); // Buy buy
}
}