java字符串String.intern()方法的实际作用与应用场景

java字符串的intern()方法,是一个理解的难点.下面针对其实际作用和应用场景进行解析,以便正确,全面地理解这个方法.

作用

首先明确一些概念

字符串和字符串对象

这里对字符串和字符串对象的概念进行一下区分,便于后续的理解.字符串我们就理解为"abc"这个字符串本身,而字符串对象,我们可以认为是一个以"abc"为核心的对象,带有其他的一些数据,比如长度等等.

等价字符串对象

如果两个字符串对象用equals比较结果为true,认为这两个字符串对象等价,称这两个字符串为等价字符串对象.

同一个字符串

字符串常量池

字符串常量池的位置

字符串常量池大家可以认为独立在运行时常量池之外,不要和运行时常量池混淆.个人认为,字符串常量池应该是在堆中.

字符串常量池里放的是什么

字符串常量池里放的实际上是字符串对象的引用,而不是字符串对象,这个也是十分容易混淆的地方.
字符串常量池里的引用指向堆中的字符串对象.
但是堆中的字符串对象,只有一部分是被字符串常量池所引用的,还有一部分,我们称为不在常量池中,比如

new String("")

这样搞出来的.

被常量池引用的那些字符串对象,我们一般称为字符串常量,也就是常说的

String str = "abc";

中的"abc"了,它们也在堆中,只有一个类被初始化,它的class常量池里面的常量才会被加载,字符串常量就是初始化时候被加载到堆里的.

intern()的作用

如果字符串常量池里存在一个和当前字符串对象等价的字符串对象(equals==true认为相同),那么返回字符串常量池里那个对象.如果不存在,把当前字符串对象存进常量池, 返回当前字符串对象.
代码示例

String test1 = "abc";
String test2 = new String("abc");
String str = test2.intern();

图示如下
java字符串String.intern()方法的实际作用与应用场景
字符串引用str,如果直接用str=test2,那么就会如图中蓝线所示,指向不在常量池中的字符串对象,此时,如果使用上面的str=test2.intern(),则会如同红线所示(因为常量池里的字符串对象和test2是等价的,intern会返回常量池里的那个),此时,不在常量池中的字符串对象"str"在没有其他引用的情况下,可以进行回收,这是intern()真正的好处.

应用场景

使用方法

public class Person{
String name;
	public void setName(String paramString)
	{
		String str = paramString.intern();
	}
}

这里是一个能展现出inern()实际作用的场景,首先假设我从数据库里读了一个人的信息出来,然后把这个人的名字赋值给这个Person对象.
那么,从数据库读数据,毫无疑问得创建一个字符串对象出来,假定读了10个人的数据,其中三个都叫小明,那么在不使用intern()的情况下,对字符串对象的引用情况如图所示
java字符串String.intern()方法的实际作用与应用场景
在使用intern的情况下,对字符串对象的引用情况如图所示
java字符串String.intern()方法的实际作用与应用场景
很显然,剩下的那两个小明字符串对象,就都可以回收了,大大节省空间.

总结

intern()的本质是改变字符串引用的方向,让对等价字符串对象的引用都指向同一个字符串对象,使得多余的等价字符串对象可以被回收.