ホームページ  >  記事  >  Java  >  Java StringBuilder および StringBuffer のソース コード分析

Java StringBuilder および StringBuffer のソース コード分析

高洛峰
高洛峰オリジナル
2017-01-22 11:28:401119ブラウズ

StringBuilder と StringBuffer は、文字列を操作するためによく使用される 2 つのクラスです。ご存知のとおり、StringBuilder はスレッド セーフではありませんが、StringBuffer はスレッド セーフです。前者は JDK1.5 で追加され、後者は JDK1.0 で利用可能になりました。内部実装を分析してみましょう。

1. 継承関係

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

2 つのクラスの継承関係は全く同じであることがわかります。 Serializable はシリアル化できるフラグです。 CharSequence インターフェイスには、charAt()、length()、subSequence()、および toString() メソッドが含まれています。String クラスもこのインターフェイスを実装します。ここで注目するのは、StringBuilder と StringBuffer のほとんどの操作の実装をカプセル化する抽象クラス AbstractStringBuilder です。

2. AbstractStringBuilder

1. 変数と構築メソッド

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

AbstractStringBuilder は内部で char[] 配列を使用して文字列を保存し、構築時に初期容量メソッドを指定できます。

2. 容量の拡張

public void ensureCapacity(int minimumCapacity) {
  if (minimumCapacity > 0)
    ensureCapacityInternal(minimumCapacity);
}
 private void ensureCapacityInternal(int minimumCapacity) {
  // overflow-conscious code
  if (minimumCapacity - value.length > 0)
    expandCapacity(minimumCapacity);
}
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);
}

拡張メソッドは、最初にexpandCapacity()によって実装されます。この時点でまだ指定された容量に達していない場合は、容量を元の容量に2を加えた値に拡張します。の場合、新しい容量は次のようになります。容量は minimumCapacity に設定されます。次に、オーバーフローするかどうかを判断します。オーバーフローする場合は、容量を Integer.MAX_VALUE に設定します。最後に値がコピーされますが、これは明らかに時間のかかる操作です。

3. append() メソッド

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

append() は最も一般的に使用されるメソッドであり、さまざまな形式のオーバーロードがあります。上記はそのうちの 1 つで、文字列を追加するために使用されます。 str が null の場合、appendNull() メソッドが呼び出されます。このメソッドは実際に文字「n」、「u」、「l」、および「l」を追加します。 null でない場合は、最初に容量が拡張され、次に String の getChars() メソッドが呼び出され、値の末尾に str が追加されます。最後に、オブジェクト自体が返されるため、append() を継続的に呼び出すことができます。

3. StringBuilder

AbstractStringBuilder には、必要なメソッドのほとんどが StringBuilder と StringBuffer を呼び出すだけで実装されています。 StringBuilder の実装を見てみましょう。

1. コンストラクター

public StringBuilder() {
  super(16);
}
public StringBuilder(int capacity) {
  super(capacity);
}
public StringBuilder(String str) {
  super(str.length() + 16);
  append(str);
}
public StringBuilder(CharSequence seq) {
  this(seq.length() + 16);
  append(seq);
}

StringBuilder のデフォルトの容量が 16 であることがわかります。もちろん、初期容量を指定したり、既存の文字シーケンスを使用して StringBuilder オブジェクトに初期値を割り当てることもできます。

2. append() メソッド

public StringBuilder append(String str) {
  super.append(str);
  return this;
}
public StringBuilder append(CharSequence s) {
  super.append(s);
  return this;
}

append() には多くのオーバーロードされたメソッドがあります。ここでは 2 つを紹介します。明らかに、ここには直接呼び出される親クラス AbstractStringBuilder のメソッドがあります。

3. toString()

public String toString() {
  // Create a copy, don&#39;t share the array
  return new String(value, 0, count);
}

toString() メソッドは、元のオブジェクトとメモリを共有しない新しい String オブジェクトを返します。実際、AbstractStringBuilder の subString() メソッドにも同じことが当てはまります。

4. SringBuffer

StiringBuffer は StringBuilder に似ていますが、同期を実現するために、次のメソッドのように多くのメソッドが lSynchronized で変更されている点が異なります。メソッドの前にあります。

さらに、上記の append() メソッドと setLength() メソッドには変数 toStringCache があります。この変数は、StringBuffer が変更されるたびに、最新の toString() メソッドのキャッシュに使用され、null の値が割り当てられます。 StringBuffer の toString は以下の通りです:

public synchronized int length() {
    return count;
}
public synchronized StringBuffer append(String str) {
  toStringCache = null;
  super.append(str);
  return this;
}
public synchronized void setLength(int newLength) {
  toStringCache = null;
  super.setLength(newLength);
}

このメソッドでは、toStringCache が null の場合、最初にキャッシュされます。最終的に返される String オブジェクトは少し異なります。このコンストラクターにはパラメーター true もあります。 String のソース コードを見つけて見てください:

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


この構築メソッドによって構築された String オブジェクトは、実際には文字列をコピーするのではなく、構築パラメータに値をポイントしているだけであることがわかります。要素をコピーする時間。ただし、このコンストラクターにはパッケージへのアクセス権があり、通常の状況では呼び出すことはできません。

概要

StringBuilder と StringBuffer はどちらも変更可能な文字列で、前者はスレッド セーフであり、後者はスレッド セーフです。

StringBuilder および StringBuffer のほとんどのメソッドは、親クラス AbstractStringBuilder の実装を呼び出します。その拡張メカニズムは、まず容量を元の容量の 2 倍に 2 を加えた値に変更します。最大容量は Integer.MAX_VALUE、つまり 0x7fffffff です。

StringBuilder と StringBuffer のデフォルトの容量は両方とも 16 です。展開による時間の消費を避けるために、文字列のサイズを事前に見積もることをお勧めします。

上記がこの記事の全内容です。Java で文字列を操作するためによく使用される 2 つのクラス、StringBuilder と StringBuffer を学習するのに役立つことを願っています。

Java StringBuilder および StringBuffer のソース コード分析に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。