Ce que cet article vous apporte est une introduction à la connaissance de la covariance des tableaux Java et de l'invariance générique (avec code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. aide.
La variabilité est un des principaux écueils de l'invariance du langage POO, et la covariance des tableaux de Java est l'un des anciens écueils. Parce que j'ai marché dessus récemment, j'ai pris note. Au passage, évoquons aussi la dégénérescence des paradigmes.
Avant d'expliquer la covariance des tableaux, clarifiez d'abord trois concepts liés, la covariance, l'invariance et la contravariance.
1. Covariance, invariance, contravariance
Supposons que j'aie écrit un tel morceau de code pour un restaurant
class Soup<T> { public void add(T t) {} } class Vegetable { } class Carrot extends Vegetable { }
Il existe une classe générique Soup
Alors la question est : quelle est la relation entre la soupe
La première réaction est que Soup
Soup<Vegetable> soup = new Soup<Carrot>(); soup.add(new Tomato());
La première phrase est correcte, Soup
Cependant, il y a un problème lorsque les deux phrases sont mises ensemble. Le type réel de soupe est Soup
Alors, quelle est la relation entre la soupe
(1) Si Soup
(2) Si Soup
(3) Si Soup
Comprenez les concepts de covariance, d'invariance et de contravariance, puis examinez l'implémentation en Java. Les génériques généraux de Java sont immuables, ce qui signifie que Soup
2. Covariance des tableaux
En Java, les tableaux sont des types de base, pas des génériques, et Array
Contrairement à l'immuabilité des génériques, les tableaux Java sont covariants. En d’autres termes, Carrot[] est une sous-classe de Vegetal[]. Les exemples de la section précédente ont montré que la covariance peut parfois poser problème. Par exemple, le code suivant
Vegetable[] vegetables = new Carrot[10]; vegetables[0] = new Tomato(); // 运行期错误
Les tableaux étant covariants, le compilateur permet à Carrot[10] d'être affecté à des variables de type Vegetal[]. Ce code peut donc être compilé avec succès. Ce n'est que pendant l'exécution, lorsque la JVM essaie d'insérer une tomate dans un tas de carottes, que quelque chose d'important se passe mal. Par conséquent, le code ci-dessus lèvera une exception de type java.lang.ArrayStoreException pendant l'exécution.
La covariance des tableaux est l'un des célèbres bagages historiques de Java. Soyez prudent lorsque vous utilisez des tableaux !
Si vous remplacez le tableau de l'exemple par une List, la situation sera différente. Comme ça
ArrayList<Vegetable> vegetables = new ArrayList<Carrot>(); // 编译期错误 vegetables.add(new Tomato());
ArrayList est une classe générique et elle est immuable. Par conséquent, il n’existe aucune relation d’héritage entre ArrayList
Bien que les deux morceaux de code signalent des erreurs, les erreurs de compilation sont généralement plus faciles à gérer que les erreurs d'exécution.
3. Quand les génériques veulent aussi la covariance et la contravariance
Les génériques sont immuables, mais dans certains scénarios, nous espérons toujours qu'ils peuvent covarier. Par exemple, il y a une jeune femme qui boit chaque jour de la soupe aux légumes pour perdre du poids
class Girl { public void drink(Soup<Vegetable> soup) {} }
我们希望drink方法可以接受各种不同的蔬菜汤,包括Soup
要实现这一点,应该采用一种类似于协变性的写法
public void drink(Soup<? extends Vegetable> soup) {}
意思是,参数soup的类型是泛型类Soup
但是,这种方法有一个限制。编译器只知道泛型参数是Vegetable的子类,却不知道它具体是什么。所以,所有非null的泛型类型参数均被视为不安全的。说起来很拗口,其实很简单。直接上代码
public void drink(Soup<? extends Vegetable> soup) { soup.add(new Tomato()); // 错误 soup.add(null); // 正确}
方法内的第一句会在编译期报错。因为编译器只知道add方法的参数是Vegetable的子类,却不知道它具体是Carrot、Tomato、或者其他的什么类型。这时,传递一个具体类型的实例一律被视为不安全的。即使soup真的是Soup
但是方法内的第二句是正确的。因为参数是null,它可以是任何合法的类型。编译器认为它是安全的。
同样,也有一种类似于逆变的方法
public void drink(Soup<? super Vegetable> soup) {}
这时,Soup
这种情况就不存在上面的限制了,下面的代码毫无问题
public void drink(Soup<? super Vegetable> soup) { soup.add(new Tomato()); }
Tomato是Vegetable的子类,自然也是Vegetable父类的子类。所以,编译期就可以确定类型是安全的。
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!