下方代码主要说明:
String b = new String("xyz") 创建2个对象,一个在常量池中的 "xyz",一个 String 实例对象,返回的是实例对象引用。
intern() 方法有两个作用,一是取出 String Pool 中的值(可能是字面量可能是引用),二是如果 String Pool 没有该值,则将String 对象引用添加到 String Pool
String a = "abc" 该表达式有两个作用,一是取出 String Pool 中的值并返回(可能是字面量可能是对象的引用),二是如果 String Pool 没有该值,则将 字面量添加到 String Pool
检测代码:
public class Test { @org.junit.Test public void test() { String s1 = new String("x") + new String("yz"); //这里的 new String 会创建5个对象,3个实例,2个字面量,存入 "x", "yz" 2 个字面量。 //返回 "xyz" 的引用 String l_s1 = s1.intern(); //当常量池中没有该字面量或引用时,则把该字符串对象的引用添加到常量池中,并返回引用 String s2 = "xyz"; printHash(l_s1); //引用 printHash(s1); //引用 printHash(s2); //当常量中有该字符串的引用,返回引用 String s3 = new String("abc"); //生成 2个对象,1个实例,1个 "abc" 字面量。存入 "abc" 字面量,返回 "abc" 引用 String s4 = "abc"; String l_s3 = s3.intern(); //与前面对比,可知常量池中确实有该字符串,返回的是字面量 printHash(l_s3); //字面量 printHash(s3); //引用 printHash(s4); //字面量 String s = "s"; //存入该字面量,返回该字面量 printHash(s.intern()); //字面量 printHash(s); //字面量 } private void printHash(String str) { int hash = System.identityHashCode(str); System.out.println(str.hashCode() + " : " + hash); }}
返回结果:
119193 : 476800120119193 : 476800120119193 : 47680012096354 : 174434704396354 : 125452627096354 : 1744347043115 : 662441761115 : 662441761
下方代码说明:
new String("xyz") 会生成 2 个对象,而 new String(bytes) 只生成一个对象
检测代码
public class Test { @org.junit.Test public void test() { char[] bytes = new char[]{'a', 'b', 'c'}; String s1 = new String(bytes); String l_s1 = s1.intern(); String s2 = "abc"; printHash(s1); printHash(l_s1); printHash(s2); String s3 = new String("xyz"); String l_s3 = s3.intern(); String s4 = "abc"; printHash(s3); printHash(l_s3); printHash(s4); } private void printHash(String str) { int hash = System.identityHashCode(str); System.out.println(str.hashCode() + " : " + hash); }}
返回结果
96354 : 47680012096354 : 47680012096354 : 476800120119193 : 1744347043119193 : 125452627096354 : 476800120
总结:
在不同情况下 new String(param) 方法或 "abc" 会生成字面量与引用。那么考虑一般情况,在使用 new String("abc") 或 String s = "abc" ,通常会生成字面量。使用 new String(bytes) 通常不会自动生成字面量,需要调用 new String(bytes).intern() 方法。
补充:
1. 对象的 hashCode 方法与 System.identityHashCode 区别 :一般情况下 hashCode 等同于 identityHashCode。但是由于下一条中的因素,会导致不相等。
2. 当对象的 equals 方法重写时,也需要正确重写对象的 hashCode 方法。一个原则是,equals 相等,hashCode 必须相等。而 hashCode 相同,equals 可以不相等。在该对象作为字典中的 key 涉及到 Hash 存取时,判断是否相等先使用 hashCode 判断,再使用 equals 判断,这样可以提高效率。(分析见 )