Maison >Java >javaDidacticiel >Méthodes de covariance, contravariance, extensions et super sélection des génériques Java
Pour comprendre la covariance et la contravariance, il faut d'abord introduire :
D'après le principe de substitution de Liskov, si C est une sous-classe de P, alors P peut remplacer C, c'est-à-dire P p = new C();
C hérite de P, enregistré comme P
Si F est inchangé, lorsque CSauf par exemple Integer est une sous-classe de Number Selon le principe de substitution de Liskov
Number number = new Integer(1); //correctMais si vous l'écrivez comme ça, une erreur sera signalée
List<Number> list = new ArrayList<Integer>(1); //errorBien que Number et Integer aient un héritage. relation : Integer 09a50b8c699633a4e7667b7bfecc86ff et
Listc0f559cc8d56b43654fcbe4aa9df7b4a
sans aucun héritage. relation# 🎜🎜#Qu'est-ce que la covarianceListc8f01a3f8889dcf657849dd45bc0fc4c
和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
Si F est covariant, quand C <= P, alors F(C) <= F(P)#🎜 🎜#
Java fournit une extension pour convertir l'invariance en covariance, par exemple :
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()); } } }À ce moment,
Java fournit un super pour convertir l'invariant en un changement consensuel, pour exemple : #🎜🎜##🎜🎜#rrreee#🎜🎜#À l'heure actuelle,Lista2b037db85f4e1df0e812b9647ac55a8
peut être considéré comme la classe parent deArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
- Les tableaux sont covariants par défaut
extend Number
peut être considéré comme un type ? plage, représentant une certaine sous-classe de Nombre 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); }Qu'est-ce que la contravariance
- Si F est contravariant Oui , lorsque C 005981dc2681b7fae899b7167d46016f= F(P)
Listda50108ad159903fabe211f1543600e8
peut être considérée comme la classe parent deArrayLista87fdacec66f0909fc0757c19f2d2b1d
#🎜🎜##🎜🎜#extends et super#🎜🎜##🎜🎜##🎜🎜#Tout d'abord, regardons l'implémentation de Collection.add : #🎜🎜##🎜🎜#rrreee#🎜🎜## 🎜🎜 #Le code suivant signalera-t-il une erreur ? #🎜🎜#? extends Number
ne correspond pas au typeInteger
#🎜🎜#rrreee#🎜🎜#Tout d'abord, lors de l'appel de la méthode add, leE
code> devient automatiquementa2b037db85f4e1df0e812b9647ac55a8
#🎜🎜##🎜🎜#La deuxième ligne signale une erreur, ce qui signifie que? classe parente. Ici, nous devons distinguer que
Lista2b037db85f4e1df0e812b9647ac55a8
est la classe parent deArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
. #🎜🎜##🎜🎜#? extends Number
peut être considéré comme un certain type dans une plage de types, représentant une certaine sous-classe de Number, mais il n'est pas clair de quelle sous-classe il s'agit, peut-être Float. Il peut s'agir de Short ou d'une sous-classe d'Integer (Integer est modifié par final et ne peut pas avoir de sous-classes. Il s'agit simplement d'une situation hypothétique. Il détermine uniquement sa limite supérieure en tant que nombre et ne détermine pas la limite inférieure (cela peut). existe? extends Number
<Integer
), donc? extends Number
n'est pas la classe parent deInteger
#🎜 🎜## 🎜🎜##🎜🎜# Modifiez légèrement le code ci-dessus et il sera correct : #🎜🎜##🎜🎜#rrreee#🎜🎜#Tout d'abord, à cause de l'inversion,List<? ;
est ArrayLista87fdacec66f0909fc0757c19f2d2b1d, la première ligne est correcte. #🎜🎜##🎜🎜#La deuxième ligne :? super Number
est la classe parent deInteger
, la raison est :super Number
signifie Number One des classes parent peut êtreSerializing
ouObject
, mais peu importe de laquelle il s'agit, la classe parent de Number doit être la classe parent d'Integer, donc le la deuxième ligne est également correcte# 🎜🎜##🎜🎜#Devrions-nous utiliser extends ou super ? ##🎜🎜##🎜🎜##🎜🎜#Lorsque vous souhaitez écrire des données dans une classe générique, utilisez super #🎜🎜##🎜🎜##🎜🎜##🎜🎜#Si vous souhaitez à la fois obtenir et écrivez, vous n'avez pas besoin de caractères génériques (c'est-à-dire que ni extends ni super ne sont utilisés) #🎜🎜##🎜🎜##🎜🎜#rrreee
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!