Java Generics Wildcarding con più classi


385

Voglio avere un oggetto Class, ma voglio forzare qualunque classe rappresenti per estendere la classe A e implementare l'interfaccia B.

Posso fare:

Class<? extends ClassA>

O:

Class<? extends InterfaceB>

ma non posso fare entrambe le cose. C'è un modo per fare questo?

Risposte:


613

In realtà, puoi fare quello che vuoi. Se vuoi fornire più interfacce o una classe più interfacce, devi avere un carattere jolly simile a questo:

<T extends ClassA & InterfaceB>

Vedi il tutorial di Generics su sun.com, in particolare la sezione Parametri del tipo associato , nella parte inferiore della pagina. Puoi effettivamente elencare più di un'interfaccia se lo desideri, usando & InterfaceNameper ognuna di cui hai bisogno.

Questo può diventare arbitrariamente complicato. Per dimostrare, vedere la dichiarazione JavaDoc di Collections#max, che (racchiusa in due righe) è:

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

perché così complicato? Come detto nelle FAQ di Java Generics: per preservare la compatibilità binaria .

Sembra che questo non funzioni per la dichiarazione di variabili, ma funziona quando si pone un limite generico su una classe. Pertanto, per fare ciò che desideri, potresti dover saltare alcuni cerchi. Ma puoi farlo. Puoi fare qualcosa del genere, ponendo un limite generico alla tua classe e quindi:

class classB { }
interface interfaceC { }

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

per ottenere variablequello ha la restrizione che desideri. Per ulteriori informazioni ed esempi, consulta la pagina 3 di Generics in Java 5.0 . Nota, in <T extends B & C>, il nome della classe deve venire prima e le interfacce seguono. E ovviamente puoi elencare solo una singola classe.


94
Questo è utile Vale la pena ricordare che la classe deve venire prima, non si può dire '<T estende InterfaceB & ClassA>'.
EricS,

5
Come fai lo stesso per T dovrebbe estendere una classe o implementare un'interfaccia?
Ragunath Jawahar,

1
@RagunathJawahar: non puoi essere troppo aperto a riguardo. Devi avere dei limiti e uno di questi è sapere in anticipo dove avrai interfacce e dove avrai classi e come utilizzerai l'eredità. Praticamente devi sapere per un parametro di tipo se sarà una classe o un'interfaccia.
Eddie,

4
La prima riga della tua risposta dice "fai in modo che il tuo jolly assomigli a questo" Non c'è ?in quella espressione, quindi è davvero un "jolly"? Lo chiedo perché non riesco a far funzionare l'intero concetto di "estensione di due cose contemporaneamente" quando il parametro type è in realtà un carattere jolly.
L'

1
Sì, non è proprio un jolly e non puoi fare ciò che l'OP ha richiesto con un jolly. È possibile fare ciò che il PO voleva, in modo efficace, non solo con un carattere jolly.
Eddie,

17

Non è possibile farlo con parametri di tipo "anonimo" (ovvero caratteri jolly che utilizzano ?), ma è possibile farlo con parametri di tipo "denominato". Dichiarare semplicemente il parametro type a livello di metodo o di classe.

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

2
Perché i caratteri jolly non sono ammessi? cioè non vedo perché questo non dovrebbe essere valido: ArrayList <? estende l'elenco ClassA & InterfaceB>; E quindi se estrai un elemento dall'elenco, potresti assegnarlo a una variabile di tipo ClassA o di tipo InterfaceB
Segna il

Sostituire il carattere jolly con una variabile è un'ottima tecnica! Ma non sempre funziona. Ad esempio, Java non consente variabili di tipo nomi nei tipi di valore di annotazione, mentre consente caratteri jolly.
firmato il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.