String StringBuilder StringBuffer

1,String 是不可变类 immutable 

    不可变类:所谓的不可变类是指这个类的实例一旦创建完成后就不能改变其成员变量值。如JDK内部自带的很多不可变类:八大包装类和String等。
    可变类:相对于不可变类,可变类创建实例后可以改变其成员变量值,开发中创建的大部分类都属于可变类。 

    以String 为例,不可变类,一般如何设计?

    1,类一般会用final 来修饰,无法创建子类

  

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

}

     2,类里面的成员变量等都会用private 来修饰

     3, 不会提供setters,append 等方法来改变变量值

2,String 对象的创建发方式

   String k = "hello,world"

   String i = "hello,world" //通过JVM 虚拟机创建

   String j = new String("hello,world") //通过构造器创建

    k == i // true 

   对象的比较是比较地址,JVM创建的对象,如果值相同,会指向同一个地址

   i == j // false

   通过new 生成的对象,会指向新的地址

3,String 重写了Object 里面的equals 方法 

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;
    }

4,String 因为是不可变类,所以处理字符起来比较麻烦,也比较占用资源,因此可以用这两个可变类:

     StringBuilder StringBuffer

 

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {

      相同点:StringBuilder  StringBuffer 都是 继承于 类 AbstractStringBuilder

      不同点:StringBuilder 是现线程不安全,StringBuffer 是线程安全的,因为StringBuffer 的方法上加上了线程同步 syncronized

    @Override
    public synchronized StringBuffer append(String str) { // 线程同步
        toStringCache = null;
        super.append(str);
        return this;
    }
@Override
public StringBuilder append(String str) { super.append(str); return this; }

 

另外:StringBuilder是如何append的?

以append(String str) 为例子

StringBuilder 类下面有方法,是重写了父类的append 方法

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

其父类

    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len); //扩容
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

因为String 的底层是char[]  StringBuilder 也是将字符存在char []中

str.getChars(0, len, value, count) 通过调用了String 类下面的getChars方法,
len 代表新增的str 的长度
value 代表 StringBuilder 对象的char[]
count 代表 StringBuilder 对象的char[] 的长度

String 类下面的getChars 方法
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }
getChars 方法传入了
srcBegin : 0
srcEnd :需要append的str 的长度
dst:StringBuilder 对象的char[]
dstBegin:StringBuilder 对象的char[] 的长度
通过调用 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin)方法
value:
需要append的str char[]
这个方法通俗的的将就是将 str 的 char[] 从0 开始 到 char[] 长度 copy 到目标数组,目标数组是StringBuilder 对象的char[],从它的length 的下标开始复制(也就是接着复制)

因为 system.arraycopy 是浅拷贝,直接改变目标数组的数据结构,虽然对象的引用并没有返回从String 这个方法 返回到StringBuilder 下的append 方法下,但是内存中的值已经改了,所以StirngBuilder 的char[] 已经更改

证明:hashcode 的值是一样的

 

综上:

  1. 操作少量的数据: 适用String
  2. 单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer

 

    

 

    

    

    

posted @ 2019-06-20 13:33  Chris,Cai  阅读(169)  评论(0编辑  收藏  举报