Java 7のベースタイプ6編-Java可変文字列タイプ


実際のプロジェクト開発では、動的なSQL文のつづりなど、可変文字列を操作する場合が多いかもしれません.
StringBuilderとStringBufferを可変文字列と呼ぶのは、
(1)append()メソッドのような元の文字列を大幅に変更する操作を提供する.変更は元の文字列に基づいて修正され、Stringのいくつかの方法とは異なり、new String()によって新しい文字列が返されます.
(2)文字列は自動的に拡張され,人為的な操作を必要とせず,String自体は拡張を行わない.
この2つのクラスの実装について詳しく説明します.まずAbstractStringBuilderクラスを見てみましょう
abstract class AbstractStringBuilder implements Appendable, CharSequence {
	//      
    char[] value;
    int count;    // The count is the number of characters used.
    //     
    AbstractStringBuilder() {   }
    
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
    //   
    public int capacity() {
        return value.length;
    }

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

    /**
     * This implements the expansion semantics of ensureCapacity with no
     * size check or synchronization.
     */
    void expandCapacity(int minimumCapacity) { //    value       
        int newCapacity = value.length * 2 + 2;//         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);//                 
    }
}
は、上記のように文字配列を定義し、制限はありません.拡張方法といくつかのデフォルトの構築方法も提供されています.クラスはAppendableインタフェースを継承するため、このインタフェースは主にappend()メソッドを定義し、この抽象クラスで実装されています.
public AbstractStringBuilder append(CharSequence s, int start, int end) {
        if (s == null)
            s = "null";
        if ((start < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException("start " + start + ", end " + end + ", s.length() "  + s.length());
        int len = end - start;//          
        ensureCapacityInternal(count + len); //   value       
        for (int i = start, j = count; i < end; i++, j++) //                value     
            value[j] = s.charAt(i);
        count += len;
        return this;
    }

多くのappend()メソッドがあり、処理方法は非常に似ており、興味のある人は自分で見ることができます.append()メソッドは末尾でのみ追加できますが、文字列の真ん中を挿入する場合はinsert()メソッドを使用して、例を挙げます.
 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);//  value          len   
        str.getChars(value, offset); //  str        value     
        count += len;
        return this;
    }

自動拡張が行われ、str文字列の文字がvalueの指定された位置に挿入されることがわかります.自動的に拡張されるので、可変文字列を使用する場合は、拡張を防止するために十分な容量を指定することが望ましい.下位層は配列のコピーを行う必要があるからです.
テスト手順は次のとおりです.
StringBuilder str =new StringBuilder("abc");
str.insert(1, "xx");
System.out.println(str.toString());// axxbc

StringBuilderクラスとStringBufferクラスはこの抽象クラスを実現しているが、StringBufferクラスで公開されている方法にsynchronizedキーワードを加えて同期するのもStringBuilderとの最大の違いである.
CharSequenceは文字シーケンスを表すインタフェースであり、String、StringBuilder、StringBufferはこのインタフェースを実現し、下位層は配列によって実現される.
String、StringBuilder、StringBufferの異同点を前に書いたブログと結びつけて、この3つのよく使われるクラスの異同点を分析します.
異同点:
  • Stringのオブジェクトは可変ではありません.StringBuilderとStringBufferは可変です.
  • StringBuilderはスレッドが安全ではありません.StringBufferはスレッドが安全な
  • です
  • Stringのoffset,value,countはfinalによって修飾された修正不可能である.一方、StringBufferとStringBuilderのvalueでは、countはAbstractStringBuilderクラスから継承され、finalによって修飾されず、実行中に修正可能でoffset変数がないことを示しています.

  • 同じ点:
    3つのクラスはfinalで修飾されており、継承できません.いずれも表示文字列を表すことができます(ソースコードではCharSequence.javaクラスが継承されていることがわかります)