String,StringBuilder,StringBuffer总结

String:不可变字符序列    Stringbuilder和StringBuffer:可变字符序列三个类都在java.lang包,都是final类不可继承,都用char[]保存内容

String:

关于String s = "abc";和String s = new String("abc");

拘留字符串对象:equals相同的字符串对象,在堆内存中只会有一个拘留字符串对象。

String s = new String("abc");堆中两个对象:一个拘留对象一个普通对象。在此基础上加:String s2 = new String("abc"); 此时堆中一共三个对象(一个拘留两个普通)

String s = "abc"; 堆中只有一个拘留对象。在此基础上加:String s2 = "abc"; 此时堆中仍然只有一个拘留对象,两个引用指向同一个堆中地址。

“ab”+“cd” == “abcd”,true,一共三个拘留字符串对象,常量池中三个值;

String s = “ab”,s+“cd" == "abcd"; false,四个对象,其中三个拘留字符串对象,常量池中三个值。

String类中的源码

private final char[] value;  所以String是不可变的,new出来的String对象进行操作“+”会new一个新对象然后改变引用(大量+导致效率低:JVM时间消耗主要在创建对象和回收对象)。

重写equals:

    public boolean equals(Object anObject) {
        if (this == anObject) {<span style="white-space:pre">//先判断地址,是不是同一个对象
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {<span style="white-space:pre">//待比较对象是字符串且长度相同时,拿到String的value(字符数组),依次比较
                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;
    }
重写equals必重写hashcode。 源码中hashcode的值:h = 31 * h + val[i];     val表示String存内容的那个字符数组,字符数组多长循环多少次。

substring方法:先判断index是否正确,然后new了一个新String返回。


StringBuilder和StringBuffer:

   异:StringBuffer中所有的insert、append、delete等方法都加了synchronized锁,保证多线程下的同步,但是影响效率;

  StringBuilder是JDK1.5新增的,所有的方法都没有加锁。适用于单线程下的操作,效率比StringBuffer高。但是多线程下不能使用,会出现线程安全问题。

同:都继承自抽象类AbstractStringBuilder,大部分方法的实现都是在这个类里写的,两个实现类基本都是super调它的方法(有无synchronied)。


关于AbstractStringBuilder中的源码:

  char[] value; 保存各字符;区别于String类少了private final的修饰。所以可以改value的引用地址,使这两个类看上去长度是可变的(长度不够数组扩容)。

      append源码:

    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);//保证不会超过当前数组的容量,超过则建新数组替换引用(因为数组长度是final,只能创建新的容量更大的数组,同时拷贝原来的数据)
        str.getChars(0, len, value, count);//将str放到value数组的最后(len)的位置。实现:System.arraycopy(),五个参数。
        count += len;
        return this;
    }
  insert方法类似:判断形参、保证数组容量、System.arraycopy将目标索引后面的元素都向后移、str.getChars将新的str放到字符数组。

  数组扩容的源码:

    void expandCapacity(int minimumCapacity) {  //形参的值:新字符串的实际长度
        int newCapacity = value.length * 2 + 2;  //扩容后的默认大小是原来数组长度的两倍+2
        if (newCapacity - minimumCapacity < 0)  //两倍+2 长度仍然不够新的实际长度
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0)
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);//改变value的引用。原来那个char数组由于没有任何引用可以到达,下一次GC会被回收掉
    }</span>

总结:不需要改变字符串的内容时,使用String,且尽量不要new对象;

     需要改动字符串的内容时(增插删),单线程内使用StringBuilder,多线程使用StringBuffer。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值