String、StringBuffer、StringBuilder 的区别?String为什么是不可变的?
String、StringBuffer与StringBuffer区别
String是字符串常量
StringBuffer和StringBuilder是字符串变量
有时候大家会很疑惑,为什么String会是常量,如下代码:
String s = "abcd";
s = s+1;
System.out.print(s);// result : abcd1
仅仅从视觉上来看,s确实改变了,实际上这里需要大家区分引用和实体对象的概念,第1行,s是String对象的一个引用,指向”abcd”这个String对象,我们这里说的常量意思是String对象的字面值不能改变,而第二行s+1又创建出了一个String对象用来存储新的字面值,然后s重新指向这个新的对象。
而StringBuffer,StringBuffer的值是可以改变的。
StringBuffer是线程安全的,也就是多线程修改同一个StringBuffer对象的时候,过程是同步的,当然这就导致了StringBuffer的效率降低,毕竟如果要提升安全性,就必须要损失一定的效率。
StringBuilder是jdk1.5后新增的,主要就是为了提升单线程下StringBuffer的效率问题,因为StringBuilder没有了同步操作,所以效率提升了。
从以下源码中也可以看出就是多了一个synchronized 的区别。
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, Appendable, CharSequence {
/** * Constructs a string buffer with no characters in it and an * initial capacity of 16 characters. */
public StringBuffer() {
super(16);
}
public synchronized StringBuffer append(int i) {
super.append(i);
return this;
}
public synchronized StringBuffer delete(int start, int end) {
super.delete(start, end);
return this;
}
}
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, Appendable, CharSequence {
public StringBuilder() {
super(16);
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
}
String,StringBuffer与StringBuilder速度区别
从执行效率快慢来看
String < StringBuffer < StringBuilder
但是存在一种特殊情况,就是当String全是字面量相加的时候,这种情况会很快,因为字面量在编译期时,编译器会优化处理,将字面量全部合成一个字面量然后扔进方法区的常量池中,所以运行时当在执行S1指向的时候,这个对象就已经存在与常量池中了,不需要计算了。而StringBuffer 则需要在运行时进行append操作,所以这就造成了这种假象。
常量池可以参看《Java常量池理解》这篇文章。
//String效率是远要比StringBuffer快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“simple”).append(“ test”);
把上面代码换成下面代码,String的执行效率就低了很多,因为运行时需要重新创建一个对象,将S2,S3 ,S4的值相加厚再复制给这个新对象,S1再重新指向这个新对象。
//String速度是非常慢的:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
String为什么是不可变的?
先上源代码:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
...
...
}
String类使用了final修饰,那么使用了final修饰就规定了String是不能被继承的,换句话说,有一个String s=”abc”,s引用我们可以很明确的知道s就是指向的String类型的对象,而不是String类型的子类,这样从jvm的角度考虑,是提升了一定的效率,而且可以看到char value[]也是final,这说明了里面的char数组也是不能改变的,只能进行一次赋值,而且我们都知道数组一旦长度固定,就没有办法扩容,所以这就是为什么String对象里面的值不能改变的原因,因为String对象一旦创建,char数组的长度就刚好够存字符串的长度,以后就没有办法扩充了。