面试:String、StringBuilder以及StringBuffer
参考于:https://www.cnblogs.com/dolphin0520/p/3778589.html
String
被final修饰
大部分方法也被final修饰,反例有
CaseInsensitiveComparator 尽量不要说这个点,会引入 比较器排序知识点,未掌握
String对象的改变,不会影响原对象,而是创建新的对象,所以,String对象不建议经常变动,否则,会造成大量的运行时常量池内存浪费。
每次String str = "zhangsan"生成,都会去常量池中查找"zhangsan",如果有,将地址值修改为原来内容的地址值;没有,那就单独开辟内存空间。
new关键字来生成对象是在堆区进行的,堆区进行对象生成的过程是不会去检测该对象是否已经存在的,所以每次String str = new String("zhangsan"),都是不同的新对象。即:凡是new出来的,正如字面意思,都是新对象。
故
String str1 = "hello world";String str2 = new String("hello world");String str3 = "hello world";String str4 = new String("hello world"); System.out.println(str1==str2); falseSystem.out.println(str1==str3); trueSystem.out.println(str2==str4); false
在分析下面代码
public class Main { public static void main(String[] args) {String string = "";for(int i=0;i<10000;i++){ string += "hello"; } } }
为了更好的分析,我们先使用 javac Main.java
编译一下 Main.class 文件
接下来 就可以使用 javap Main.class 得到 注意观察 下面 变红的
Compiled from "Main.java"public class Main { public Main(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush 10000 9: if_icmpge 38 12: new #3 // class java/lang/StringBuilder 15: dup 16: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V 19: aload_1 20: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 23: ldc #6 // String hello 25: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 28: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 31: astore_1 32: iinc 2, 1 35: goto 5 38: return}
看到 是不是很扯淡?我没有写出来StringBuild,更没有调用append() 方法,别担心,这是 JVM 为了优化 减少性能浪费的。即便如次,我们也能看出来的1w,即:即便JVM 优化,依旧创建了1w个StringBuilder。你想想哪里优化了?其实是使用append()方法。 append()方法,会在原来的基础上修改原来的字符,返还This,不会造成大量的新常量池浪费,减少了gc次数,提高效率,但是创建了那么多的StringBuilder对象,效率还是不够高。
String对比StringBuilder
Builder拥有更好的性能,每次+操作,实际是在原来进行添加修改,减少常量池的损耗,为什么这么说,详细,往下看源码
StringBuilder @Overridepublic StringBuilder append(Object obj) {return append(String.valueOf(obj)); }@Overridepublic StringBuilder append(String str) {super.append(str);return this; } StringBuffer @Overridepublic synchronized StringBuffer append(Object obj) { toStringCache = null;super.append(String.valueOf(obj));return this; }@Overridepublic synchronized StringBuffer append(String str) { toStringCache = null;super.append(str);return this; }
你看,不管是StringBuilder,还是StirngBuffer,在使用append的时候,如果参数类型是String,那么直接相加,如果不是String的引用类型,那么就会先转为String,在进行相加。
所以,在大量相加字符串面前,不管是StringBuilder还是StringBuffer,性能都比String要好。
StringBuilder与StringBuffer对比。
因为Buffer中加入了 synchronized 关键字,这个关键字是在多线程访问时起到安全保护作用的。
所以,StringBuffer是线程安全的。
总而言之 :
不考虑线程安全 大量“加”操作的时候,builder > buffer >String
在线程安全下,大量使用“加”操作,只能使用buffer。
如果看完,还要问Buffer为什么比String要性能好,因为他是有append()方法。
还没有评论,来说两句吧...