ProgrammingJava開発者

Javaにおける不変オブジェクトとは何か、それらの価値は何か、そして独自の不変クラスを正しく実装する方法は何か?

Hintsage AIアシスタントで面接を突破

回答。

不変オブジェクトとは、作成後に状態を変更できないオブジェクトです。主な特性は以下の通りです:

  • すべてのフィールドはfinalである;
  • セッターを含まない;
  • 内部オブジェクト(例えば、コレクション)への変更可能な参照を持たない。

不変オブジェクトの利点:

  • マルチスレッドアクセスに安全(スレッドセーフ)である;
  • キャッシュしやすく、コレクションのキーとして再利用しやすい;
  • デバッグとテストが簡単である;
  • 状態の予期しない変更によるバグが少ない。

不変クラスの実装例:

public final class Person { private final String name; private final int age; private final List<String> phones; public Person(String name, int age, List<String> phones) { this.name = name; this.age = age; // 渡されたリストの変異からの保護 this.phones = Collections.unmodifiableList(new ArrayList<>(phones)); } public String getName() { return name; } public int getAge() { return age; } public List<String> getPhones() { return phones; } // 読み取り専用リストを返す }

裏のある質問。

なぜJavaのStringは不変であるのか、もしそうでなかったらどうなるか?多くの人は「安全のため」と答えますが、それは実際にはどういう意味でしょうか?

回答:

Stringは多くの場所で使用されます:コレクションのキーとして、安全性のロジック(例えば、パスワード)で。もし1つの参照を通じて文字列を変更できた場合、それは同じオブジェクトへの他のすべての参照に影響を与え、コレクションが正しく機能することが不可能になります(例えば、HashMap — hashCodeの計算時に)し、セキュリティ上の脆弱性を引き起こす可能性があります。

テーマの詳細を知らなかったための実際のエラーの例。


物語

大規模な銀行プロジェクトで、内部コレクション(トランザクションのリスト)が通常のゲッターを通じて渡されました。その結果、リストは外部から変更可能であり、不変条件が破られ(例えば、不適切な日付でのトランザクションの追加)、データが失われてしまいました。Collections.unmodifiableListを返却するようになるまで問題が続きました。

物語

設定のルートクラスに保護されていないフィールドオブジェクト(DateList)が保存されていました。1つのスレッドで設定が変更され、別のスレッドで古いまたは一貫性のないデータを取得したため、ビジネスアルゴリズムが正しく作動しませんでした。

物語

ログインシステムでパスワードが可変オブジェクトに保存されていました。安全でないアクセスにより別のユーザーのパスワードが突然「漏洩」することになりました。同じオブジェクトのインスタンスが複数のスレッドで使用されていたためです。