エキサイト株式会社の中尾です。
effective java を最近読んでいて、気になった部分を自分でコーディングして理解を深めようと思っています。 その一部を紹介します。
public class Main { public static void main(String[] args) { System.out.println("元のクラス"); Counter counter = new Counter(100); System.out.println("変更可能なクラス"); MutableCounter mutableCounter = new MutableCounter(counter); System.out.println("初期値 : " + mutableCounter.getCounter().get()); counter.set(10); System.out.println("10で更新される : " + mutableCounter.getCounter().get()); System.out.println("理由はcounterとmutableCounterが等しいため"); System.out.println(counter.hashCode() + " = " + mutableCounter.getCounter().hashCode()); System.out.println("trueになる : " + counter.equals(mutableCounter.getCounter())); System.out.println(); System.out.println("不完全な不変クラス"); counter = new Counter(100); BlockCounter blockCounter = new BlockCounter(counter); counter.set(10); System.out.println("10で更新されない : " + blockCounter.getCounter().get()); System.out.println("理由はcounterとblockCounterが等しくないため"); System.out.println(counter.hashCode() + " = " + blockCounter.getCounter().hashCode()); System.out.println("falseになる : " + counter.equals(blockCounter.getCounter())); blockCounter.getCounter().set(20); System.out.println("blockCounter.getCounter() から counterを参照できるため、更新することができる : " + blockCounter.getCounter().get()); System.out.println("当たり前だけど一致する"); System.out.println(blockCounter.getCounter().hashCode() + " = " + blockCounter.getCounter().hashCode()); System.out.println("trueになる : " + blockCounter.getCounter().equals(blockCounter.getCounter())); System.out.println(); System.out.println("完全な不変クラス"); counter = new Counter(100); ImmutableCounter immutableCounter = new ImmutableCounter(counter); System.out.println(immutableCounter.getCounter().get()); counter.set(10); System.out.println("10で更新できない : " + immutableCounter.getCounter().get()); immutableCounter.getCounter().set(20); System.out.println("20で更新できない : " + immutableCounter.getCounter().get()); System.out.println("immutableCounter.get()するたびに新しいオブジェクトが作成されるため、ハッシュコードが毎回変わる"); System.out.println(immutableCounter.getCounter().hashCode() + " != " + immutableCounter.getCounter().hashCode() + " != " + immutableCounter.getCounter().hashCode()); } }
setterとgetterのみを持つクラスです。 数値を設定できます。
public class Counter { private int count; public Counter(int count){ this.count = count; } public int get(){ return this.count; } public void set(int i){ this.count = i; } }
上記のカウンタークラスを使うMutableCounterクラスです。 変更可能なクラスです。
public class MutableCounter { private final Counter counter; public MutableCounter(Counter sampleCounter){ this.counter = sampleCounter; } public Counter getCounter(){ return this.counter; } }
上記のカウンタークラスを使うBlockCounterクラスです。 少しだけ防御力があがっています。
public class BlockCounter { private final Counter counter; public BlockCounter(Counter sampleCounter){ this.counter = new Counter(sampleCounter.get()); } public Counter getCounter(){ return this.counter; } }
上記のカウンタークラスを使う ImmutableCounterクラスです。 完全に防御されているクラスです。
public class ImmutableCounter { private final Counter counter; public ImmutableCounter(Counter sampleCounter){ this.counter = new Counter(sampleCounter.get()); } public Counter getCounter(){ return new Counter(this.counter.get()); } }
実行結果です。
元のクラス 変更可能なクラス 初期値 : 100 10で更新される : 10 理由はcounterとmutableCounterが等しいため 951007336 = 951007336 trueになる : true 不完全な不変クラス 10で更新されない : 100 理由はcounterとblockCounterが等しくないため 834600351 = 471910020 falseになる : false blockCounter.getCounter() から counterを参照できるため、更新することができる : 20 当たり前だけど一致する 471910020 = 471910020 trueになる : true 完全な不変クラス 100 10で更新できない : 100 20で更新できない : 100 immutableCounter.get()するたびに新しいオブジェクトが作成されるため、ハッシュコードが毎回変わる 1418481495 != 303563356 != 135721597
effective javaに書いている通り、不変クラスが作ることができました。 不変クラスを作れるとかっこいいですね!!! かっこいいけど、柔軟性も欲しい気がするのが私の気持ちです。