java中String、StringBuffer、StringBuilder

jdk1.8 源码,三个类的类图如下

说明:

 是否可变对象equals() 和hashcode()是否线程安全
String不可变对象重写 
StringBuffer可变对象未重写线程安全(synchronized修饰方法)
StringBuilder线程不安全

首先明确什么不可变对象。一个对象在创建完成之后,不能再改变它的状态,那么这个对象是不可变对象。不能改变状态即不能改变对象内的成员。对于基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,且引用类型指向的对象的状态也不能改变。

1.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;
    
     public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

     public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
}

从源码可以看出String类中使用字符数据保存字符串,private final char value[];

使用final修饰符,所有String对象是不可变。此外,final类是不可继承的的,所以String类不可继承。String中的对象是不可变的,也就可以理解为常量,显然线程安全。

重写了equals() 和hashcode() 方法,所以String比较时,比较的是内容。


2.StringBuffer

StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,方法使用synchronized 修饰,所以是线程安全的。看如下源码:

 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    private transient char[] toStringCache;

    static final long serialVersionUID = 3388685877147921107L;

    public synchronized int length() {
        return count;
    }
    @Override
    public synchronized char charAt(int index) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        return value[index];
    }
    ...
}

3.StringBuilder

StringBuilder并没有对方法进行加同步锁,所以是非线程安全的

public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence{
    @Override
    public StringBuilder reverse() {
        super.reverse();
        return this;
    }
}

4.StringBuilder与StringBuffer共同点

它们的区别就在于一个关键字:synchronized。StringBuffer线程安全,StringBuilder线程不安全,所以决定了它们的使用场景,单线程和多线程。在单线程中,使用StringBuilder的效率要高,在多线程中,使用StringBuffer。

  StringBuilder与StringBuffer有公共父类AbstractStringBuilder(抽象类)。StringBuilder和StringBuffer的初始大小都是16。

  抽象类与接口的其中一个区别是:抽象类中可以定义一些子类的公共方法,子类只需要增加新的功能,不需要重复写已经存在的方法;而接口中只是对方法的申明和常量的定义。

  StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法,如super.append(...)。只是StringBuffer会在方法上加synchronized关键字,进行同步。

5.CharSequence接口和Serializable接口

5.1 CharSequence 接口

实现了这个接口的类有:CharBuffer、String、StringBuffer、StringBuilder这个四个类。提供这么一个接口,有些处理String或者StringBuffer的类就不用重载了。但是这个接口提供的方法有限,只有下面几个:charat、length、subSequence、toString这几个方法

 而这个接口中要强调的重点是:CharSequence并没有提取出IObject中的hashCode和equals方法的通用规范。所以对于2个不仅实现了CharSequence接口的对象(还继承了其他的类)的对象来说,在比较时,其结果也是未定义的。(因为对于继承了Object的类来说,根据具体的实现,比较时,是有2中选择的,比较地址用==,比较内容用equals。),每一对象都可以由不同的类来实现,不确定其是否具备同等比较的能力。因此,使用任意 的CharSequence实例作为Set集合的元素或者map中的key,都是不合适的,因为CharSequence实例没有equlas方法。

public interface CharSequence {
  
    int length();

    char charAt(int index);

    CharSequence subSequence(int start, int end);

    public String toString();
    ...  //还有其他方法
}

5.2 Serializable接口

public interface Serializable {
}

在Serializable接口中,只是声明了一个接口,不包含任何变量或函数。这个接口的作用是实现对象的序列化与反序列化。

序列化:将对象转换为字节序列的过程称为序列化。

反序列化:将字节序列转换为对象的过程称为反序列化。

序列化与反序列化应用场景:对象持久化,网络中传输对象信息。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值