見出し画像

【Javaお勉強日記】イミュータブル(変更不能)なオブジェクトを作る


変数は参照渡しなので、時々困ったことが起きる話

インスタンスはほぼほぼ変数に代入して使うけど、実は変数に入っているのはオブジェクトそのものの具体的な数値ではなくて、メモリ上のどこに数字が置いてあるかのアドレスだけ。

なので、

public class ExecMethod{
    public static void main(String[] args){
        // String nameとint numberというフィールド変数を持つOriginalクラスがあるとして
        Original instance1 = new Original("hoge",1)
        
        // instance1のnumberに数字を足したいなぁ(※)
        add(instance1, n)
        
        // 数字は足せたけど
        System.out.println(instance1.getNumber())
        
        // 名前も変わってる??
        System.out.println(instance1.getName())
    }
    
    public static void add(Original instance2, int n){
        // Originalオブジェクトのフィールド変数numberに受け取った値を足すメソッド
        int m = instance2.getNumber()
        instance2.setNumber(n + m)
        
        // のはずが、実は余計なことをしていたりして
        instance2.setName("huga")
    }
}

なんてやると、「あれっいつの間にかnameの値が変わってるんだけど?!」ってことになる。よくない。

(※本当はそもそも、こういう時はOriginalクラス側に数字を足すメソッドを作るべきなんだけど、参照渡しであることが解っていれば、100歩譲って、addの中で(instance1の中の)Number変数が書き換わってるのかな?までは予想ついても、「えっそこでName変えちゃってるの?!」みたいな実装されてた場合に気づくの大変だよね)

(VBAみたいに明示的に値渡しできたら良いのになーーー!と、思うけど、それやるとオブジェクトの実体がうぞうぞ増えてしまって激重になってしまうのだな……)

なので、「一度代入したら、もう値は変えられないようにしといた方がいいんじゃないの」っていうのが、「イミュータブルなクラス」。

イミュータブルなクラスを作るには

・setterを作らない
・フィールド変数に final修飾子 を付ける
・クラス自体にもfinal修飾子を付けて、継承による書き換えを防ぐ

// final修飾子の使い方

// ↓class自体にfinalを付ける
public final class Book{

    // フィールド変数にfinalを付ける
    private final String title;
    private final String author;
    
    ...略
    
    // setTitle,setAuthorは作らない

}

これで一度入った数値は変更できない、イミュータブルなクラスを作ることができる。

これで、いままでチラチラ見え隠れしていた謎のfinalの意味がわかりましたね!やったね!


この記事が気に入ったらサポートをしてみませんか?