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); // HELLOStringプール(インターニング)
文字列リテラルは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"); // printsintern(): 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 stringsString連結の動作
+による連結では、新しい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); // abcdStringを正しく比較する
必ず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")); // 42Stringは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.5null安全な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フィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- String の不変性と String Pool
- 効率的な連結のための StringBuilder
- テキストブロックと String.format
- Pattern と Matcher による正規表現