JAVA回顾巩固之String、StringBuilder、StringBuffer结合源码比较

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/diaomeng11/article/details/52012645

今天回顾巩固了一下java的基础知识,那么String、StringBuilder、StringBuffer之间有什么区别呢?

尝试查看源码之后,有了一个清晰的认识。

首先大体说明,通常情况下大家都知道,String是不可变的字符串对象,StringBuilder、StringBuffer是可变的,其中StringBuilder线程不安全,StringBuffer线程安全,具体情况如下:

String:

源码注释写到:“Strings are constant; their values cannot be changed after they are created.“

具体到代码中:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    private final char value[];<pre name="code" class="java">    <span style="font-family: Arial, Helvetica, sans-serif;">…</span><span style="font-family: Arial, Helvetica, sans-serif;">…</span><pre name="code" class="java">}
 
 
 看一看到,String其实就是一个char数组,但是由于使用了private修饰,且没有给出外部接口,又使用了final修饰,使得这个String对象一旦创建,就不能进行修改。 
 

至于为什么可以对String进行赋值等操作,是因为对String进行赋值等操作以后,其实是给了String变量一个新的String对象,而之前被创建的对象依然存在于内存中。


StringBuilder和StringBuffer:

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

从源码中可以看出StringBuilder和StringBuffer都继承于AbstractStringBuilder,实现的接口也是一致的。

再来看AbstractStringBuilder:

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;
接口AbstractStringBuilder中,可以看到,StringBuilder和StringBuffer其实也是char数组,只不过没有用private和final进行修饰,这意味着他们是可变的。


其中最重要的一个方法就是append,同个这个方法,使得他们可以对数组进行扩容,我们都知道数组一旦被定义,那么长度就是一定的,不能再进行改变了,那他们是怎么做到对数组进行扩容的呢,于是查看了AbstractStringBuilder中以下源码:

void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }

   public static char[] copyOf(char[] original, int newLength) {
        char[] copy = new char[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

这里可以发现,其实并不是对原本的数组进行了修改,而是新建了一个数组,将原数组内容进行了copyOf操作,让value引用了新数组,旧的数组等待被回收。

而后通过观察发现,他们实现的方法也基本一致。

StringBuilder:

    private StringBuilder append(StringBuilder sb) {
        if (sb == null)
            return append("null");
        int len = sb.length();
        int newcount = count + len;
        if (newcount > value.length)
            expandCapacity(newcount);
        sb.getChars(0, len, value, count);
        count = newcount;
        return this;
    }
    public StringBuilder append(StringBuffer sb) {
        super.append(sb);
        return this;
    }
StringBuffer:

 public synchronized StringBuffer append(StringBuffer sb) {
        super.append(sb);
        return this;
    }

这里可以看出唯一的区别是StringBuffer的方法基本上都有synchronized修饰,synchronized本意是同步的,java中用它来修饰一个方法或一块代码时,能保证同一时刻最多只有一个线程能执行改代码。所以有synchronized修饰即线程安全的。


比较的同时,通读了3个类中的源代码,发现了很多方法是以前不曾注意过的,但是都很有用。



猜你喜欢

转载自blog.csdn.net/diaomeng11/article/details/52012645