在阅读深入理解java虚拟机的时候看到了如下代码,不理解String.intern()。
第一个结果为true,第二个结果为false。
于是阅读了这篇文章https://blog.csdn.net/soonfly/article/details/70147205,其中遇到一些问题。
上代码
String str2 = new String("str")+new String("01");
str2.intern();
String str1 = "str01";
System.out.println(str2==str1);
结果为true。
String str2 = new String("str01");
str2.intern();
String str1 = "str01";
System.out.println(str2==str1);
结果为false。
问题来了,把第一个代码创建字符串合到一起为什么就是false了?两者有什么区别?
先说明一下 String str = new String("xxx")和 String str = “xxx”的区别
String a = new String( "Hello"),jvm首先在字符串常量池内里面看看能不能找到字符串 "Hello ",如果找到,不做任何事情,否则,创建新的string对象,放到字符串常量池里面。由于遇到了new,还会在堆上创建string对象存储 "Hello ",并将引用返回给s2。(注:先在常量池里进行创建,再在堆中创建字符串)。
String b = "Hello",jvm首先在常量池内里面看找不找到字符串 "Hello ",找到,返回他的引用给b,否则,创建新的string对象,放到string池里,并返回引用。
答案:
第一段代码先检查常量池里面有没有字符串“str”和“01”,由于没找到,所以先在常量池里创建两个字符串常量 “str”和“01”(创建两个,并不是一个“str01”),然后在堆中创建“str”和“01”。最后将堆中的new String("str")和new String("01") 返回的引用组合起来返回给str2。
调用str2.intern(),由于常量池里面没有字符串“str01”,所以根据intern()方法,将在常量池中生成(“str”和“01”)在堆中的引用。(其实就是把两个字符串的地址拼接起来放到常量池中)。
String str1 = “str01”,因为常量池中有了字符串“str01”,所以返回堆中的引用。最终的结果为true。
第二段代码会先在常量池中创建字符串“str01”,然后在堆中创建,并返回堆中的引用。
调用str2.intern(),由于常量池已经存在,不会做任何事。
String str1 = “str01”,由于常量池已经存在,返回在常量池中的引用。str1(常量池引用)和str2(堆中引用)不一样,返回false。
注释:
常量池在jdk 1.7以前,常量池在方法区中,1.7之后在堆中开辟一块内存,存放常量池。
String.intern()方法:
jdk1.7之前,intern方法先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,不存在,将字符串的实例复制到常量池中,并返回常量池中的引用。
jdk1.7之后,intern方法先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,不存在,而只是在常量池中生成一个对原字符串的引用。(将堆中的引用放到常量池中存储) 。
还有一个问题不是很理解,书中所说java这个字符串在执行StringBuilder.toString()之前已经出现过,常量池已经有了它的引用,所以返回false。莫非常量池自带字符串“java”?
答案在:https://blog.csdn.net/w605283073/article/details/72753494