きどたかのブログ

いつか誰かがこのブログからトラブルを解決しますように。

コンパイラが怪しい

プロジェクト参照では動き、
Jar参照だとClassCastException。


インスタンス変数にList
そこにセッターインジェクション。
public void setList(List list)


インジェクションはされてるのだが、
リストの中身はHogeではない。
これ自体は今回問題にしてない。
ダメなことした場合の話だから。


そのリストが設定された状態で、
拡張for文を使う箇所がある。
for(Object obj : list)


Jar参照では、ここでHogeについてのcheckcastが走り例外になる。
厳密に言うと、イテレータのnext()の後に。
しかしプロジェクト参照では例外にならない。
そう、そこの差異がおかしい。


別の例を示す。


List a = new ArrayList();
a.add("");
List b = eraze(a);
System.out.print(b.get(0));



public List eraze(List a){
return (List)a;
}


Jar参照ではまだ試してないが、
プロジェクト参照では表示できた。
printメソッドの引数Objectを考慮してるように見える。
まあ、拡張for文で試さないと意味がない可能性もあるな。


個人的にはcheckcastしてくれて構わないと思ってる。ただ、Jarになってから厳しくチェックされても困る。


さて、とりあえず、クラスビューワーで見て、checkcastの違いがクラスファイル間で認められたのは事実。
では、各々のクラスファイルが、それぞれどのような状況で作られていたのかが調べるべきことの一つ。
また、言語仕様というか、コンパイラ仕様というか、いわゆる「正解」はどちらであるのかも調べるべきこと。
あと、回避する方法はすでにある。Raw型にしてからループさせれば良い。
IBMに問い合わせるために、簡単に再現するコードを用意しておくのも良い。



あまり詳しくないが、JavaBuilderとかいうのも頭の片隅に入れておく。


あと、Rational Application Developerと、WebSphere Application Server に付属のjavac.exeのバージョンとか。
また、Sun Javaでやるとどうなるか等。


だいたい必要そうな情報の目星は付いてきたけど、あまり関わりたい内容じゃない。


== 追記 ==
自宅で試したが、どうやらSun Javaでも同様のことが起こる。
自宅はeclipse 3.5 つまりはガリレオ。
eclipse上で動かすと動いてしまう。
eclipseから単純なexportでjar化して使っても動いてしまう。
しかし、jdk1.6.0_17のjavac.exeを用いたコンパイルを施して動かすとClassCastExceptionが発生する。
IBM Javaでも起きたし、Sun Javaで起きたとなると、
つまりは、org.eclipse.jdt.core.javabuilderを疑う方向性だと思う。


JLS Third Editionの[14.14.2 The enhanced for statement]を部分的に引用します。


EnhancedForStatement:
for ( VariableModifiersopt Type Identifier: Expression) Statement

for (I #i = Expression.iterator(); #i.hasNext(); ) {

VariableModifiersopt Type Identifier = #i.next();
Statement
}

の2つが引用。


これを見ると、逆によく分からなくなった。
今回のケースでは、VariableModifiersoptはObjectが入る。
ふむ、Sun JavaIBM Javaは、#i.next()の後に必ずcheckcastをするのだろう。
Iteratorの「E next()」のEを厳密にチェックするのだと思う。