关于String.intern()

我来回答下这个问题。String构造方法执行的差异在不同jdk下,string类中的String(char chars)(或者包含char构造方法)是有差异的!String str1 = new String("a");System.out.println(str1.intern() == str1); String str2 = new String(new char {\u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;});System.out.println(str2.intern() == str2); 如果是jdk6,这段代码输出,false,false。而jdk7这段代码输出false,true在jdk6中String(char chars)构造函数的实现是,在堆中创建String对象,然后将堆中的对象复制到方法区的常量池中。在jdk7中以上,String(char chars)构造函数的实现是,在堆中创建String对象,然后将堆中引用复制到方法区的常量池中。这个属于jvm的优化,因为方法区号称永久带,GC回收方法区变量很苛刻,这样的优化提高jvm对内存的使用。现在来看看题主的问题, String s1 = new StringBuilder("why").append("true").toString(); System.out.println(s1.intern() == s1); String s2 = new StringBuilder("why").append("true").toString(); System.out.println(s2.intern() == s2);其中new StringBuilder("why").append("true")构建StringBuilder对象,而toString使用String构造函数是String(char value, int offset, int count)所以s1.intern(),在jdk7中s1的引用就存入方法区的常量池中,s1.intern()与s1是同一个引用。System.out.println(s1.intern() == s1); // 结果为true而String s2 = new StringBuilder("why").append("true").toString();System.out.println(s2.intern() == s2);s2是在堆上创建的新对象!当s2.intern()在方法区的常量池中查找的时,发现“whytrue”的引用已存在(应该是equals之类的判断),所以s2.intern()返回的实际上是s1.intern()(或s1)。而s1和s2是两个不同的引用,自然是不相等的。===============================================但是,我发现了很奇怪的问题!!!(jdk7)唯独String special = new String(new char{\u0026#39;a\u0026#39;, \u0026#39;z\u0026#39;});System.out.println(special.intern() == special); // false按道理应该是也是true,不知道JVM底层做了什么
■网友
intern没什么神秘的,说白了就是jvm内部维护一个hashmap而已。oop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) { unsigned int hashValue = https://www.zhihu.com/api/v4/questions/28916657/hash_string(name, len); int index = the_table()-/u0026gt;hash_to_index(hashValue); oop found_string = the_table()-/u0026gt;lookup(index, name, len, hashValue); // Found if (found_string != NULL) { ensure_string_alive(found_string); return found_string; } Handle string; // try to reuse the string if possible if (!string_or_null.is_null()) { string = string_or_null; } else { string = java_lang_String::create_from_unicode(name, len, CHECK_NULL); } // Grab the StringTable_lock before getting the_table() because it could // change at safepoint. oop added_or_found; { MutexLocker ml(StringTable_lock, THREAD); // Otherwise, add to symbol to table added_or_found = the_table()-/u0026gt;basic_add(index, string, name, len, hashValue, CHECK_NULL); } ensure_string_alive(added_or_found); return added_or_found;}oop StringTable::lookup(int index, jchar* name, int len, unsigned int hash) { int count = 0; for (HashtableEntry/u0026lt;oop, mtSymbol/u0026gt;* l = bucket(index); l != NULL; l = l-/u0026gt;next()) { count++; if (l-/u0026gt;hash() == hash) { if (java_lang_String::equals(l-/u0026gt;literal(), name, len)) { return l-/u0026gt;literal(); } } } // If the bucket size is too deep check if this hash code is insufficient. if (count /u0026gt;= rehash_count /u0026amp;/u0026amp; !needs_rehashing()) { _needs_rehashing = check_rehash_table(count); } return NULL;}


推荐阅读