Maison  >  Article  >  Java  >  Méthodes de covariance, contravariance, extensions et super sélection des génériques Java

Méthodes de covariance, contravariance, extensions et super sélection des génériques Java

PHPz
PHPzavant
2023-05-26 13:46:121244parcourir

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

Ce qui est inchangé#🎜🎜 #

Si F est inchangé, lorsque C
Sauf par exemple Integer est une sous-classe de Number Selon le principe de substitution de Liskov

Number number = new Integer(1);  //correct

Mais si vous l'écrivez comme ça, une erreur sera signalée

List<Number> list = new ArrayList<Integer>(1);  //error

Bien 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 NumberInteger类型不匹配

List<? extends Number> list = new ArrayList<Integer>(); // correct
list.add(Integer.valueOf(1));  //error

首先在调用add方法时,泛型E自动变成了a2b037db85f4e1df0e812b9647ac55a8

第二行报错,也就是说? extends Number不是Integer的父类。这里要将 Lista2b037db85f4e1df0e812b9647ac55a8ArrayListc0f559cc8d56b43654fcbe4aa9df7b4a的父类区分开。

? extends Number可以看作为一个类型范围中某一个类型,表示Number的某一个子类,但又没明确是哪个子类,可能是Float,可能是Short,也可能是Integer的子类(Integer被final修饰,不可能有子类,这里只是一种假设情况),它只确定了它的上界为 Number,并没有确定下界(有可能存在? extends NumberInteger),因此 ? extends Number不是Integer的父类

将上面代码稍做修改就正确了:

List<? super Number> list = new ArrayList<Object>(); // correct
list.add(Integer.valueOf(1));  //correct

首先因为逆变,Listda50108ad159903fabe211f1543600e8ArrayLista87fdacec66f0909fc0757c19f2d2b1d的父类,第一行正确。

第二行: ? super NumberInteger的父类,原因是:? 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, Lista2b037db85f4e1df0e812b9647ac55a8 peut être considéré comme la classe parent de ArrayListc0f559cc8d56b43654fcbe4aa9df7b4a
  • extend Number peut être considéré comme un type ? plage, représentant une certaine sous-classe de Nombre

  • Les tableaux sont covariants par défaut
  • 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)

Java fournit un super pour convertir l'invariant en un changement consensuel, pour exemple : #🎜🎜##🎜🎜#rrreee#🎜🎜#À l'heure actuelle, Listda50108ad159903fabe211f1543600e8 peut être considérée comme la classe parent de ArrayLista87fdacec66f0909fc0757c19f2d2b1d #🎜🎜##🎜🎜#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 type Integer #🎜🎜#rrreee#🎜🎜#Tout d'abord, lors de l'appel de la méthode add, le Ecode> devient automatiquement a2b037db85f4e1df0e812b9647ac55a8#🎜🎜##🎜🎜#La deuxième ligne signale une erreur, ce qui signifie que ? classe parente. Ici, nous devons distinguer que Lista2b037db85f4e1df0e812b9647ac55a8 est la classe parent de ArrayListc0f559cc8d56b43654fcbe4aa9df7b4a. #🎜🎜##🎜🎜#? 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 de Integer#🎜 🎜## 🎜🎜##🎜🎜# 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 de Integer, la raison est :  super Number signifie Number One des classes parent peut être Serializing ou Object, 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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer