String、StringBuffer、StringBuilder 的区别?String为什么是不可变的?

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数组的长度就刚好够存字符串的长度,以后就没有办法扩充了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值