Joker générique Java avec plusieurs classes


385

Je veux avoir un objet Class, mais je veux forcer la classe qu'il représente à étendre la classe A et à implémenter l'interface B.

Je peux faire:

Class<? extends ClassA>

Ou:

Class<? extends InterfaceB>

mais je ne peux pas faire les deux. Y a-t-il un moyen de faire cela?

Réponses:


614

En fait, vous pouvez faire ce que vous voulez. Si vous souhaitez fournir plusieurs interfaces ou une classe plus d'interfaces, vous devez faire en sorte que votre caractère générique ressemble à ceci:

<T extends ClassA & InterfaceB>

Consultez le didacticiel sur les génériques sur sun.com, en particulier la section Paramètres de type délimités , au bas de la page. Vous pouvez en fait lister plus d'une interface si vous le souhaitez, en utilisant & InterfaceNamepour chacune dont vous avez besoin.

Cela peut devenir arbitrairement compliqué. Pour le démontrer, voir la déclaration JavaDoc de Collections#max, qui (enroulée sur deux lignes) est:

public static <T extends Object & Comparable<? super T>> T
                                           max(Collection<? extends T> coll)

pourquoi si compliqué? Comme indiqué dans la FAQ Java Generics: pour préserver la compatibilité binaire .

Il semble que cela ne fonctionne pas pour la déclaration de variable, mais cela fonctionne lorsque vous mettez une limite générique sur une classe. Ainsi, pour faire ce que vous voulez, vous devrez peut-être sauter à travers quelques cerceaux. Mais tu peux le faire. Vous pouvez faire quelque chose comme ça, en mettant une limite générique sur votre classe, puis:

class classB { }
interface interfaceC { }

public class MyClass<T extends classB & interfaceC> {
    Class<T> variable;
}

pour obtenir variablecela a la restriction que vous voulez. Pour plus d'informations et d'exemples, consultez la page 3 de Generics in Java 5.0 . Notez que dans <T extends B & C>, le nom de la classe doit venir en premier et les interfaces suivent. Et bien sûr, vous ne pouvez lister qu'une seule classe.


95
C'est utile. Il convient de mentionner que la classe doit venir en premier, vous ne pouvez pas dire «<T étend InterfaceB & ClassA>».
EricS

5
Comment faites-vous la même chose pour T devrait soit étendre une classe OU implémenter une interface?
Ragunath Jawahar

1
@RagunathJawahar: Vous ne pouvez pas être trop ouvert à ce sujet. Vous devez avoir des limites, et l'une d'elles sait à l'avance où vous aurez des interfaces et où vous aurez des classes, et comment vous utiliserez l'héritage. Vous devez à peu près savoir pour un paramètre de type s'il s'agira d'une classe ou d'une interface.
Eddie

4
La première ligne de votre réponse dit «que votre caractère générique ressemble à ceci». Il n'y a pas ?dans cette expression, alors est-ce vraiment un "joker"? Je demande parce que je ne peux pas faire fonctionner le concept "étendre deux choses à la fois" lorsque le paramètre type est vraiment un caractère générique.
The111

1
Oui, ce n'est pas vraiment un caractère générique et vous ne pouvez pas faire ce que l'OP a demandé avec un caractère générique. Vous pouvez faire ce que le PO voulait, efficacement, mais pas avec un caractère générique.
Eddie

17

Vous ne pouvez pas le faire avec des paramètres de type "anonymes" (c'est-à-dire des caractères génériques qui utilisent ?), mais vous pouvez le faire avec des paramètres de type "nommés". Déclarez simplement le paramètre type au niveau de la méthode ou de la classe.

import java.util.List;
interface A{}
interface B{}
public class Test<E extends B & A, T extends List<E>> {
    T t;
}

2
Pourquoi les caractères génériques ne sont-ils pas autorisés? c'est-à-dire que je ne vois pas pourquoi cela ne devrait pas être valide: ArrayList <? étend la liste ClassA & InterfaceB>; Et puis, si vous retirez un élément de la liste, vous pouvez l'affecter à une variable de type ClassA ou de type InterfaceB
Mark

Le remplacement du caractère générique par une variable est une excellente technique! Mais ça ne marche pas toujours. Par exemple, Java n'autorise pas les variables de type noms dans les types de valeur d'annotation, alors qu'il autorise les caractères génériques.
sigpwned
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.