Javaのenumとswitchとコンパイル結果
目的
Oracleの配布しているJDKと、Eclipseで使われるJDKで、コンパイル後のファイル数が違うケースに気づいたのでメモ。
switch文でenumを使う時のコンパイル結果についてです。
本題
Javaのenumが、ただの定数ではなくて特殊なクラスとして扱われるのは有名なことかと思います。EffectiveJava(読みかけ 汗)にも書いてありました。
クラスなので、コンパイルすればenum定義は一つの.classファイルになります。クラス内で定義したら、staticな内部クラスとして、やっぱり別の.classになります。
ところで、そんなenumの利点として、switch文の条件にできるという点があります。
では、このようなコードはコンパイルするとどういったファイル名になるでしょうか?
Person.java
public class Person { public void work(Day day) { switch (day) { case SAT: System.out.println("寝て過ごす"); break; case SUN: System.out.println("遊びに出かける"); break; default: System.out.println("働く"); break; } } }
Day.java
public enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
Eclipseのコンパイル結果は予想通り
自分は、当然Person.classとDay.classの2つになると思ってました。
そして、Eclipseを使うとその通りになります。(バージョンは4.2と4.5で確認)
Oracle JDKでは違った
でも、OracleのJDK(1.7)のjavacを使ったら、
* Day.class
* Person.class
* Person$1.class
の3つになりました。なぜだ(・д・)
javap Person$1.class とすると、
Compiled from "Person.java" class Person$1 { static final int[] $SwitchMap$Day; static {}; }
だそうな???
検索すると次のような記事に当たります
enum 定数の switch 文の実装 - happynowの日記
Java列挙型メモ(Hishidama's Java enum Memo)
enumの値が変わったり増減したりしても、enumを使う側はコンパイルし直さなくても済むというのがenumの特徴です。そういった挙動を既存の文法だけで再表現するための実装として、Oracleのjavacでは内部的に勝手にクラスを作っていたんですね。そしてEclipseのコンパイラでは別の実装になっていると。
感想
Javaではクラスごとに.classファイルが作られることになっています。
しかも無名のクラスは$1のような通し番号のついたクラスになったりします。
実装依存なのだとしても、コンパイル後のファイル数まで違ってしまうのはなんとも気持ち悪いというか。
たとえば1つの.javaファイルから100個の.classが作られることも許されているのかなみたいな。
コンパイル後のことなんて気にするなと言われれば、まぁそうなんですが...('_')ナンダカナー
全然別の話題ですが
またオーボエはじめました。