JDTコンパイラならOKだけど、純正コンパイラじゃ通らない記述
久々にはまった。。。
以前にも書きましたが、JDTコンパイラとSunの純正コンパイラはいろいろ微妙に振る舞いが違ってます。
01:public class Sample { 02: public static void main(String[] args) { 03: List list = new ArrayList(); 04: list.add(1L); 05: list.add(2L); 06: List<Object[]> list2 = list; 07: for(Object o : list2) { 08: System.out.println(o); 09: } 10: } 11:}
前回判明したケースは、コンパイル時点で発覚したのですが、
上記コードは、JDTコンパイラでは正しく動作するのですが、Sunの純正コンパイラでは、
ClassCastExceptionが発生してしまいます。
開発環境では普通に動くので見つけるのに苦労しました。
悪いのは6行目の型が一致しない型総称参照への代入ですね。
「そんなのするなよ」と言われればその通りなんですが、
やっちゃったものは仕方なし^^;
で、なんで振る舞いが異なるかっていうと、jadでリバースをかければ一目瞭然。
JDTコンパイラのclassファイルからリバース
01: public static void main(String args[]) 02: { 03: List list = new ArrayList(); 04: list.add(Long.valueOf(1L)); 05: list.add(Long.valueOf(2L)); 06: List list2 = list; 07: Object o; 08: for(Iterator iterator = list2.iterator(); iterator.hasNext(); System.out.println(o)) 09: o = iterator.next(); 10: }
Sun純正コンパイラのclassファイルからリバース
01: public static void main(String args) 02: { 03: ArrayList arraylist = new ArrayList(); 04: arraylist.add(Long.valueOf(1L)); 05: arraylist.add(Long.valueOf(2L)); 06: ArrayList arraylist1 = arraylist; 07: Object aobj; 08: for(Iterator iterator = arraylist1.iterator(); iterator.hasNext(); System.out.println(((Object) (aobj)))) 09: aobj = (Object[])iterator.next(); 10: }
拡張forループの一時参照の型が違うから見たいですね。
つまり、、、
というコンセプトで拡張forループは展開するようです。
う〜ん、コンパイラの実装としてはJDTコンパイラの方がいい気がするんだけどね。
ちなみに、jadの結果を見ると、メソッド内の一時参照変数は具象クラスが明確な場合には、
あえて、具象クラスの型で受けるようですね。
このあたりもどうだろうという気がせんことはないのですが、こっちの方が早く動作するんでしょうね。
JDTコンパイラはとにかく高速にコンパイルする必要が有るので、あまり最適化はしないってこことでFAですかね?
ちなみに、前回(と言ってもはるか昔)書いた日記は、
完全なガセでした。
普通に動いてくれちゃってます。
う〜ん、徹夜作業中だったから見間違えたのかしら。。。