0Pricing
Java Academy · レッスン

String の不変性と String Pool

String が不変である理由、String Pool の仕組み、== と equals の使い分けを理解します。

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

Stringの不変性とStringプール

JavaのStringは不変です。不変性、Stringプール、参照の等価性と値の等価性を理解すると、見つけにくいバグを防げます。

Stringが不変である理由

Stringオブジェクトは生成後に変更できません。Stringを「変更」する操作は、実際には新しいStringオブジェクトを生成します。これにより、共有、スレッドセーフ性、hashCodeのキャッシュが可能になります。

String s = "hello";
s.toUpperCase(); // creates a new String, does NOT modify s
System.out.println(s); // still "hello"

String upper = s.toUpperCase(); // must capture the result
System.out.println(upper); // HELLO

Stringプール(インターニング)

文字列リテラルはStringプール(ヒープ内の特別な領域)に格納されます。内容が同じ2つのリテラルは、同じオブジェクトを共有します。

String a = "hello"; // goes into pool
String b = "hello"; // same object from pool
String c = new String("hello"); // forces new object outside pool

System.out.println(a == b);       // true  (same pool reference)
System.out.println(a == c);       // false (different objects)
System.out.println(a.equals(c));  // true  (same content)

==とequals()の違い

Stringの内容を比較する場合は、必ず.equals()を使用してください。==演算子は、2つの変数が同じオブジェクトを指しているかどうか(参照の等価性)を確認します。

String input = new String("admin"); // from user input, not pooled
String role  = "admin";

// Dangerous: fails because different objects
if (input == role) System.out.println("Same"); // not printed!

// Correct: compares content
if (input.equals(role)) System.out.println("Equal!"); // prints

// Null-safe: put constant first to avoid NPE
if ("admin".equals(input)) System.out.println("Admin"); // prints

intern(): Stringを手動でプールに格納

String.intern()はStringを強制的にプールに格納し、プール内の参照を返します。現代のJavaでは、ほとんど必要ありません。

String s1 = new String("interned");
String s2 = s1.intern();
String s3 = "interned"; // already in pool

System.out.println(s2 == s3); // true (both point to pool)
System.out.println(s1 == s3); // false (s1 is off-pool)

// Modern use: prefer String.intern() only when you need
// identity-based caching with thousands of repeated strings

String連結の動作

+による連結では、新しいStringオブジェクトが生成されます。ループ内では、これはO(n²)になります。コンパイラーは単一の式を最適化しますが、ループによる連結は最適化しません。

// Compiler optimizes this to a StringBuilder automatically:
String result = "Hello, " + "World" + "!";

// In loops: compiler does NOT optimize — use StringBuilder explicitly!
List<String> words = List.of("a", "b", "c", "d");
String bad = ""; // O(n^2) — new object each iteration
for (String w : words) bad += w;

StringBuilder sb = new StringBuilder();
for (String w : words) sb.append(w); // O(n) — efficient
String good = sb.toString();
System.out.println(good); // abcd

Stringを正しく比較する

必ずequals()を使用してください。大文字と小文字を区別しない比較にはequalsIgnoreCase()を使用します。辞書順の比較にはcompareTo()を使用します。

String a = "Java";
String b = "java";

System.out.println(a.equals(b));             // false
System.out.println(a.equalsIgnoreCase(b));   // true
System.out.println(a.compareToIgnoreCase(b)); // 0 (equal)
System.out.println(a.compareTo(b));           // negative (J < j in Unicode)

Stringのハッシュコードキャッシュ

Stringは不変であるため、Javaは最初の呼び出し後にhashCodeをキャッシュします。以降の呼び出しではキャッシュされた値が返されるため、StringはHashMapのキーとして非常に効率的です。

String key = "product:12345";
// hashCode computed once and cached:
int h1 = key.hashCode();
int h2 = key.hashCode(); // returns cached value
System.out.println(h1 == h2); // true

// Strings are ideal HashMap keys because:
// 1. hashCode is consistent (immutable content)
// 2. hashCode is cached (fast repeated lookups)
// 3. equals is well-defined (content-based)
Map<String, Integer> map = new HashMap<>();
map.put("key", 42);
System.out.println(map.get("key")); // 42

Stringはfinal

Stringクラスはfinalであり、サブクラス化できません。これにより、サブクラスが不変性やhashCodeの一貫性を壊すことがないと保証されます。

// String is final — this will not compile:
// class MutableString extends String {} // compile error

// You cannot override String behavior.
// If you need custom string-like behavior, use a wrapper:
record ProductSku(String value) {
    ProductSku { if (!value.matches("[A-Z]{3}-[0-9]{4}")) throw new IllegalArgumentException(); }
    @Override public String toString() { return value; }
}

String.formatと連結

複数の要素からなる文字列では、明確でローカライズしやすいString.format()またはテキストブロックを、連結よりも優先してください。

String name = "Alice";
int age = 30;
double score = 97.5;

// Concatenation — harder to read with many parts
String bad = "User: " + name + ", Age: " + age + ", Score: " + score;

// String.format — clear placeholders
String good = String.format("User: %s, Age: %d, Score: %.1f", name, age, score);

System.out.println(good);
// User: Alice, Age: 30, Score: 97.5

null安全なString操作

多くのString操作は、文字列がnullの場合にNPEをスローします。nullを安全に処理するには、防御的なパターンやString.valueOf()を使用してください。

String value = null;

// Null-safe length check
int len = (value != null) ? value.length() : 0;
System.out.println(len); // 0

// Null-safe comparison (put constant first)
boolean isAdmin = "admin".equals(value); // false, no NPE

// String.valueOf converts null to "null" string
System.out.println(String.valueOf(value)); // "null"
System.out.println(Objects.toString(value, "default")); // "default"

確認問題

次のコードは何を出力しますか。

String a = "hello";
String b = new String("hello");
System.out.println(a.equals(b));
System.out.println(a == b);

まとめ:Stringの不変性とStringプール

要点:

  • Stringは不変であり、操作は新しいStringオブジェクトを返し、元のオブジェクトを変更しません
  • Stringリテラルはプールに格納され、内容が同じ2つのリテラルは1つのオブジェクトを共有します
  • Stringの内容を比較する場合は必ず.equals()を使用し、==はオブジェクト参照を比較します
  • 大文字と小文字を区別しない比較にはequalsIgnoreCase()を使用します
  • ループ内でのString連結はO(n²)になるため、効率化にはStringBuilderを使用します
  • StringはhashCodeをキャッシュするため、HashMapのキーとして効率的かつ安全に使用できます

よくある質問

「String の不変性と String Pool」レッスンは無料ですか?

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

「String の不変性と String Pool」で何を学びますか?

String が不変である理由、String Pool の仕組み、== と equals の使い分けを理解します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「String の不変性と String Pool」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

  1. String の不変性と String Pool
  2. 効率的な連結のための StringBuilder
  3. テキストブロックと String.format
  4. Pattern と Matcher による正規表現
← Java Academyに戻る