String intern在Java6 7 8中实现原理不一样,本文仅针对Java8的原理进行分析
首先来看interna方法的说明:java
/** * Returns a canonical representation for the string object. * <p> * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * <p> * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. * <p> * It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. * <p> * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * <cite>The Java™ Language Specification</cite>. * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. */
简单来讲,在Java8中,String类维护了一个字符串常量池(注意此常量池在运行期间位于堆中),当调用intern方法时,首先在常量池中查看是否已有相同的字符串(字符串是否相同使用String的equal方法判断),若是常量池中已有,则直接返回该字符串的引用,若是没有,则将当前字符串对象加入常量池中,并返回当前字符串的引用。express
字符串的建立,若是使用 new 建立时,是在堆中建立字符串对象,若是直接使用字面量,则先看常量池中是否有相等的字符串,若是有,则返回此字符串的引用,若是没有,则在常量池中建立。优化
下面举例说明this
String s1 = new String(String.valueOf(11)); String s2 = s1.intern();
这里使用String.valueOf(11)而不是“11”,是为了先说明非字符串常量的状况。spa
执行第一行代码时,内存中的数据如图1所示:
在堆中建立String "11" 对象,在栈中建立变量s1,指向String对象。code
执行第二行代码时,调用String对象的intern方法,此时常量池中没有 "11",因此将"11"加入到常量池中,返回"11"对象的引用,赋值给s2, 内存中数据分布如图2所示:orm
因此此时s1==s2,执行结果:对象
下面看下字面量字符串和常量字符串的状况blog
String s1 = "11"; String s2 = new String("11"); String s3 = s2.intern(); System.out.println(s1 == s2); System.out.println(s2 == s3); System.out.println(s1 == s3);
对于字面量字符串和常量字符串是直接在string pool中建立, 因此s1指向常量池中的字符串对象;
s2使用new操做符,在堆中建立,因此s2指向堆中的字符串对象;
s2调用intern方法后,由于常量池中已经有“11”的字符串对象,因此直接返回常量池中的字符串引用。 内存中的数据分布如图3:内存
因此执行结果是:
string pool是使用Map结构存储字符串及引用,若是想要增长string pool的大小,能够设置JVM参数:
-XX:StringTableSize=1000003
Java8中默认是60013,设置的值最好是素数,以减小Hash碰撞,提升查询效率。
参考:
https://www.journaldev.com/79...
http://java-performance.info/...
https://www.baeldung.com/java...