Genericsの罠 再び
Javaでこんなコードを書いたら、例によってjavacに文句を言われました。
static final Tuple<String, FieldType>[] TYPE_MAP = { new Tuple<String, FieldType>("int", FieldType.INT), };
そんな型は作れない、と仰りやがります。
10秒ほど考えて、
static final Tuple[] TYPE_MAP = { new Tuple<String, FieldType>("int", FieldType.INT), };
としたら通りました。
Genericsの仕様と、言語組み込みの総称型である配列が衝突を起こしています。
Java Genericsの総称型はコンパイル時にのみ解釈され、バイトコードには総称型であったという痕跡すら残りません。
仕様的に残さないことになっているため、実行時に総称型オブジェクトの型パラメータを知る方法はありません。
一方、Javaの配列型は本物の(実行時にも型が残る)総称型です。
Tuple<String, FieldType>[]の型パラメータであるTuple<String, FieldType>も、実行時に残らなければなりませんが、Genericsの仕様からそれはできません。
というわけで、コンパイラはこれを文法違反と見なして文句を言っています。
Genericsの仕様を決めるとき、配列とGenericsの意味論上の互換性も議論されていたはずです。
しかし、文法上の互換性よりバイトコードの互換性を重視したせいで、このような奇妙なことが起きるようになってしまったのだと思われます(注1)。
互換性を理由に言語使用を歪める(注2)なんて、Javaも成長したものですね(注3)
注1.
言語仕様の一貫性よりもバイトコードの互換性を優先したのは、広く使われる言語の設計として妥当な判断だと思います。
ライブラリやフレームワークをコンパイルしたjavacのバージョンを気にしなければならない事態は、DLL HELL並の悪夢を引き起こしたはずです。
注2.
型パラメータをclassファイルに残して、もっと自然な形で総称型を実現できたはずです。
しかし、そのためにはバイトコードの仕様を変更しなければなりません。
そうなるとJDK1.5で作ったバイナリをJDK1.4以下の環境で使えなくなってしまいます。
これを避けるために、実行時の情報から型パラメータを消しているようです(他にも細々した理由はあるみたいですが)。
注3.
老化の兆しかも知れない。
Dog yearの時代に生まれた言語だけに、寿命も犬並みとか。
- Category(s)
- 雑談
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/anaka/generics306e7f60-518d/tbping
- Genericsの罠
- ¦
- Main
- ¦
- へびら
[java] Genericsの実行時型情報