1. String对象是不可变的,String类中每一个看起来修改String值的方法,实际上都是创建了全新的String对象。
package com.lyj.string; /* * String是不可变的 */ public class StringDemo { public static void main(String[] args) { String s1 = "lyj"; System.out.println(s1); String s2 = upcase(s1); System.out.println(s2); System.out.println(s1); } public static String upcase(String s) { return s.toUpperCase(); }
输出结果是lyj, LYJ, lyj。s.toUpperCase(String s)会创建一个新的String对象,返回时返回指向这个对象的引用。 如果s1不指向新的对象,则它指向的值始终是lyj。
2. String对象是不可变的,可以给String对象加任意多的别名,因为String对象具有只读性,所以指向它的任何引用都不能改变它的值。
package com.lyj.test; public class Test { /** * @param args */ public static void main(String[] args) { String s1 = "lyj"; String s2 = "zky" + s1 + "age"; System.out.println(s2); } }
这个例子中,编译器会创建一个StringBuilder对象,用于构造最终的String,并且为每个字符串调用一次StringBuilder的append方法,总计4次。最后调用toString生成结果,并保存为s2.
StringBuilder是java SE5引入的,在这之前java用的StringBuffer.后者是线程安全的,因此开销会大一点,所以在引入StringBuilder操作字符串会更快一点。
3.
public static void main(String[] args) { String hello = "hello"; String hel = "hel"; String lo = "lo"; /* * 输出true * 在"+"两边都是常量字符串,则将两个字符串合并并且在String Pool中查找"hello",然后返回他的内存地址 */ System.out.println(hello == "hel" + "lo"); /* * 输出false * "编译器为了对"hel" + lo语句进行优化,其实会创建一个StringBuilder对象,然后依次调用它的append方法, * 最后调用toString方法返回一个String对象的引用。 */ System.out.println(hello == "hel" + lo); }
4.
public static void main(String[] args) { /* * 虽然两个语句都是返回一个String对象的引用,但是jvm对两者的处理方式是不一样的。对于第一种,jvm会马上在heap中创建一个String对象, * 然后将该对象的引用返回给用户。对于第二种,jvm首先会在内部维护的strings pool中通过String的 equels 方法查找是对象池中是否存放有 * 该String对象,如果有,则返回已有的String对象给用户,而不会在heap中重新创建一个新的String对象;如果对象池中没有该String对象, * jvm则在heap中创建新的String对象,将其引用返回给用户,同时将该引用添加至strings pool中。 * 注意:使用第一种方法创建对象时,jvm是不会主动把该对象放到strings pool里面的,除非程序调用 String的intern方法。 */ String s1 = new String("abc"); String s2 = "abc"; String s3 = new String("abc"); System.out.println(s1 == s2);//false System.out.println(s1 == s3);//false System.out.println(s2 == s3);//false // 程序显式将s1放到strings pool中,intern运行过程是这样的:首先查看strings pool // 有没“abc”对象的引用,没有,则在堆中新建一个对象,然后将新对象的引用加入至 // strings pool中。执行完该语句后,str1原来指向的String对象已经成为垃圾对象了,随时会 // 被GC收集。s1.intern()是在String Pool中的“abc"的引用,s1是在heap中新建“abc”对象的引用。 //分析这类题最好画图,这样比较好理解 System.out.println(s1 == s1.intern());//false System.out.println(s2 == s1.intern());//true System.out.println(s2 == s2.intern());//true System.out.println(s1.intern() == s3.intern());//true }
分析图如下: