java字符串的intern()方法,是一个理解的难点.下面针对其实际作用和应用场景进行解析,以便正确,全面地理解这个方法.
首先明确一些概念
这里对字符串和字符串对象的概念进行一下区分,便于后续的理解.字符串我们就理解为"abc"这个字符串本身,而字符串对象,我们可以认为是一个以"abc"为核心的对象,带有其他的一些数据,比如长度等等.
如果两个字符串对象用equals比较结果为true,认为这两个字符串对象等价,称这两个字符串为等价字符串对象.
字符串常量池大家可以认为独立在运行时常量池之外,不要和运行时常量池混淆.个人认为,字符串常量池应该是在堆中.
字符串常量池里放的实际上是字符串对象的引用,而不是字符串对象,这个也是十分容易混淆的地方.
字符串常量池里的引用指向堆中的字符串对象.
但是堆中的字符串对象,只有一部分是被字符串常量池所引用的,还有一部分,我们称为不在常量池中,比如
new String("")
这样搞出来的.
被常量池引用的那些字符串对象,我们一般称为字符串常量,也就是常说的
String str = "abc";
中的"abc"了,它们也在堆中,只有一个类被初始化,它的class常量池里面的常量才会被加载,字符串常量就是初始化时候被加载到堆里的.
如果字符串常量池里存在一个和当前字符串对象等价的字符串对象(equals==true认为相同),那么返回字符串常量池里那个对象.如果不存在,把当前字符串对象存进常量池, 返回当前字符串对象.
代码示例
String test1 = "abc";
String test2 = new String("abc");
String str = test2.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()的情况下,对字符串对象的引用情况如图所示
在使用intern的情况下,对字符串对象的引用情况如图所示
很显然,剩下的那两个小明字符串对象,就都可以回收了,大大节省空间.
intern()的本质是改变字符串引用的方向,让对等价字符串对象的引用都指向同一个字符串对象,使得多余的等价字符串对象可以被回收.