假如有这样一个语句 String str = “1234”;
那么“1234”这个字符串常量就存放在堆区中的字符串常量池某一位置(jdk版本号<=1.6字符串常量池在方法区,>=1.7在堆区),然后把这个字符串的地址返回给str
public static void main(String[] args) {
String str1 = "1234";
String str2 = "12"+"34";
System.out.println(str1==str2);
}
通过上面的测试可以发现虽然是三个字符串常量,地址看起来也不大相同,但是实际上是编译器底层对字符串常量加字符串常量这种操作进行了优化,直接优化成了str1的情况,所以两个字符串常量地址相同,结果为true
public static void main(String[] args) {
String str1 = "1234";
String str = "12";
String str2 = str+"34";
System.out.println(str1==str2);
}
这种情况的底层实现稍微复杂一些
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(“12”);
stringBuilder.append(“34”);
String str2 = stringBuilder.toString();
此时str2的地址是在堆上任意位置重新new出来的一个内存,所以两个字符串地址不同,返回false
再看接下来的一组测试
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1 == str2);
}
首先第2句把"hello"放在了字符串常量池中,而第3句是在堆上申请了一块内存,显而易见地址不同
而如果想让str1和str2在同一位置取值,需要将第3句改成如下语句
String str2 = new String(“hello”).intern();
这样就会返回true
String.intern()方法的作用就是先查找常量池中有没有"hello",如果有,直接返回字符串常量中的地址,如果没有,先把"hello"放到常量池中,然后再去new对象,即在常量池中增加了一个"hello"