C#3.0でジェネリックスを使用していた人がJava6でジェネリックスを使用すると...(4)

こんにちは。受託開発担当(ここでは雑記担当)のMasaです。

前回C# で検証したので、今回は Java で検証します。
最終回です。


前々回作成した MyObject1 MyObject2 クラスにプロパティとデバッグ用メソッドを追加します。

public class MyObject1 extends MyObject {

  private String company;

  public String getCompany() {
    return company;
  }

  public MyObject1() { }

  public MyObject1(String name, String company) {
    super(name);
    this.company = company;
  }

  public String toString() {
    return "名前は、" + this.getName() + "です。企業は、" + this.getCompany() + "です。";
  }
}

public class MyObject2 extends MyObject {

  private String value;

  public String getValue() {
    return value;
  }

  public MyObject2() { }

  public MyObject2(String name, String value) {
    super(name);
    this.value = value;
  }

  public String toString() {
    return "名前は、" + this.getName() + "です。値は、" + this.getValue() + "です。";
  }
}

次はジェネリックなクラスです。C# と同様にイベントリスナー風の何かを作成します。

public interface MyObjectContainer<T extends MyObject> {
    T getInstance();
}

上記インタフェースを実装したクラスを追加します。C# と同様に Test クラスにプライベートクラスを追加しちゃいます。

private class MyObject1Container implements MyObjectContainer<MyObject1> {
  @Override
  public MyObject1 getInstance() {
    return new MyObject1("Java", "Sun");
  }
}

private class MyObject2Container implements MyObjectContainer<MyObject2> {
  @Override
  public MyObject2 getInstance() {
    return new MyObject2("Java", "6");
  }
}

MyObjectContainer クラスを格納するリストを追加します。C# と同様にクラスを分けます。
予想通りビルドエラーです。

]
public class MyObjectTest {

  private List myObjectContainerList;

  public <T extends MyObject> void AddMyObjectContainer(MyObjectContainer<T> container)
  {
    if (myObjectContainerList == null)
      myObjectContainerList = new ArrayList();
    myObjectContainerList.add(container);
  }

  public <T extends MyObjectContainer<E>, E extends MyObject> void execute()
  {
    for (Object container : myObjectContainerList) {
      if (container instanceof MyObjectContainer<E>) {  // ← エラー
        System.out.println(((MyObjectContainer<E>) container).getInstance().toString());
      }
    }
  }
}

しょうがないので引数で型を渡します。

  //public <T extends MyObjectContainer<E>, E extends MyObject> void execute()
  public <T extends MyObjectContainer<E>, E extends MyObject> void execute(Class<T> t)
  {
    for (Object container : myObjectContainerList) {
      //if (container instanceof MyObjectContainer<E>) {
      if (t.isInstance(container)) {
        System.out.println(((MyObjectContainer<E>) container).getInstance().toString());
      }
    }
  }

準備が整ったので、Test クラスにテストメソッドを追加し、実行します。

static void Main(string[] args)
{
    Test test = new Test();

    MyObjectTest myObjectTest = new MyObjectTest();

    myObjectTest.AddMyObjectContainer(test.new MyObject1Container());
    myObjectTest.AddMyObjectContainer(test.new MyObject2Container());

    System.out.println("Execute(MyObject2Container<MyObject1>)が呼ばれるはずです。");
    myObjectTest.execute(MyObject1Container.class);
    System.out.println("Execute(MyObject2Container<MyObject2>)が呼ばれるはずです。");
    myObjectTest.execute(MyObject2Container.class);
}

Javaコンソール2

実行できました。。。予想通りの展開になりました。