0Pricing
Java Academy · レッスン

文字列が不変である理由

文字列の不変性を理解します

「文字列が不変である理由」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

文字列は変更できない

Java の String は不変です。一度作成すると、その文字を変更することはできません。文字列を変更しているように見えるメソッドも、実際にはまったく新しい文字列を返します。

メソッドは新しい文字列を返す

toUpperCase() や replace() などのメソッドは、元の文字列を変更しません。新しい String を生成し、元の文字列はそのまま残します。

public class Main {
    public static void main(String[] args) {
        String original = "hello";
        String upper = original.toUpperCase();
        System.out.println("original: " + original);
        System.out.println("upper: " + upper);
    }
}

再代入は変更ではない

s = s + "!" と記述すると、変数は新しい文字列を指すようになります。古い文字列オブジェクトは変更されず、ガベージコレクションの対象になる可能性があります。

public class Main {
    public static void main(String[] args) {
        String s = "hi";
        String firstRef = s;
        s = s + "!";
        System.out.println("s: " + s);
        System.out.println("firstRef: " + firstRef);
    }
}

なぜ不変なのか

不変性には実際の利点があります。

  • スレッドセーフ:文字列をロックなしで共有できます
  • キャッシュ:ハッシュコードやプール内のエントリが有効なまま保たれます
  • 安全性:メソッドに渡した文字列が、意図せず変更されることはありません

文字列プール

同一の文字列リテラルは、文字列プール内の1つのオブジェクトを共有できます。文字列が決して変更されないからこそ、これが安全に行えます。ここでは、2つのリテラルが同じプール内のオブジェクトを参照しています。

public class Main {
    public static void main(String[] args) {
        String a = "java";
        String b = "java";
        System.out.println(a == b);
        System.out.println(a.equals(b));
    }
}

new String はプール共有を解除する

new String(...) を使用すると別のオブジェクトが強制的に作成されるため、内容が同じでも参照の等価性は異なります。内容の比較には必ず equals を使用してください。

public class Main {
    public static void main(String[] args) {
        String a = "java";
        String b = new String("java");
        System.out.println("== : " + (a == b));
        System.out.println("equals: " + a.equals(b));
    }
}

連結のコスト

文字列に対する各 + は、新しいオブジェクトを作成します。ループ内でこれを行うと、短時間しか使われない文字列が多数割り当てられるため、時間とメモリを無駄にします。

public class Main {
    public static void main(String[] args) {
        String result = "";
        for (int i = 1; i <= 5; i++) {
            result = result + i;
        }
        System.out.println(result);
    }
}

二次的な増加

連結するたびに、それまでのすべての文字がコピーされるため、ループ内で + を使って長い文字列を構築すると、規模が大きくなるにつれて効率が悪化します(およそ O(n²))。これが中心的なパフォーマンス上の問題です。

public class Main {
    public static void main(String[] args) {
        String s = "";
        for (int i = 0; i < 1000; i++) {
            s += "x";
        }
        System.out.println("Length: " + s.length());
    }
}

不変な値は予測しやすい

文字列をメソッドに渡しても安全です。メソッドが元の文字列を変更することはできません。ここではメソッドが新しい文字列を作成し、呼び出し元の値はそのまま保たれます。

public class Main {
    static void shout(String s) {
        s = s + "!!!";
        System.out.println("inside: " + s);
    }
    public static void main(String[] args) {
        String msg = "hello";
        shout(msg);
        System.out.println("outside: " + msg);
    }
}

解決策の紹介

文字列を効率的に構築する必要がある場合、Java にはStringBuilderという可変版のクラスが用意されています。毎回新しいオブジェクトを割り当てるのではなく、その場で内容を変更します。

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= 5; i++) {
            sb.append(i);
        }
        System.out.println(sb.toString());
    }
}

2つの方法を比較する

連結が数回だけなら、+ で十分読みやすく記述できます。ループ内で何度も連結する場合は、StringBuilder を使用してください。構築する量に応じて選択しましょう。

public class Main {
    public static void main(String[] args) {
        String simple = "a" + "b" + "c";
        StringBuilder sb = new StringBuilder("a");
        sb.append("b").append("c");
        System.out.println(simple);
        System.out.println(sb);
    }
}

確認問題

String に対して s.toUpperCase() を呼び出すと、実際には何が起こるでしょうか。

まとめ

文字列が不変である理由を学びました。

  • String の内容は決して変更されません
  • メソッドは新しい文字列を返します
  • 不変性によって、スレッドセーフ、プール共有、安全性が実現します
  • ループ内で + による連結を行うと、規模が大きくなるにつれて効率が悪化します
  • StringBuilder が可変な解決策です

よくある質問

「文字列が不変である理由」レッスンは無料ですか?

はい。「文字列が不変である理由」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「文字列が不変である理由」で何を学びますか?

文字列の不変性を理解します ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「文字列が不変である理由」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 文字列が不変である理由
  2. StringBuilderで文字列を構築する
  3. StringBuilderのメソッド
  4. StringBuilderとStringBuffer
← Java Academyに戻る