首先,String实现了常量池技术
1. 看以下例子:
public class TestStringIntern {
public static void main(String[] args) {
String s0="StringIntern";
String s1="StringIntern";
String s2="String" + "Intern";
System.out.println( s0==s1 );
System.out.println( s0==s2 );
}
}
结果是:
true
true
理解:因为s0和s1中的“StringIntern”都是字符串常量,他们在编译器就被确定了,“StringIntern”存在于常量池中,所以s0==s1为true;s2由两个常量连接而成,还是字符串常量,所以也为true。
2. 看一下列子
public class TestStringIntern {
public static void main(String[] args) {
String s0="StringIntern";
String s1=new String("StringIntern");
String s2="String" + new String("Intern");
System.out.println( s0==s1 );
System.out.println( s0==s2 );
System.out.println( s1==s2 );
}
}
结果:
false
false
false
理解:使用new String()创建的字符串不是常量,是在堆中生成的对象,不能在编译器就确定,所以不存在与常量池中。所以结果为false。
3. intern方法:存在于.class文件中的常量池,在运行期被jvm装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法,当一个String的实例str调用intern()方法是,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其引用;如果没有,则在常量池中增加一个Unicode等于该实例str的字符串并返回它的引用。看如下例子:
public class TestStringIntern {
public static void main(String[] args) {
String s0="StringIntern";
String s1=new String("StringIntern");
String s2=new String("StringIntern");
System.out.println( s0==s1 );
s1.intern(); //在常量池里扩展常量,发现已经存在了
s2=s2.intern(); //把常量池中“StringIntern”的引用赋给s2
System.out.println( s0==s1);
System.out.println( s0==s1.intern() );
System.out.println( s0==s2 );
}
}
输出:
false
false
true
true
public class TestStringIntern {
public static void main(String[] args) {
String s1=new String("StringIntern");
String s2=s1.intern();//s1.intern()在常量池里新生成了一个常量,并将引用赋值给了s2
System.out.println( s1==s1.intern() );
System.out.println( s1+" "+s2 );
System.out.println( s2==s1.intern() );
}
}
输出:
false
StringIntern StringIntern
true
理解:在这个类中我们没有声名一个” StringIntern”常量,所以常量池中一开始是没有” StringIntern”的,当我们调用s1.intern()后就在常量池中新添加 了一个” StringIntern”常量,原来的不在常量池中的” StringIntern”仍然存在,也就不是“将自己的地址注册到常量池中”了。 s1==s1.intern()为false说明原来的“ StringIntern”仍然存在; s2现在为常量池中“ StringIntern”的地址,所以有s2==s1.intern()为true。