1. はじめに
JavaのString型において、ある変数を別の変数に代入した後、元の変数の値を変更しても影響しないのはなぜでしょうか?
この記事では、Stringが不変オブジェクトとして設計されている理由と、代入時の挙動をわかりやすく解説します。
Sample.java
public class Sample {
public static void main(String[] args) {
String st1 = "Hello!";
String st2 = st1;
st1 = "Java";
System.out.println(st1); // Java
System.out.println(st2); // Hello! ← 参照型なのに影響されないのはなぜ?
}
}
2. 結論
冒頭でもさらっと記載しましたが、
JavaのStringは不変オブジェクト(Immutable Object)として設計されているため、ある変数を別の変数に代入した後に値を変更しても、他の変数に影響を与えることはありません。
ピンときませんね。
順を追って説明します。
3. 不変オブジェクトとは
不変オブジェクトには以下のような特性があります。
- 一度作成された文字列は変更できない。
- 新しい値が代入されると、新しいオブジェクトが作成され、既存のオブジェクトには影響がない。
3.1. 具体例で理解するStringの代入と参照
- 参照の挙動
Sample.java
public class Sample {
public static void main(String[] args) {
String st1 = "Hello!";
String st2 = st1; // -- ポイント1
st1 = "Java"; // -- ポイント2
System.out.println(st1); // Java
System.out.println(st2); // Hello!
}
}
- メモリ上の挙動
- ポイント1
初期状態:st1
とst2
は同じ文字列("Hello!")を参照している。 - ポイント2
st1 = "Java";
を実行した際に、新しい文字列オブジェクト("Java")が作成される。
- ポイント1
4. なぜStringは不変オブジェクトなのか?
- セキュリティの理由
- パスワードやURLなどの重要データを変更できないことで、安全性が向上。
- スレッドセーフの理由
- マルチスレッド環境で文字列が共有されても、状態を変更される心配がない。
- パフォーマンスの理由
- 文字列プールによるメモリ効率の向上。
5. Stringと他の可変オブジェクトの違い
- 可変オブジェクトの例
-
ArrayList
やStringBuilder
は可変(Mutable)オブジェクト。 - これらでは、値を変更することで同じ参照に影響を与える。
-
- 参照の挙動
SampleArrayList.java
public class SampleArrayList {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("Hello");
ArrayList<String> list2 = list1;
list1.add("World");
System.out.println(list1); // [Hello, World]
System.out.println(list2); // [Hello, World] ← list1を編集したがlist2にも影響あり
}
}
- 解説
-
list1
とlist2
は同じArrayList
オブジェクトを参照しています。 -
list1.add("World")
でリストに新しい要素を追加すると、list2
にもその変更が反映されます。
-
SampleStringBuilder.java
public class SampleStringBuilder {
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("Hello");
StringBuilder sb2 = sb1;
sb1.append(" World");
System.out.println(sb1); // "Hello World"
System.out.println(sb2); // "Hello World" ← sb1を編集したがsb2にも影響あり
}
}
- 解説
-
sb1
とsb2
は同じStringBuilder
オブジェクトを参照しています。 -
sb1.append()
で値を変更すると、sb2
にもその変更が反映されます。
-
6. まとめ
-
String
は不変オブジェクトであり、新しい値の代入は新しいオブジェクトを作成する。 - この特性により、安全で効率的な文字列操作が可能になる。
- 一方、
ArrayList
やStringBuilder
は可変なので、内容を直接変更することで同じオブジェクトに影響を与える。