Maison > Java > javaDidacticiel > 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
Libérer: 2023-05-26 13:46:12
avant
1333 Les gens l'ont consulté

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
Copier après la connexion

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

List<Number> list = new ArrayList<Integer>(1);  //error
Copier après la connexion

Bien que Number et Integer aient un héritage. relation : Integer < Number, mais en Java, les génériques sont inchangés par défaut, ils peuvent donc également être considérés comme List<Number> et <code>List<Integer> sans aucun héritage. relation

# 🎜🎜#Qu'est-ce que la covarianceList<Number> List<Integer> 不存在任何继承关系

什么是协变

如果F是协变的,当 C <= P 时,那么 F(C) <= F(P)

Java 提供了一个extends来将不变转为协变,例如:

List<? extends Number> list = new ArrayList<Integer>(1);  //corrent
Copier après la connexion

此时的List<? extends Number>可以看作为ArrayList<Integer>的父类

? extend Number可以看作为一个类型范围,表示Number的某一个子类

数组默认是协变的

Number[] numbers = new Integer[3];
Copier après la connexion

什么是逆变

如果F是逆变的,当 C <= P 时,那么 F(C) >= F(P)

Java 提供了一个super来将不变转为协变,例如:

List<? super Number> list = new ArrayList<Object>(1);  //corrent
Copier après la connexion

此时的 List<? super Number>可以看作为 ArrayList<Object>的父类

extends 和 super

首先,我们看看Collection.add的实现:

public interface List<E> extends Collection<E> { boolean add(E e); }
Copier après la connexion

下面代码将会报错?? extends NumberInteger类型不匹配

List<? extends Number> list = new ArrayList<Integer>(); // correct
list.add(Integer.valueOf(1));  //error
Copier après la connexion

首先在调用add方法时,泛型E自动变成了<? extends Number>

第二行报错,也就是说? 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
Copier après la connexion

首先因为逆变,List<? super Number>ArrayList<Object>的父类,第一行正确。

第二行: ? 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());
        }
    }
}
Copier après la connexion
    À ce moment, List<? extends Number> peut être considéré comme la classe parent de ArrayList<Integer>
  • 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);
    }
    Copier après la connexion

    Qu'est-ce que la contravariance

  • Si F est contravariant Oui , lorsque C <= P, alors F(C) >= F(P)

  • Java fournit un super pour convertir l'invariant en un changement consensuel, pour exemple : #🎜🎜##🎜🎜#rrreee#🎜🎜#À l'heure actuelle, List<? super Number> peut être considérée comme la classe parent de ArrayList<Object> #🎜🎜##🎜🎜#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 <? extends Number>#🎜🎜##🎜🎜#La deuxième ligne signale une erreur, ce qui signifie que ? classe parente. Ici, nous devons distinguer que List<? extends Number> est la classe parent de ArrayList<Integer>. #🎜🎜##🎜🎜#? 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 ArrayList<Object>, 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!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal