共分散と反分散を理解するには、まず次のことを導入する必要があります。
リスコフ置換原理によれば、C が P のサブクラスである場合、P は C を置き換えることができます。つまり、 P p = new C();
C は P から継承し、 C
F が不変の場合、 C
たとえば、リスコフ置換原則によれば、Integer は Number のサブクラスです。
Number number = new Integer(1); //correct
ただし、このように書くとエラーが報告されます
List<Number> list = new ArrayList<Integer>(1); //error
Number と Integer には Integer < Number という継承関係がありますが、Java ではジェネリックはデフォルトで変更されないため、変更することもできます。 List<Number>
および List<Integer>
と見なされます。継承関係はありません
F が共分散の場合, when C <= P, then F(C) <= F(P)
Java は、不変性を共分散に変換するための extends を提供します。次に例を示します。 ##List<? extends Number> list = new ArrayList<Integer>(1); //corrent
は、ArrayList<Integer>
Number の特定のサブクラスを表す型範囲として見ることができます配列はデフォルトで共変です
Number[] numbers = new Integer[3];
反変性とは
If F は反変です。C <= P の場合、F(C) >= F(P)Java は、不変式を共変式の Change に変換するためのスーパーを提供します。 :
List<? super Number> list = new ArrayList<Object>(1); //corrent
は、ArrayList<Object>
## の親クラスとみなすことができます。 #extends と super
public interface List<E> extends Collection<E> { boolean add(E e); }
? extends Number は Integer 型
List<? extends Number> list = new ArrayList<Integer>(); // correct list.add(Integer.valueOf(1)); //error
と一致しません。まず、add メソッドが呼び出されるとき、汎用の
E自動的に extends Number> 2 行目はエラーを報告します。これは、
? extends Number
Integer## の親クラスではないことを意味します。 #。ここで、List<? extends Number>
が ArrayList<Integer>
の親クラスであることを区別する必要があります。 ? extends Number
は、Number の特定のサブクラスを表す、型範囲内の特定の型と見なすことができますが、それがどのサブクラスであるかは明確ではありません。Float または Short である可能性があります。 . 、または Integer のサブクラスである可能性があります (Integer は Final によって変更され、サブクラスを持つことはできません。これは単なる仮定の状況です)。上限は Number として決定されるだけで、下限は決定されません (## が存在する可能性があります)。 # ? extends Number
Integer)、したがって
? extends Number は
Integer の親クラスではありません上記のコードを変更します。少し変更すると正しくなります:
List<? super Number> list = new ArrayList<Object>(); // correct list.add(Integer.valueOf(1)); //correct
List super Number> は ## の親クラスです。 #ArrayList<Object>。1 行は正しいです。
2 行目: ? super Number
は Integer
の親クラスです。理由は次のとおりです:
は特定の親クラスを表しますNumber の場合、 Serializable
または Object
の場合がありますが、どちらであっても、 Number の親クラスは Integer の親クラスでなければならないため、2 行目は次のようになります。これも正しいです Use extends それともスーパーですか?
java.util.Collections (JDK1.7) の copy メソッドから答えが得られます:
public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++) dest.set(i, src.get(i)); } else { ListIterator<? super T> di=dest.listIterator(); ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) { di.next(); di.set(si.next()); } } }
ジェネリックから変換するには クラスがデータを取得する場合は extends; を使用します
private static <E> E getFirst(List<? extends E> list){ return list.get(0); } private static <E> void setFirst(List<? super E> list, E firstElement){ list.add(firstElement); } public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); setFirst(list, 1); Number number = getFirst(list); }
以上がJava ジェネリックスの共分散、反分散、拡張および超選択メソッドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。