StringBuffe 소스 코드 분석과의 StringBuilder


StringBuffer를하고 StringBuilder에 두 종종 문자열 조작 클래스를 수행하는 데 사용됩니다, 사람들은 보통의 StringBuilder는 스레드로부터 안전하지 않습니다, StringBuffer를이 스레드 안전 알고 있지만, 내부 소스에 대해 너무 많은 분석을하지 않았다, 우리는 두 가지를 분석 이러한 차이점과 장단점 소스.
이 논문의 출발점은, 소스 코드에서 둘 사이의 차이의 상세한 분석을 진행하고, 이전에 대해 모두 일반적인 결론은 기사 요약 작성했습니다 문자열, StringBuffer를하고 StringBuilder의 차이를

1. StringBuffer를

전체 문자열의 StringBuffer 세 클래스 간의 StringBuilder 클래스 구조 :
그림 삽입 설명 여기
할 아래도 상기 클래스 구조 의존성에 직접 또는 간접적으로 의존하고 StringBuffer를 모두 StringBuilder의 Appendable 및 인터페이스 기반의 CharSequence 기본 기능 확장 때문에 문자열 자체는 변경되지 않고, 문자열의 편리하고 효율적인 운용 StringBuffer와 StringBuilder의 순서는, 캐릭터 동작은 문자열을 추가로, 많은 기능을 달성하기 위해, 문자열을 삽입하고, 대체 문자열 그렇다.

1.1 소스 코드 분석

상기 구조 해석에있어서의 StringBuffer 클래스 메인 추상 클래스를 상속 일부 기본 AbstractStringBuilder 캐릭터의 동작 방법을 제공 CharSequence를 AbstractStringBuilder 인터페이스, 삽입하는 문자의 문자를 대체 기능적 문자열 삭제 문자를 추가 등급으로, 문자 인덱스 취득 나눌 수있다 문자열의 문자의 인덱스를 획득하기 위해 주로 스트링 길이를 얻을의 CharSequence 인터페이스를 달성하기위한 일련의 방법은 캐릭터의 동작 방법의 핵심이며, 플립 및 방법에 관한 것이다.
주 : 각 방법은 동기화 된 키워드로 변성되어 있기 때문에 모든 방법, 스레드 안전 더 중량 클래스 로크에 속하는 특성에 따른 잠금 성능이 낮아질 수밖에 없다.
AbstractStringBuilder 기본이되는 문자 배열이 저장 문자에 사용되는 반면 StringBuffer를 전체 속성은 AbstractStringBuilder로부터 상속.

  1. 문자열 값에 저장된 문자의 배열의 사용
    char[] value;
  2. 배열에 저장된 실제 값의 문자 수 계산
    int count;

다음과 같은 기능을 포인트 소스 빗에 따르면,

1.1.1 생성자

1. 빈의 StringBuffer 객체 구성

이 방법은 임의의 스트링을 포함하지 않는 문자열 버퍼 시퀀스를 확립 주로 생성자 호출 상위 클래스 AbstractStringBuilder되면, 기본 버퍼 사이즈는 16 만들어
StringBuffer.java을

public StringBuffer() {
    super(16);
}

AbstractStringBuilder.java

AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

2. StringBuffer와 오브젝트 사이즈 구성 지정된

A는 특정 문자열 버퍼 크기 지정, StringBuffer와 객체의 문자열을 포함하지 않는 만들고, 부모 클래스의 메소드가 슈퍼로 전화 ()와 유사합니다.

public StringBuffer(int capacity) {
    super(capacity);
}

3. 지정된 초기 문자열의 StringBuffer 객체의 구성

특정 문자열은 StringBuffer와 16, 인수 문자열 길이의 기본 크기를 생성하도록 구성의 StringBuffer 객체를 객체

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}

어떤 APPEND ()에있어서 원래의 배열에 문자열을 저장하는데, 이 방법은 여러 스레드간에 이러한 방법의 안전성을 보장하는 방식으로 잠금으로써, 동기 키워드 결합 유의 한 내부 구현 방법은 상위 클래스의 AbstractStringBuilder APPEND () 메소드. 여기에서 당신은 AbstractStringBuilder의 중요성은 기본적으로 StringBuffer와 클래스의 핵심 방법입니다 볼 수 있습니다.

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

) (상위 클래스를 추가 전화

// 该方法是父类AbstractStringBuilder的共用方法
public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    // 用于数组长度的扩展
    ensureCapacityInternal(count + len);
    // 将字符串str追加到value字符数组后
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

배열 확장 방법을 분석하는 :

// 数组扩展的方法
// 该方法是ensureCapacity的非同步版本
// 主要目的将数组扩展至minimumCapacity,主要是利用数组复制的方式
private void ensureCapacityInternal(int minimumCapacity) {
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,newCapacity(minimumCapacity));
    }
}


