Java String、StringBuffer、StringBuilderの違い

26123 ワード

Javaで文字列を作成する3つの方法を見てみましょう.String、StringBuffer、StringBuilderです.

0、概要


結論から言えば、次は一つ一つ理解してみましょう.

1.文字列生成方式


不変性と可変性を理解するには、その作成方法を理解する必要があります.

1) String


Stringクラスを使用して文字列を作成する方法は、大きく2つあります.1) 리터럴 방식 (쌍따옴표) 2) 생성자 방식メモリの使用効率が低いため、ジェネレータメソッドはあまり使いにくい.
したがって、String은 리터럴 방식を使用すると仮定します.

テキスト方式(二重引用符)


Javaでは、""の二重引用符文字列を作成する方法を리터럴 방식と呼びます.
文字方式は、まずHeapのString Constant Poolを検索し、hello文字列を検索します.ない場合は作成し、ある場合はアドレス値を参照し、作成しません.
class Main {
    public static void main(String[] args) {
        // 1) 리터럴 방식
        // String constant Pool에 hello 저장
        String a = "hello";
        // 이미 저장된 hello 참조
        String b = "hello";

        System.out.println(a == b); // 주소비교 true
        System.out.println(a.equals(b)); // 값 비교 true
    }
}

ジェネレータモード


新しいオブジェクトを作成してheapに保存するたびに.
メモリ管理もString Constant Poolでは行えないため、効率が悪い.
class Main {
    public static void main(String[] args) {
        // 생성자 방식
        // heap에 hello 문자열 저장
        String a = new String("hello");
        // heap에 hello 문자열 저장
        String b = new String("hello");

        System.out.println(a == b); // 주소비교 false
        System.out.println(a.equals(b)); // 값 비교 true
    }
}

2) StringBuffer, StringBuilder


StringBufferとStringBuilderの作成方法は同じです.
16個の連続メモリ領域が最初に割り当てられます.領域を超えると、より長い連続メモリ領域が割り当てられ、以前の内容がコピーされます.

2.不変、可変


1)定義


不変、可変の意味は次のとおりです.불변は現在参照されている주소의 값이 변하지 않음を表し、가변は現在参照されている참조하고 있는 값이 변할 수 있음を表している.

2) String


Stringは、新しい文字列を置換するときに古い参照値を破棄し、新しいアドレスを参照します.
class Main {
    public static void main(String[] args) {

        // a - "hello" 참조
        String a = "hello";
        // b - "hello" 참조
        String b = a;
        // a - 새로운 객체 "hello world" 참조 - "hello"는 더이상 참조하지 않음
        a += " world";

        // a는 "hello world" 참조
        System.out.println("a " + a);
        // b는 "hello" 참조
        System.out.println("b " + b);
    }
}

3) StringBuffer, StringBuilder


現在のアドレス値から新しい文字列を追加した後、連続メモリ領域に追加します.
ArrayList.
class Main {
    public static void main(String[] args) {

        // a - "hello" 참조
        StringBuffer a = new StringBuffer("hello");
        // b - "hello" 참조
        StringBuffer b = a;
        // a - "hello world" 참조, 참조하는 주소의 값이 변경된 경우
        a.append(" world");
        
        // a는 "hello world" 참조
        System.out.println("a " + a);
        // b는 "hello world" 참조
        System.out.println("b " + b);
    }
}

4)整理


長所

  • 重複除外によるメモリ使用率の向上
    重複文字列を複数回作成すると、新しいオブジェクトを作成することなく、リファレンスによってメモリ効率を向上させることができます.
  • スレッドセキュリティ
    String値を同時に参照しても更新できないため、複数のねじが常に同じ値であることを確認します.
  • 不変の欠点


  • 文字列の変更が多すぎると、新しいオブジェクトを作成し続けるとメモリの使用効率が低下します.
    新しい文字列が既存の文字列に追加され続ける場合、Stringは古い参照オブジェクトを破棄し続け、参照用に新しいオブジェクトを作成します.
    これにより、不要なオブジェクトが大量に生成され、メモリの使用率が向上します.
  • class Main {
        public static void main(String[] args) {
            String a = "";
            for(int i=0; i<100000; i++) {
                // 새로운 객체 참조
                a += "";
            }
        }
    }

    可変のメリット

  • 文字列を変更する必要がある場合は、
  • を追加してメモリ効率を向上させることができます.

    3.スレッドセキュリティ


    1)定義


    スレッドセキュリティは、複数のスレッドに同時にアクセスしてもプログラムの動作に問題が発生しないことを意味します.

    2)スレッドセキュリティ


    String


    変化しないため、いずれの場合も同じ値であることを確認します.

    StringBuffer


    複数のスレッドがsynchronizedキーワードで同時にアクセスされている場合は、一度に1つのスレッドしか使用できず、スレッドのセキュリティが確保されます.

    StringBuilder


    スレッドセキュリティはまったく設定されません.

    4.演算速度


    0)概要


    String-遅い-O(xn^2)-xは連続文字の長さ、nはカウント
    StringBuffer-中間-O(xn)
    StringBuilder-高速-O(xn)

    1) String


    最大백만번の追加演算1156msが必要です.
    Stringは+演算を実行するたびに新しい文字列をコピーします.
    1 + 2 + .... n=n(n+1),O(xn^2).
    class Main {
        public static void main(String[] args) {
            long beforeTime = System.currentTimeMillis();
    
            String a = "";
            for(int i=0; i<1000000; i++) {
                a += "a";
            }
    
            long afterTime = System.currentTimeMillis();
            long secDiffTime = (afterTime - beforeTime);
            System.out.println("시간차이(ms) : "+secDiffTime);
        }
    }

    2) StringBuffer


    追加演算1억번は、951msを必要とする.
    class Main {
        public static void main(String[] args) {
            long beforeTime = System.currentTimeMillis();
    
            StringBuffer sb = new StringBuffer();
            for(int i=0; i<100000000; i++) {
                sb.append("a");
            }
    
            long afterTime = System.currentTimeMillis();
            long secDiffTime = (afterTime - beforeTime);
            System.out.println("시간차이(ms) : "+secDiffTime);
        }
    }

    3) StringBuilder


    追加演算1억번は、371msを必要とする.
    class Main {
        public static void main(String[] args) {
            long beforeTime = System.currentTimeMillis();
    
            StringBuilder sb = new StringBuilder();
            for(int i=0; i<100000000; i++) {
                sb.append("a");
            }
    
            long afterTime = System.currentTimeMillis();
            long secDiffTime = (afterTime - beforeTime);
            System.out.println("시간차이(ms) : "+secDiffTime);
        }
    }

    5.整理


    だからいつ何を使うかが一番重要です

    String


    少量の文字列追加と重複除外が必要なスレッドセキュリティ環境

    StringBuffer


    文字列付加操作の多いスレッドセキュリティ環境

    StringBuilder


    マルチスレッド環境では、スレッドセキュリティを考慮する必要はほとんどありません.
    本当に、例えば、アルゴリズムを解く
    最近はあまり流行していませんが、以前は文字列入力を直接受信して処理することがよくありました.
    BufferedReaderアクセラレータを使用し、BufferedReaderは内部で文字列を受信するときにStringBuilderを使用します.
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    class Main {
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
            // 문자열 한줄 읽기
            int n = Integer.parseInt(br.readLine());
        }
    }