@Testpublic void stringDemo1(){ String a = "a1"; String b = "a" + 1; System.out.println(a == b);// true // 要说明一点:当两个字符串字面值连接时(相加),得到的新字符串依然是字符串字面值,保存在常量池中}@Testpublic void stringDemo2(){ String a = "ab"; String bb = "b"; String b = "a" + bb; System.out.println(a == b);// false // 当字符串字面值与String类型变量连接时,得到的新字符串不再保存在常量池中,而是在堆中新建一个String对象来存放。很明显常量池中要求的存放的是常量,有String类型变量当然不能存在常量池中了。}@Testpublic void stringDemo3(){ String a = "ab"; final String bb = "b"; String b = "a" + bb; System.out.println(a == b);// true // 注意此题与上一题的区别,此处是字符串字面值与String类型常量(final)连接,得到的新字符串依然保存在常量池中。}@Testpublic void stringDemo4(){ String a = "ab"; final String bb = getBB(); String b = "a" + bb; System.out.println(a == b);// false /** * 此题中第条语句:final String bb = getBB();其实与final String bb = new String(“b”);是一样的。 * 也就是说return “b”会在堆中创建一个String对象保存”b”, * 虽然bb被定义成了final。可见并非定义为final的就保存在常量池中, * 很明显此处bb常量引用的String对象保存在堆中, * 因为getBB()得到的String已经保存在堆中了, * final的String引用并不会改变String已经保存在堆中这个事实。 */}private static String getBB() { return "b";}private static String a5 = "ab";@Testpublic void stringDemo5(){ String s1 = "a"; String s2 = "b"; String s = s1 + s2; System.out.println(s == a5);// false // 当字符串字面值与String类型变量连接时,得到的新字符串不再保存在常量池中,而是在堆中新建一个String对象来存放。很明显常量池中要求的存放的是常量,有String类型变量当然不能存在常量池中了。 System.out.println(s.intern() == a5);// true /** * 可能很多人对intern()这个函数不了解。JDK API文档中对intern()方法的描述是: * 返回字符串对象的规范化表示形式。 * 一个初始为空的字符串池,它由类 String 私有地维护。 * 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。 * 它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。 * 所有字面值字符串和字符串赋值常量表达式都使用 intern 方法进行操作。 */}@Testpublic void stringDemo6(){ String s1 = "a"; String s2 = "b"; String s = s1 + s2; System.out.println(s == a5);// false System.out.println(s.intern() == a5);// true System.out.println(s.intern() == a5.intern());// true // 这个可以不解释啦吧,Demo5都能明白,这就不是事了}
/** * 小试牛刀: String s = new String("xyz");创建了几个String Object? 二者之间有什么区别? * String s = new String("xyz"); * 这个跟常量池没有关系,只要是new,都是重新分配堆空间, * 如果不区分栈和堆,这里创建了1个String Object。 * 如果是从jvm角度来说的话,它是创建了两个对象,String s是在栈里创建了一个变量,new String("xyz")是在堆里创建了一个对象并被s引用到。 * * 如果是String s = "xyz",那就要看常量池里有没有"xyz",如果有直接引用,如果没有则创建再引用 * 这里"xyz"本身就是pool(常量池)中的一个对象,而在运行时执行new String()时, * 将pool中的对象复制一份放到heap中, * 并且把heap中的这个对象的引用交给s持有。ok, * 这条语句就创建了2个String对象。 * */
/** * jdk1.8 description * Returns a canonical representation for the string object. ** A pool of strings, initially empty, is maintained privately by the * class {@code String}. *
* When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. *
* It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. *
* All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * The Java™ Language Specification. * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. */public native String intern();