回答
String 的 intern()
是一个用于字符串添加到字符串常量池中,它的作用是:当调用 intern()
方法时,如果常量池中已经该字符串,则返回池中的字符串;如果常量池中不存在该字符串,则根据版本的不同处理方式不同:
- 如果在 JDK 7 以前,由于字符串常量池在永久代,
intern()
会将这个字符串的副本添加到常量池中,并返回常量池中的引用。 - 从 JDK 7 开始,字符串常量池被移到了Java堆内存中,则
intern()
则是将 Java 堆中的引用复制到字符串常量池中,而不是复制字符串副本,这样,intern()
会返回指向堆上已存在对象的引用。
intern()
是基于字符串常量池(String Pool)。字符串常量池是 Java 堆中(JDK 7 以后)的一部分,其目的是存储字符串字面量和显式调用intern()
方法的字符串实例,这样可以减少Java虚拟机中相同内容字符串对象的数量,以节省内存资源。
注:JDK 6 以前,字符串常量池是在永久代,从 JDK 7 开始,字符串常量池被移至堆内存中,同时,在 JDK 8 ,Java 去掉了永久代。下面演示代码全部基于 JDK 21。
扩展
intern() 核心原理
JDK 中对 intern()
描述如下:
/**
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to
this String object as determined by the equals(Object) method, then the string from
the pool is returned. Otherwise, this String object is added to the pool and a
reference to this String object is returned.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and
only if s.equals(t) is true.
All literal strings and string-valued constant expressions are interned. String
literals are defined in section 3.10.5 of the The Java Language Specification.
Returns:
a string that has the same contents as this string, but is guaranteed to be from a
pool of unique strings.
*/
public native String intern();
intern()
是一个 Native 方法,底层调用 C++ 的 StringTable::intern
方法。这段注释告诉了如下几个信息:
- 当调用
intern()
方法时,如果常量池中已经该字符串,则返回池中的字符串;否则将此字符串添加到常量池中,并返回字符串的引用。 - 对于任意两个字符串
s
和t
,若s.intern() == t.intern()
为true
,当且仅当s.equals(t)
为true
。
intern()
看着很简单,使用起来也非常方便,但是要深入理解还是蛮有难度的。
PS:以下例子都是基于 JDK 21(JDK 7 以后执行结果都一样)
请看下面例子: