Javaでは常に_値渡し_メカニズムが使用されますが、オブジェクトには特別な特徴があります:
そのため、メソッド内でオブジェクトのフィールドを変更すると、元のオブジェクトに反映されますが、メソッド内で新しい参照を変数に代入しようとすると、元のオブジェクトには影響を与えません。これを値渡しと参照渡しと混同することがよくありますが、Javaは参照渡しをサポートしていません!
例:
void changePrimitive(int a) { a = 10; } void changeObject(Point p) { p.x = 10; } int num = 5; changePrimitive(num); // numはまだ5 Point pt = new Point(1, 2); changeObject(pt); // 今やpt.x == 10
重要! メソッド内でp = new Point(100, 200)と代入すると、メソッドの外の元のオブジェクトは変わりません。フィールドが変わるのですが、参照自体は変わりません!
質問: メソッドから引数として渡されたオブジェクトを変更し、メソッドの外で参照変数が新しいオブジェクトを指すようにすることはできますか?
答え: いいえ、できません。メソッド内で引数に新しい参照を代入すると、それは参照のコピーだけに影響し、メソッドを出ると消えてしまいます。メソッドの外で引数の変数は以前のオブジェクトを指し続けます。
void reassign(Point p) { p = new Point(100, 200); // ローカルだけ! } Point pt = new Point(5, 5); reassign(pt); // ptはまだ(5, 5)
事例
大規模な金融システムでは、メソッド内で参照を変更することによってオブジェクトの変更を“返す”APIが実装されました。その結果、メソッドを出た後に変更が反映されませんでした。ミューテーションと新しいオブジェクトの返却を明確に区別するために、ロジックの一部を完全に再設計する必要がありました。
事例
Javaで2つのオブジェクトを入れ替えるスワップメソッド
swap(A a, B b)を実装しようとした開発者が参照を渡して、メソッド内で入れ替えました。これは機能しませんでした。結果を返すか、コンテナ配列を使用する必要があります。値渡しを知らなかったために、オブジェクトの交換が正しく行われませんでした。
事例
プロジェクトの参加者の一人がC++からロジックを移行し、値渡しの動作を期待しました。その結果、メソッドが正しく動作しなくなり、メソッド内での変更が外に出なくなりました。重要なコードの部分を緊急に書き直す必要があり、かなりの時間がかかりました。