Java のジェネリックは、常に明白であるとは限りません。私は完全には理解できない状況に遭遇しました - おそらく誰かが私をここで助けてくれるでしょう. 次の 3 つのクラスを考えてみましょう。それぞれに内部クラスが含まれています。
public class DoesStuff<E extends DoesStuff.Element> {
ArrayList<E> elements;
public void MethodA(ArrayList<E> moreElements) {}
public void MethodB(ArrayList<E> moreElements) {}
public static class Element {}
}
public class DoesMoreStuff<E extends DoesMoreStuff.ElementA> extends DoesStuff<DoesMoreStuff.ElementA> {
ArrayList<DoesMoreStuff.ElementA> otherElements;
@Override
public void MethodA(ArrayList<DoesMoreStuff.ElementA> moreElements) {}
public static class ElementA extends DoesStuff.Element {}
}
public class DoesEvenMoreStuff extends DoesMoreStuff<DoesEvenMoreStuff.ElementB> {
ArrayList<DoesEvenMoreStuff.ElementB> stillOtherElements;
@Override
public void MethodB(ArrayList<*****> moreElements) {}
public static class ElementB extends DoesMoreStuff.ElementA {}
}
3 番目のクラスに進む前に、まず 2 番目のクラスの MethodA を見てみましょう。ArrayList の型パラメータは、「DoesStuff.Element」を拡張する「DoesMoreStuff.ElementA」です。これは明らかに機能します。
3 番目のクラスでは、MethodB をオーバーライドします。このクラスでは、ElementB のインスタンスを操作する予定です。ただし、私たちはクラス階層のさらに下のレベルにあり、型パラメーター (「*」で示されます) を適切に指定するのは難しいことがわかりました。
以下にいくつかの可能性を示します。これらはすべてある程度理にかなっていますが、どれも機能しません。
<DoesEvenMoreStuff.ElementB> ElementB は ElementA を拡張し、それ自体が Element を拡張するため、これは機能するはずです。
<DoesStuff.Element> 最悪の場合、すべてを Element のように扱いますが、これも機能しません。
<? extends DoesStuff.Element> 必死になって、Element のサブタイプである限り、クラスが何であるかは気にしないと言います。ArrayList が読み取られるだけである限り、これは問題ありませんが、機能しません。
実際、唯一の可能性は次のようです。
- <DoesMoreStuff.ElementA> おそらく ElementA が Element を直接拡張し、最上位クラスの元の宣言と一致するため、これは機能します。しかし、少なくとも私には論理的ではないように思えます。
誰でもこの状況を明確に説明できますか?
- - - 編集 - - -
2 番目のクラスの望ましい動作は、型パラメーター「DoesEvenMoreStuff.ElementB」を使用できるようにすることです。以下の受け入れられた回答は、問題を説明しています。2 番目のクラスを次のように変更すると、問題が解決します。
public class DoesMoreStuff<E extends DoesMoreStuff.ElementA> extends DoesStuff<E> {
ArrayList<E> otherElements;
@Override
public void MethodA(ArrayList<E> moreElements) {}
public static class ElementA extends DoesStuff.Element {}
}
軟膏に残っている 1 つのハエ: 2 番目のクラスでは、MethodA の宣言は実際には正しくありません: ArrayList には内部クラスの要素が正確に含まれるため、これは実際には "MethodA(ArrayList<DoesMoreStuff.ElementA>" である必要があります。ただし、コンパイラは受け入れられなくなりました。
PS このような複雑なクラス構造のアプリケーションに興味がある人向け: 最上位のクラスは、データベース アプリケーションのオフライン モード用の汎用データ キャッシュ機能を提供します。2 番目のクラスは、ほとんどのデータ クラスのデータ キャッシュを提供します。3 番目のクラスは、何か特別なものを必要とする特定のクラスにキャッシュを提供します。内部クラスはキャッシュ データ要素です。