2009/03/07

[Java] Eclipse でコンパイルできるのに Sun JDK だとコンパイルできない件

Java のジェネリックを使っていて、Eclipse ではコンパイルできるのに Sun の JDK ではコンパイルできない事象に遭遇した。

勝手な解釈としては、下のコードのメソッド bar において、Z 経由で Y から X への型推論が Sun JDK ではできないのだと思う。引数の型、戻り値を受ける変数の型はダイレクトなので解決してくれるが、この場合のように型パラメータ間の関係までは知らないよ、というとこなんだろうか。

仕方ないのでメソッド bar2 経由で明示的に型を指定してみたところ動くようになった。

package gen;

public class Foo {

public static interface ID<T1, T2> {
public T1 getValue(T2 arg);
}

public static interface IA<B> {
}

public static class A1 implements IA<B1> {
}

public static class B1 {
}

public static class E1 implements ID<A1, B1> {
public A1 getValue(B1 arg) {
return new A1();
};
}

public static class A2 implements IA<B2> {
}

public static class B2 {
}

public static class E2 implements ID<A2, B2> {
public A2 getValue(B2 arg) {
return new A2();
};
}

@SuppressWarnings("unchecked")
private <Z> Z getZ(Object y) {
if (y instanceof B1) {
return (Z) new E1();
}
if (y instanceof B2) {
return (Z) new E2();
}
return null;
}

public <X extends IA<Y>, Y, Z extends ID<X, Y>> X bar(Y y) {
Z z = this.<Z> getZ(y);
return z.getValue(y);
}

public <X extends IA<Y>, Y> X bar2(Y y) {
// ここで bar の Z を明示的に指定する。
return this.<X, Y, ID<X, Y>> bar(y);
}

public static void main(String[] args) {
Foo foo = new Foo();
// JDK ではコンパイルエラー。Z 経由で Y から X の型が推論できないらしい。
// 互換性のない型; 推定型引数 gen.Foo.A,java.lang.Object は
// 型変数 X,Z の境界に適合しません。
// A a = foo.bar(new B());

// bar2 経由でなら ok
A1 a1 = foo.bar2(new B1());
System.out.println(a1);

A2 a2 = foo.bar2(new B2());
System.out.println(a2);

// ちなみに次のように引数と戻り値のタイプ不整合は Eclipse でも JDK でもコンパイルエラーとなる。
// a1 = foo.bar2(new B2());
}
}

全部 Eclipse のコンパイラですませればいいのにさ。

2 件のコメント:

Indra さんのコメント...

導入、インドラメイン私パレンバン、インドネシア国から来た。
あなたと私は非常に満足している。
あなたのブログとても良いです。
私たちは友達になることを期待

Yoshinori Tahara さんのコメント...

こんにちはいんでらさん。
コメントありがとうございます。
今のインドネシアに住んでいるのですか?
私のブログのどんなところが気にいってくださったのでしょうか。