Java のジェネリックスでのサブタイプ
ここでは、サブタイプの問題について触れておきます。
サブタイプというのは、言い換えればサブクラスあるいは派生クラスということですが、 ジェネリックスの場合、通常のオブジェクトと異なる動作をするので注意が必要です。
Person クラスから SalesPerson クラスが派生しているとします。
このとき、SalesPerson オブジェクトから Person クラスへのキャストは安全に行うことができます。 なぜなら SalesPerson クラスは Person クラスから派生しているので、SalesPerson は Person でもあるからです。
一般的に、このようにスーパークラスへのキャストは安全に行うことができます。これをアップキャストといいます。
では、ジェネリックスで定義された型ではどうなるでしょうか?
次の例をみてください。
Box<String> sbox = new Box<String>(new String("Hello"));
Box<Object> obox = sbox; // 間違い!
上の例では、Box<String> 型の sbox を Box<Object> に代入しようとしています。
String は Object でもあるわけですから、これは一見正しいように見えますが、実はこのコードはコンパイルできません。
なぜ、このような制限が発生してしまうのでしょうか。
もし、Box<Object> を通して Box<String> を操作できたとしたら、Box<String> の中に Integer など他の型のオブジェクトが混じり込むことになってしまいます。
これでは、型付けを強めるためにジェネリックにした意味がなくなってしまいます。
つまり、String が Object のサブタイプだとしても、ジェネリックスで定義された Box<String> は Box<Object> のサブタイプにはならないのです。