Effective Javaを読むチャレンジ-項目30その2-

項目30 int 定数の代わりに enum を使用する の続き

enumはコンパイル時の型安全性を提供している

int enumパターンでは定数名にグループを表す接頭辞を付けていましたが、実際はどれもただのint定数なので、どのグループの定数もint型のパラメータに渡すことができます。しかしenumでは異なるグループは異なる型とできるため、型安全になります。下記のようなことはできません。

同一名の定数を持つ異なるenum型は問題なく共存する

同じ名前を持つ異なるenum型は共存します。本書ではその理由として、各enum型は独自の名前空間を持つとあります。異なるenum型はクラスが異なることと同じなので、名前空間が異なるということですね。

その次に、enumはクライアントコードをコンパイルすることなく、enum型へ定数を追加したり、定数の順序を変更できるとあります。また、それがなぜかというと、定数を公開しているフィールドは、enum型とクライアントの間に隔離層を提供しているからとあります。このあたりはちょっと想像しづらいですね・・・。

定数を公開しているフィールドというのは、前回のタイプセーフenumパターンの例に出た「public static final FUJI = new Apple();」の部分ですね。クライアントはこのstatic finalのインスタンスを参照している訳ですが、値のインライン展開とは違い、この場合はコンパイルされるとインスタンスの参照という点は変わらない結果になります。つまり、クライアントの中に定数値がコンパイルされるわけではなく、実行時にインスタンスの参照を見に行くということです。

最後に、enum型のtoStringメソッドは、デフォルトで定数の名前を返します。つまり、enumを表示可能な文字列にできます。

このように、enum型はint enumパターンの欠点を修正します。

enumの機能

enumがint定数の代わりとして使えることが分かったところで、本書ではenumにはもっといろいろな機能があるんだよ、ということを示しています。

  1. enum型は任意のフィールドやメソッドを追加できる
  2. enum型は任意のインタフェースを実装できる
  3. enum型はObjectのすべてのメソッドについて高品質な実装を提供している
  4. enum型はComparableとSerializableを実装している

1番目は例えば、定数に対してデータや振る舞いを関連付けることができます。定数は名前と値が1対1で関連付けられていますが、名前と値の関連を1対多にすることができます。本書では惑星の名前と惑星の半径と質量といったデータを関連付け、振る舞いの関連付けとして惑星表面上での物体の重さを計算して取得するメソッドを追加したサンプルを載せています。他にも1週間の曜日に対してその漢字表記や英字表記やそれらの略語、DayOfWeekの番号などを関連付けるといった使い方もできそうです。

・・・と思ったら、Java 8のDate and Time APIにDayOfWeekという列挙型が既にあるようです。それまでは自作するなどしてましたが、今ではこんな風にして曜日の表記を簡単に出力できます。Java本体ではenum型はすごく大量ではありませんが、それなりの数使われています。

2番目はそのままの意味です、外部インタフェースを実装できるということは、異なる列挙型をまたがって同じ振る舞いを持たせるなど、もっと柔軟に振る舞いをもたせることができます。

3番目は、enumはクラスなので当然Objectを継承しています。実際にはenum型は暗黙的にjava.lang.Enumという抽象クラスを継承しています。その抽象クラスがObjectのメソッドを実装しています。

そのなかで、toStringメソッドはenum型のそれぞれの値の名前を返します。それが不十分である場合は、enum型でオーバーライドします。equalsメソッドは、参照の比較、すなわち==演算子による比較を行います。

4番目は、enum型のcompareToメソッドはenum定数の書かれた順番の比較を行います。次にenum型はシリアライズ可能ということですので、本書の惑星についてのサンプルを使ってenum型のシリアライズとデシリアライズを試してみます。

実行結果はこうなります。

ちゃんと追加したフィールドについてもデータがシリアライズされています。

脱線ばかりで今回どこまで読んだか分からなくなりました。おそらく惑星のサンプルを使ってenum定数にデータを関連付けることをやっているあたりですか・・・次回はその辺の内容を見ていきたいと思います。

広告
  • LINEで送る