Java intern() 方法
intern() 方法用于在运行时将字符串添加到内部的字符串池中,并返回字符串池中的引用。
当调用 intern() 方法时,如果字符串常量池已经包含该字符串,则返回池中的引用,如果池中没有该字符串,则将其添加到池中,并返回该字符串的引用。
intern() 方法遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
String s1 = new String("Hello"); String s2 = "Hello"; String s3 = s1.intern(); System.out.println(s1 == s2); // false System.out.println(s2 == s3); // true
语法
public String intern()
参数
无
返回值
intern() 方法的返回值是字符串在字符串常量池(String Pool)中的引用。
返回值规则:
- 如果字符串常量池已存在该字符串:返回池中已有字符串的引用。
- 如果字符串常量池不存在该字符串:将当前堆中的字符串引用存入常量池(而非创建新对象),并返回该引用。
Java 版本差异:
在 JDK 6 及之前,字符串常量池存储在方法区(永久代),容量有限,过多使用 intern() 可能导致 OutOfMemoryError。
JDK 7 及以上,字符串常量池移动到了堆内存,可以存储更多数据。
实例
以下实例演示了intern() 方法的应用:
实例
public static void main(String args[]) {
// str1 直接赋值字符串字面量 "Runoob",它存储在字符串常量池(String Pool)中
String str1 = "Runoob";
// str2 使用 new 关键字创建,它存储在堆(Heap)内存中
String str2 = new String("Runoob");
// str3 是 str2 调用 intern() 方法后得到的引用
// intern() 方法会将 "Runoob" 放入字符串常量池,并返回池中的引用
String str3 = str2.intern();
// str1 和 str2 比较
// str1 指向常量池中的 "Runoob",str2 指向的是堆内存中的对象
// 由于它们的地址不同,结果为 false
System.out.println(str1 == str2); // false
// str1 和 str3 比较
// str3 是 str2 调用 intern() 方法后返回的引用,它指向常量池中的 "Runoob"
// 而 str1 也是指向常量池中的 "Runoob",因此它们的地址相同,结果为 true
System.out.println(str1 == str3); // true
}
}
代码说明:
String str1 = "Runoob";
-
直接赋值字符串字面量
"Runoob"
,它会自动存储在字符串常量池(String Pool)中。
String str2 = new String("Runoob");
-
由于使用
new
关键字,它会在堆(Heap)中创建一个新的字符串对象,即str2
不指向常量池,而是指向一个新的内存地址。
String str3 = str2.intern();
-
intern()
方法检查字符串"Runoob"
是否已经存在于字符串常量池:如果存在,返回该字符串的引用;
如果不存在,则将其添加到常量池并返回池中的引用。
-
由于
str1
已经在常量池中,str3
和str1
指向同一个对象。
System.out.println(str1 == str2);
-
str1
指向常量池,str2
指向堆中的对象,所以==
比较的是不同的内存地址,结果false
。
System.out.println(str1 == str3);
-
str3
经过intern()
之后,指向常量池中的字符串,与str1
指向相同的对象,结果true
。
以上程序执行结果为:
false true
莫洛
mol***[email protected]
参考地址
尽管在输出中调用intern方法并没有什么效果,但是实际上后台这个方法会做一系列的动作和操作。在调用”ab”.intern()方法的时候会返回”ab”,但是这个方法会首先检查字符串池中是否有”ab”这个字符串,如果存在则返回这个字符串的引用,否则就将这个字符串添加到字符串池中,然会返回这个字符串的引用。
可以看下面一个范例:
得到的结果:
为什么会得到这样的一个结果呢?我们一步一步的分析。
运行结果:
由运行结果可以看出来,b.intern() == a和b.intern() == c可知,采用new 创建的字符串对象不进入字符串池,并且通过b.intern() == d和b.intern() == f可知,字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量(如f中的e)则不会进入字符串池中。但是字符串一旦进入字符串池中,就会先查找池中有无此对象。如果有此对象,则让对象引用指向此对象。如果无此对象,则先创建此对象,再让对象引用指向此对象。
当研究到这个地方的时候,突然想起来经常遇到的一个比较经典的Java问题,就是对比equal和==的区别,当时记得老师只是说“==”判断的是“地址”,但是并没说清楚什么时候会有地址相等的情况。现在看来,在定义变量的时候赋值,如果赋值的是静态的字符串,就会执行进入字符串池的操作,如果池中含有该字符串,则返回引用。
执行下面的代码:
运行的结果:
莫洛
mol***[email protected]
参考地址