/**
 * 扩展数组大小的思路
 * 1. 判断参数中的minCapacity和(2*nowCapacity+2) = newCapacity的大小
 * 2. 如果newCapacity < minCapacity,则将数组扩展为minCapacity
 * 3. 如果newCapacity > minCapacity,则将数组扩展为2 * nowCapacity + 2
 * 4. 校验最新扩容的大小,至少不能比Integer.MAX_VALUE大
 * @param minCapacity
 * @return
 */
private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int newCapacity = (value.length << 1) + 2;
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}

/**
 * 校验最新扩容的大小,防止数据溢出
 * @param minCapacity
 * @return
 */
private int hugeCapacity(int minCapacity) {
    if (Integer.MAX_VALUE - minCapacity < 0) { 
        throw new OutOfMemoryError();
    }
    return (minCapacity > MAX_ARRAY_SIZE)
        ? minCapacity : MAX_ARRAY_SIZE;
}

4. 지정된 초기 문자열의 StringBuffer 객체의 구성

문자열로 문자의 문자열 길이 시퀀스는 기본 크기 파라미터를 +16 StringBuffer를 생성 구성된
3 유사한 배열 및 시공 방법의 특정 확장 길이

public StringBuffer(CharSequence seq) {
    this(seq.length() + 16);
    append(seq);
}

1.1.2 기본적인 방법

기본적인 기능에 따른 방법은 프로파일 분석을 제어하기 위해, 각각의 특징이 분석의 한 방법으로서, 다양한 방법을 구별하는 것이다.

1. 추가 자 符串

소스 코드는 방법이 문자열을 추가하는 다양한에서 사용할 수 있지만 비슷한 전반적으로하지만, 다른 처리 요청 매개 변수 만 이제 가장 일반적인 요청 매개 변수 개체에 대한 분석
그림 삽입 설명 여기

/**
 * 追加字符串
 * 该方法继承于AbstractStringBuilder
 * 思路:
 * 1. 将参数做强制类型转化为String,再通过父类AbstractStringBuilder的append()方法追加字符串
 * @param   obj   an {@code Object}.
 * @return
 */
@Override
public synchronized StringBuffer append(Object obj) {
    toStringCache = null;
    // 调用父类的append()方法追加字符串
    super.append(String.valueOf(obj));
    return this;
}

문자열을 제거합니다

인덱스의 특정 범위 내에서 삭제 문자는, 지정된 인덱스 문자, 일관성있는 모든 생각을 삭제하는 방법이있다.

/**
 * @param      start  开始的下标索引
 * @param      end    结束的下标索引
 * @return
 */
@Override
public synchronized StringBuffer delete(int start, int end) {
    toStringCache = null;
    // 通过调用父类的删除字符串方法
    super.delete(start, end);
    return this;
}


/**
 * 删除字符序列中一部分
 * 思路:
 * 1. 前面的都是一些参数的校验,比如检查收尾索引是否得当
 * 2. 通过数组复制的方式删除元素
 * @param start
 * @param end
 * @return
 */
public AbstractStringBuilder delete(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        end = count;
    if (start > end)
        throw new StringIndexOutOfBoundsException();
    int len = end - start;
    if (len > 0) {
        System.arraycopy(value, start+len, value, start, count-end);
        count -= len;
    }
    return this;
}	

문자열의 일부를 취득합니다

/**
 * 获取字符串的一部分
 * @param      start    开始索引
 * @param      end      结束索引
 * @return
 */
@Override
public synchronized String substring(int start, int end) {
    return super.substring(start, end);
}

/**
 * 获取字符串一部分
 * 前面是参数的校验,真正的思路是通过String的构造方法,构造出一个新的字符串
 * @param start
 * @param end
 * @return
 */
public String substring(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        throw new StringIndexOutOfBoundsException(end);
    if (start > end)
        throw new StringIndexOutOfBoundsException(end - start);
    return new String(value, start, end - start);
}

4. 문자 삽입

그림 삽입 설명 여기
전체 삽입의 아이디어를 이해하는 방식에 많은 방법이 있지만, 단 하나 개의 분석 방법이 있기는하지만.

/**
 * 将字符串插入到元字符串中
 * @param      offset   开始插入的索引下标
 * @param      obj      插入的元素
 * @return
 */
@Override
public synchronized StringBuffer insert(int offset, Object obj) {
    toStringCache = null;
    // 调用父类的insert()方法
    super.insert(offset, String.valueOf(obj));
    return this;
}

/**
 * 将字符串插入的原字符索引中
 * 思路:
 * 1. 扩容
 * 2. 复制数组的方式扩展字符数组
 * @param offset        开始索引
 * @param str           插入的字符串
 * @return
 */
