Generics - 複数のインタフェースを実装していることを示す

Generics では型パラメータに extends を使用することで、指定可能な型に制約を課すことが出来ます。
例えば以下の例だと、Sample#invokeFoo メソッドで宣言されている型パラメータ T には、 IFoo インタフェースを実装したクラスのみを指定できます。

// IFoo インタフェース
public interface IFoo {
  public void foo();
}
// Generics により、キャストの必要なくメソッドを呼び出せる例
public class Sample {
  public <T extends IFoo> void invokeFoo(T t) {
    t.foo(); // IFoo のメソッドを使用可能
  }
}

<T extends IFoo> の記述により、 T の 型が少なくとも IFoo であることが保証されます。
このため、メソッド引数の t に対して明示的なキャストを行なうことなく、IFoo のメソッドを呼び出すことが可能です。

Generics を使用しなくてもメソッド引数 t の型を IFoo として宣言すれば、上記と同様のことは実現できます。

// 引数の型を IFoo にすることで、Generics を使用せずともキャストが要らない例
public class Sample {
  public void invokeFoo(IFoo t) {
    t.foo(); // Generics でなくとも可能
  }
}

しかし、Generics を使用しない場合は一つの型しか、引数の型として指定できません。このため、引数のオブジェクトが IFoo 以外に IBar インタフェースも実装していて、その両方のメソッドを呼び出す場合に、明示的なキャストが必要になります。

// IBar インタフェース
public interface IBar {
  public void bar();
}
// IFoo と IBar 両方の型であることを引数型では宣言できない
public class Sample {
  public void invokeFooBar(IFoo t) {
    t.foo();
    t.bar(); // コンパイルエラー
    ((IBar)t).bar(); // 明示的なキャストが必要
  }
}

上記例では、引数に渡された型が確かに IBar を実装していることを、コンパイル時に保証できません。そのため、実行時にキャストが必要になり、ClassCastException の発生する可能性があります。
キャストを行なわないようにするには、IFoo および IBar の両方を継承したインタフェース IFooBar を作成し、引数の型を IFooBar とするか、引数を二つに分ける必要があります。

// IFooBar インタフェースを作成して引数の型とする
public interface IFooBar extends IFoo, IBar {
}

public class Sample {
  public void invokeFooBar(IFooBar fooBar) {
    fooBar.foo();
    fooBar.bar();
  }
}

// あるいは引数を二つに分ける
public class Sample {
  public void invokeFooBar(IFoo ifoo, IBar ibar) {
    ifoo.foo();
    ibar.bar();
  }
}
// しかし引数を二つに分けると・・・
public void useSampleClass() {
  FooBarImpl fooBarImpl = new FooBarImpl();// FooBarImpl は IFoo と IBar が実装されている
  (new Sample()).invokeFooBar(fooBarImpl, fooBarImpl);// 同じオブジェクトを2回引数に渡す必要がある;
}

Generics を使用すると、このような問題をスマートに解決可能です。Generics では <T extends IFoo & IBar> のように & を使用することで、型パラメータが複数の型を実装していることを宣言できます。このため、明示的なキャストを行なうことなく、IFoo および IBar のメソッドを呼び出すことが可能です。

// Generics を使用すれば、IFoo と IBar 両方の型であることを宣言できる
public class Sample {
  public <T extends IFoo & IBar> void invokeFooBar(T t) {
    // t は IFoo および IBar であることが保証されている
    t.foo(); // IFoo のメソッドを呼び出せる
    t.bar(); // IBar のメソッドもそのまま呼び出せる
  }
}