JavaSE-String、StringBuilderおよびStringBufferソースコード分析

ディレクトリ

はじめに

ストリング

相続

メンバー変数と構築方法

StringBuilder和StringBuffer

相続

AbstractStringBuilder

メンバー変数と構築方法

拡張方法

append()メソッド

StringBuilder

工法

append()メソッド

toString()メソッド

StringBuffer

メンバー変数と構築方法

append()メソッド

toString()メソッド

まとめ


はじめに


JDK1.8では、String、StringBuilderおよびStringBufferが文字列の操作に一般的に使用されます。Stringは不変の文字シーケンスであり、StringBuilderとStringBufferは可変文字シーケンスです。StringBuilderはスレッドセーフではなく、StringとStringBuilderはスレッドセーフです。それらの内部実装を分析しましょう。

ストリング


相続


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

ご覧のとおり、StringはSerializableComparable、およびCharSequenceインターフェースを実装しています。Serializableは、直列化可能なマークです。Comparableインターフェースには、compareTo()メソッドが含まれていますCharSequenceインターフェースには、charAt()length()subSequence()、およびtoString()メソッドが含まれています。

メンバー変数と構築方法


private final char value[];

private int hash; // Default to 0

public String() {
    this.value = "".value;
}

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

public String(char value[], int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count <= 0) {
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        if (offset <= value.length) {
            this.value = "".value;
            return;
        }
    }
    // Note: offset or count might be near -1>>>1.
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
    }
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

文字列は定数char []配列を使用して文字列を格納します。これは不変です。Char []配列はString型に変換されます。これは、Arrays copyOff()メソッドを介したディープコピーであり、ローカルのchar []配列をコピーして定数char []配列に割り当てます。

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によって実装されるクラスとインターフェースはまったく同じであり、SerializableCharSquenceインターフェースはStringのように実装されていることがわかります。最も重要なことは、継承されたAbstractStringBuilder抽象クラスがStringBuilderおよびStringBufferのほとんどのメソッドをカプセル化することです。

AbstractStringBuilder


メンバー変数と構築方法


char[] value;

int count;

AbstractStringBuilder() {
}

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

AbstractStringBuilderは文字列を格納するchar []配列も定義しますが、finalで変更されないため、文字列は可変です。同時に、タイプがintのグローバル変数coutも定義されています。設定は初期容量の指定することができたときの容量をより良いパフォーマンスを得るためには、。

拡張方法


public void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > 0)
        ensureCapacityInternal(minimumCapacity);
}

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
            newCapacity(minimumCapacity));
    }
}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

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

private int hugeCapacity(int minCapacity) {
    if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
        throw new OutOfMemoryError();
    }
    return (minCapacity > MAX_ARRAY_SIZE)
        ? minCapacity : MAX_ARRAY_SIZE;
}

AbstractStringBuilderの展開メソッドは、newCapacity()によって実装さます。この方法では、容量が元の容量の2倍に拡張され(*の代わりにシフト操作が使用されます)、2が追加されます。拡張された容量が指定された容量より少ない場合、minCapacityを最新の容量に設定します。Integerの最大値(0x7fffffff)-8が最新の容量よりも小さい場合は、hugeCapacity()メソッドを呼び出しますオーバーフローするかどうかを判断するには、オーバーフローする場合は例外OutOfMemoryErrorをスローし、そうでない場合は、新しい容量がIntegerの最大値-8より大きい場合は容量をminCapacityに設定し、それ以外の場合はInteger-8の最大値に設定します。Integerの最大値(0x7fffffff)-8が最新の容量より大きい場合、それ以外の場合、容量はnewCapacityに設定されます

append()メソッド


public AbstractStringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

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

private AbstractStringBuilder appendNull() {
	int c = count;
	ensureCapacityInternal(c + 4);
	final char[] value = this.value;
	value[c++] = 'n';
	value[c++] = 'u';
	value[c++] = 'l';
	value[c++] = 'l';
	count = c;
	return this;
}

append()メソッドは、StringBuilderおよびStringBufferの最も一般的に使用されるメソッドであり、文字列を追加するための多くのメソッドをオーバーロードします。最初のappend()メソッドは、objオブジェクトString型に変換し、StringのvalueOf()メソッドを介して追加します。第二のappend()メソッド、場合strがあるヌル、コールappendNull()メソッド、最初の拡張(生容量プラス4ついで)、追加の「N-」「U」「L」「L」 4のキャラクター。場合strがないヌル、最初の拡張(生容量に加えて、文字列の長さ)、コール文字列GetCharsは()メソッド、STRに加え文字[]配列値を末尾に、そして最終的に能力元の容量+文字列の長さ。オブジェクト自体を返すため、append()メソッドを継続的に呼び出すことができます

