Generic再考 その2


この前に書いたGenericを使ったコードでは、分からない点がつあります。
 public class Variant {
     public Variant() {
         Foo<? super MiddleType> foo1_1 = new  SubFoo<MiddleType>();
         Foo<? super MiddleType> foo1_2 = new  SubFoo<SuperType>();
         Foo<? extends MiddleType> foo2_1 = new SubFoo<MiddleType>();
         Foo<? extends MiddleType> foo2_2 = new SubFoo<SubType>();

         foo1_1.bar(new MiddleType());
         foo1_1.bar(new SuperType());  // <- Compile Error
         foo1_2.bar(new MiddleType());
         foo1_2.bar(new SuperType());  // <- Compile Error

         foo2_1.bar(new MiddleType()); // <- Compile Error
         foo2_1.bar(new SubType());    // <- Compile Error
         foo2_2.bar(new MiddleType()); // <- Compile Error
         foo2_2.bar(new SubType());    // <- Compile Error
     }
 }

 class Foo<T> {
      void bar(T m) {
         System.out.println("Foo is called");
     }
 }
 class SubFoo<T> extends Foo<T> {
     @Override
      void bar(T m) {
         System.out.println("SubFoo is called");
     }
 }
 class MiddleType extends SuperType {
 }
 class SuperType {
 }
 class SubType extends MiddleType {
 }

上記のようなコードだと、コメントで示したようにbarメソッドを呼び出すほとんどの所でコンパイルエラーになります。
bar(capture#81 of ? extends MiddleType) in Foo<capture#81 of ? extends MiddleType> cannot be applied to (MiddleType)
この辺りはwildcard captureと言うキーワードがからんでいるようです。
barメソッドをgenericメソッドにすると、コンパイルエラーは解消されます。
<T> void bar(T m)
クラスファイルを逆コンパイルしても、genericメソッドの導入前後で変わりがないんですよね。
型推論ってどういうメカニズムなんだろう。。。。

分からない点は以下の2点。
  • 最初の段階のbarメソッド呼び出しでコンパイルエラーが出るものと出ないものがあった。
  • gnericメソッドを導入した時点で何が起きているのか。
IBMの記事をじっくり読めば分かるのかもしれないけども、今のところピンとこないんですよね。

コンパイラの気持ちになって、じっくり考えて見ます。

Comment