java字符串常量池——字符串==比较的一个误区

时间:2023-03-09 19:41:26
java字符串常量池——字符串==比较的一个误区

转自:https://blog.****.net/wxz980927155/article/details/81712342

起因

再一次js的json对象的比较中,发现相同内容的json对象使用==比较并不相等。 
例如:

var obj = {};
var obj2 = {};
console.log(obj == obj2); // 结果为false

json在js中代表一个对象==比较的是对象栈中存放引用堆的地址。上面的obj和obj2创建的是两个对象地址肯定不同结果为false。

但最令我不解的是为什么js的字符串比较可以用==来比较字符串的内容是否相等,而java却要使用equals去比较字符串的内容是否相等。但当我发现下面代码的时候又刷新了我这个菜鸟的认知。

String str1 = "test";
String str2 = "test";
System.out.println(str1 == str2); // 结果为true

结果难道不该为false吗?字符串的比较难道不是用equals来比较内容是否相等吗?两个不同的对象创建的内存地址应该是不一样的啊!!后来经过网上查阅资料发现jvm还存在一个字符串常量池。


字符串常量池

让我们先分析一下上述的代码:

在我的理解中常量池应该是为了减少开发者对字符串过度的创建,导致内存使用率的提升,毕竟String类是一个final类,操作字符串永远不会改变当前字符串的值,只会新增一个字符串对象。

String str1 = "test";
/* jvm在编译的时候会先查看str1字面量test是否存放在字符串常量池中有则直
接引用字符串常量池里面的地址,没有则在字符串常量池新创建一个*/
String str2 = "test";
/* str2发现字符串常量池里面已经有了test则直接把字符串常量池里面的地址拿
了过来*/
System.out.println(str1 == str2);
// 最终str1和str2的地址都是相同的结果肯定为true啦

既然都到这里在拓展拓展在走呗

String str1 = new String("test");
String str2 = new String("test");
System.out.println(str1 == str2); // 结果为false
// 这个为什么不为true了呢?

new String()会在代码运行的时候在堆中开辟一个空间存放引用字符串常量池里面的地址但是栈里面引用的堆的地址是不一样的,所以即使引用的字符串常量池里面的地址是一样也永远不可能为true!! 
java字符串常量池——字符串==比较的一个误区


intern方法

强制String对象使用字符串常量池

String str1 = new String("test");
String str2 = new String("test");
str1 = str1.intern();
str2 = str2.intern();
System.out.println(str1 == str2); // 结果为true

经典面试题

String str1 = new String("test");
// 此代码执行会创建几个对象?
// A:1个或2个,堆中会创建一个,字符串常量池中有test则常量池中不会创建,没有则创建

总结

  1. 字符串字面量会在编译的就开始判断是否在字符串常量池里面创建,而new String()会在代码运行的时候才去判断。

  2. 字符串常量池里面没有此字符串则会创建,有则会去引用字符串常量池里面的字符串。字面量里字符串常量池的地址存放在栈中,new String()则存放在堆中。