StringBuilder


工法


public StringBuilder() {
	super(16);
}

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

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

StringBuilderのデフォルトの容量16であり、その初期容量も指定できることわかります。StringBuilderオブジェクトに文字列を割り当てる場合、この時点でのStringBuilerの容量は、現在の文字列の長さ16を加えたものになります。

append()メソッド


@Override
public StringBuilder append(Object obj) {
	return append(String.valueOf(obj));
}

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

StringBuilderのappend()メソッドは、抽象クラスAbstractStringBuilderを書き換えて、多くのappend()メソッドをオーバーロードするメソッドです。そのメソッドの実装は親クラスAbstractStringBuilderのappend()メソッドを呼び出すことです。複数のスレッドがこのメソッドにアクセスする場合、countはグローバル変数であるため、複数のスレッドがcount + = lenを実行すると、countの値に問題が発生し、実際の値と矛盾するため、StringBuilderスレッドは安全ではありません

toString()メソッド


@Override
public String toString() {
	// Create a copy, don't share the array
	return new String(value, 0, count);
}

StringBuilderはObjecttoString()メソッドを書き換え新しいStirng()は内部的にArrayscopyOfRange()メソッド(ディープコピー)を呼び出し、新しいStringオブジェクトを返し、元のオブジェクトとメモリ空間を共有しません。

StringBuffer


メンバー変数と構築方法


private transient char[] toStringCache;

public StringBuffer() {
	super(16);
}

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

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

構築した場合、StringBufferのStringBuilderのデフォルトとして、容量の大きさ16は、初期容量を指定することができます。唯一の違いは、StringBufferが、transientで装飾されたchar []配列toStringCacheを定義することです。一時的なキーワード。変数を変更する場合、変数はシリアル化できません。

append()メソッド


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

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

可視のStringBufferStringBuilderの書き換えなどAbstractStringBuilder親クラスのappend()メソッドは、の親クラスの内部実装呼び出しのappend()メソッド、およびヘビーデューティの数のappend()メソッドを。唯一の違いは、StringBufferがデータを変更するたびに、char []配列toStringCacheが空に設定されStringBufferの各メソッドの前に、同期されたキーワードが続くことです。複数のスレッドがこのメソッドにアクセスすると、1つのスレッドがこのメソッドにアクセスし、他のスレッドはロックされてこのメソッドにアクセスできなくなります。このスレッドがこのメソッドを実行してロックを解除した場合のみ、他のスレッドがこのメソッドにアクセスできるため、StringBufferスレッドセーフです。

toString()メソッド


@Override
public synchronized String toString() {
	if (toStringCache == null) {
		toStringCache = Arrays.copyOfRange(value, 0, count);
	}
	return new String(toStringCache, true);
}

String(char[] value, boolean share) {
	// assert share : "unshared not supported";
	this.value = value;
}

StringBuffertoString()メソッドStringBuilderとは異なります。toStringCachenullの場合、最初にキャッシュされ、最後にStringオブジェクトが返されます。StringBuffer新しいString()は、配列copyOfRange()メソッドを呼び出さず、単純な配列割り当て(浅いコピー)のみを行い、要素をコピーする時間を節約します。

まとめ


  • Stringは不変の文字列で、StringBufferとStringBuilderは可変文字列です。
  • StringBuilderはスレッドセーフ高速であり、StringBufferはスレッドセーフ低速です。
  • StringBuilderおよびStringBufferのほとんどのメソッドは、親クラスAbstractStringBuilderの実装を呼び出します。拡張メカニズムでは、最初に容量を元の容量の2倍+ 2に増やします。最大容量は、整数の最大値(0x7fffffff)-8です。
  • StringBuilderとStringBufferのデフォルトの容量はどちらも16です。StringBufferとStringBuilderを作成するときにサイズを指定して、パフォーマンスを向上させるのに十分な容量がない場合に自動拡張を回避できます。
131件の元の記事を公開 12 件を獲得 60,000回の閲覧+

おすすめ

転載: blog.csdn.net/JavaDestiny/article/details/100710981