Heim >Java >javaLernprogramm >Kovarianz-, Kontravarianz-, Erweiterungs- und Superselektionsmethoden von Java-Generika
Um Kovarianz und Kontravarianz zu verstehen, müssen wir zunächst Folgendes einführen:
Wenn C eine Unterklasse von P ist, kann P gemäß dem Liskov-Substitutionsprinzip C ersetzen, das heißt P p = new C();
Was ist Kovarianz?
C erbt von P, aufgezeichnet als C 23b6ec0f353510d49b3d2b90e8b44360 undListc0f559cc8d56b43654fcbe4aa9df7b4a
angesehen werden. Es gibt keine VererbungsbeziehungWenn F kovariant ist, wenn C fd4888e8331f4fa99820f314ae77550c 和Listc0f559cc8d56b43654fcbe4aa9df7b4a
不存在任何继承关系什么是协变
如果F是协变的,当 C 3592d2c0d3e58f8105bc39ac7b94d518可以看作为
ArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
的父类
? extend Number
可以看作为一个类型范围,表示Number的某一个子类数组默认是协变的
Number[] numbers = new Integer[3];什么是逆变
如果F是逆变的,当 C 5d18509ffa87f09498721c15444d4b70= F(P)
Java 提供了一个super来将不变转为协变,例如:
List<? super Number> list = new ArrayList<Object>(1); //corrent此时的
Listda50108ad159903fabe211f1543600e8
可以看作为ArrayLista87fdacec66f0909fc0757c19f2d2b1d
的父类extends 和 super
首先,我们看看Collection.add的实现:
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
自动变成了a2b037db85f4e1df0e812b9647ac55a8
第二行报错,也就是说
? extends Number
不是Integer
的父类。这里要将Lista2b037db85f4e1df0e812b9647ac55a8
是ArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
的父类区分开。
? 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首先因为逆变,
Listda50108ad159903fabe211f1543600e8
是ArrayLista87fdacec66f0909fc0757c19f2d2b1d
的父类,第一行正确。第二行:
? super Number
是Integer
的父类,原因是:? super Number
表示Number的某一个父类,可能是Serializable
也可能是Object
An dieser Stelle Zeit kannLista2c08abdf84903e86dd3ad0187900e0f
als übergeordnete Klasse vonArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
angesehen werden ein Typbereich, der eine bestimmte Unterklasse darstellt. Das Array ist standardmäßig kovariant. Was ist Kontravarianz? Wenn F kontravariant ist und C 5aaf8c27f6d4179a6818d1f0035130fa = F(P)Java bietet eine Super zum Konvertieren von Invarianz in Kovarianz, zum Beispiel:
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()); } } }Zu diesem Zeitpunkt kannListda50108ad159903fabe211f1543600e8
alsArrayLista87fdacec66f0909fc0757c19f2d2b1ds übergeordnete Klasse <ul class=" list-paddingleft-2"> <li>extends und super<p></p> </li>Schauen wir uns zunächst die Implementierung von Collection.add an: <li><p><pre class="brush:java;">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); }</pre></p></li>Wird der folgende Code einen Fehler melden? <li> <code>? extensions Number
stimmt nicht mit dem Typ vonInteger
übereinrrreee
Zuallererst wird beim Aufruf der Add-Methode automatisch das generischeE
verwendet3118fc83eaba9bc6a738268c3148a1a2
Die zweite Zeile meldet einen Fehler, was bedeutet, dass? erweitert Nummer
nicht die übergeordnete Klasse vonInteger
ist. Hier müssen wir unterscheiden, dassList5a1312bd1de15616f5bbc24ce87c8691
die übergeordnete Klasse vonArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
ist. 🎜🎜? extensions Number
kann als ein bestimmter Typ in einem Typbereich betrachtet werden, der eine bestimmte Unterklasse von Number darstellt, aber es ist nicht klar, um welche Unterklasse es sich handelt. Es kann sich um Float oder Short handeln , oder es ist eine Unterklasse von Integer (Integer wird durch final geändert und kann keine Unterklassen haben. Dies ist nur eine hypothetische Situation. Es bestimmt nur seine Obergrenze als Zahl und nicht die Untergrenze (es kann ? erweitert Number <Integer
, also ist? erweitert Number
nicht die übergeordnete Klasse vonInteger
Ändern Sie den obigen Code und er wird korrekt sein. Fehler: 🎜🎜rrreee🎜Zuallererst istListda50108ad159903fabe211f1543600e8
die übergeordnete Klasse vonArrayLista87fdacec66f0909fc0757c19f2d2b1d code>, und die erste Zeile ist korrekt. 🎜🎜Die zweite Zeile: <code>? super Number
ist die übergeordnete Klasse vonInteger
. Der Grund ist:? super Number
stellt eine bestimmte übergeordnete Klasse dar Zahl. Es kannSerializable
oderObject
sein, aber egal um welche es sich handelt, die übergeordnete Klasse von Number muss die übergeordnete Klasse von Integer sein, daher ist auch die zweite Zeile korrekt . Soll ich „Extens“ oder „Super“ verwenden? 🎜🎜🎜Die Kopiermethode von java.util.Collections (JDK1.7) gibt uns die Antwort: 🎜🎜rrreee🎜🎜🎜Wenn Sie Daten von einer generischen Klasse erhalten möchten, verwenden Sie „Extens“; 🎜🎜🎜🎜Um Daten in eine generische Klasse zu schreiben, verwenden Sie „super“;
Das obige ist der detaillierte Inhalt vonKovarianz-, Kontravarianz-, Erweiterungs- und Superselektionsmethoden von Java-Generika. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!