public AbstractStringBuilder insert(int offset, String str) {
    if ((offset < 0) || (offset > length()))
        throw new StringIndexOutOfBoundsException(offset);
    if (str == null)
        str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    System.arraycopy(value, offset, value, offset + len, count - offset);
    str.getChars(value, offset);
    count += len;
    return this;
}

5. 가져 오기 첨자

원래 문자열, 방법 비동기 방식의 문자열 str을 시작 위치를 가져옵니다.
이 방법에서는, 다층 전화, StringBuffer를이 -> AbstractStringBuilder -> 문자열

@Override
public int indexOf(String str) {
    return super.indexOf(str);
}
/**
 * 该方法主要用于String、StringBuffer中的搜索使用,
 * @param source            被搜索的字符串
 * @param sourceOffset      被搜索字符的下标
 * @param sourceCount       被搜索字符串的总字符数
 * @param target            搜索的字符串
 * @param targetOffset      搜索字符串下标
 * @param targetCount       搜索字符串总字符数
 * @param fromIndex         开始搜索的下标
 * @return  返回目标字符串的起始下标,如果没有则返回-1
 */
static int indexOf(char[] source, int sourceOffset, int sourceCount,
        char[] target, int targetOffset, int targetCount,
        int fromIndex) {
    if (fromIndex >= sourceCount) {
        return (targetCount == 0 ? sourceCount : -1);
    }
    if (fromIndex < 0) {
        fromIndex = 0;
    }
    if (targetCount == 0) {
        return fromIndex;
    }

    char first = target[targetOffset];
    int max = sourceOffset + (sourceCount - targetCount);

    /**
     * 整体思路:通过双层循环方式寻找目标字符串的开始及结束
     */
    for (int i = sourceOffset + fromIndex; i <= max; i++) {
        /* Look for first character. */
        if (source[i] != first) {
            while (++i <= max && source[i] != first);
        }

        /* Found first character, now look at the rest of v2 */
        if (i <= max) {
            int j = i + 1;
            int end = j + targetCount - 1;
            for (int k = targetOffset + 1; j < end && source[j]
                    == target[k]; j++, k++);

            if (j == end) {
                /* Found whole string. */
                return i - sourceOffset;
            }
        }
    }
    return -1;
}

6. 플립 문자열

분석에 따른 소스, 프로세스 자체의 시간 복잡도는 O (log2N) 인

/**
 * 字符串翻转
 * @return
 */
@Override
public synchronized StringBuffer reverse() {
    toStringCache = null;
    // 通过调用父类的字符串翻转方法
    super.reverse();
    return this;
}


/**
 * 翻转字符串
 * 整体的时间复杂度:O(log2N)
 * @return
 */
public AbstractStringBuilder reverse() {
    boolean hasSurrogates = false;
    int n = count - 1;
    for (int j = (n-1) >> 1; j >= 0; j--) {
        int k = n - j;
        char cj = value[j];
        char ck = value[k];
        value[j] = ck;
        value[k] = cj;
        if (Character.isSurrogate(cj) ||
            Character.isSurrogate(ck)) {
            hasSurrogates = true;
        }
    }
    if (hasSurrogates) {
        reverseAllValidSurrogatePairs();
    }
    return this;
}

용량 길이 및 문자 캐릭터 어레이 (7).

참조 소스 코드는 이전 문자의 개수는 실제의 StringBuffer 객체 저장 획득 후자의 배열의 StringBuffer 객체의 실제 용량을 얻을 수있다, 두 가지 방법의 길이 () 및 용량 () 방법을 제공한다.

/**
 * 获取StringBuffer对象字符串的总长度
 * @return
 */
@Override
public synchronized int length() {
    return count;
}
/**
 * 表示字符数组中的容量,一般该方法获取的值>=length()获取的值
 * @return
 */
@Override
public synchronized int capacity() {
    return value.length;
}

예를 들면 :

public class TestStringBuffer {
    public static void main(String[] args) {
    	// 该构造方法会默认创建长度为26的字符数组
        StringBuffer s = new StringBuffer("helloWorld");
        System.out.println(s.length());         // 10
        System.out.println(s.capacity());       // 26
    }
}

1.1.3 StringBuffer를 요약

이 클래스의 방법은 기본적으로 보장을위한 동기화 키워드 사이에 스레드 안전 멀티 스레드를 추가하고, 위의 방법에서 볼 수 있습니다.

2. 모두 StringBuilder

동기화의 손실이 기능을하지만, 코드 자체 및 이와 유사한 StringBuffer를하지만, 각각의 방법, 아니 모두 StringBuilder 플러스 동기화가 없기 때문에이 문서, 소스 코드의 상세한 분석을 수행하지 않지만, 크게 향상된 성능, 사용 빈도는 일반적으로 StringBuffer를보다 큽니다.

게시 97 개 원래 기사 · 원 찬양 19 ·은 80000 +를 볼

추천

출처blog.csdn.net/weixin_37690143/article/details/104184646