2015-08-25 1 views
7

ich zwei Schnittstellen:Generisches Chaos Java

public interface Receiver<T> { 

    public void receive(T obj); 

    public Set<Class<? extends T>> getInterests(); 

} 

public interface Distributor<T> extends Receiver<T> { 

public void register(Receiver<T> receiver); 

} 

Mein Problem, dass ich zum Beispiel einen Distributor in einem Distributor registrieren möchten Distributor<Object> == Register ==>Distributor<String>

Mein erster Gedanke war die Registermethode register(Receiver<? extends T> receiver). Aber wenn ich ist der Empfänger die Klassen erhalten ändern möchten etwas wie Set<Class<? extends ? extends T>> Interessent in der Methode getInterests zurückkehren würde. Indirekt bekomme ich etwas wie Set<Class<? extends T>>, aber ich habe festgestellt, dass transitive Wildcards in Java nicht möglich sind.

Haben Sie jemanden eine Idee?

EDIT: Als Beispiel:

public void register(Receiver<? extends T> receiver){ 
    Set<Class<? extends T>> interests = receiver.getInterests(); 
    //Problem because receiver.getInterests is 
    //Set<Class<? extends ? extends T>> 
    ... 
} 
+2

Können Sie ein Beispiel für eine Codezeile, die nicht für Sie zusammenstellen? Der Code scheint zu kompilieren. –

Antwort

7

Ihr Problem ist, dass Java Generika vollständig unveränderlich sind, wenn Sie sie Variante ? extends oder ? super Platzhalter machen.

Ein Set<Class<? extends T>> kann nur Ausdrücke des Kompilierzeittyps Class<? extends T> enthalten. Class<String> ist nicht derselbe Typ wie (obwohl es zu diesem Typ konvertierbar ist).

Sie möchten ein Set, das alle Typen enthalten kann, die in Class<? extends T> konvertiert werden können.

Das ist ein Set<? extends Class<? extends T>>

+1

'Klasse' ist endgültig richtig? Wie kann es etwas geben, was die Klasse erweitert? – Codebender

+2

@Codebender: 'extends' bedeutet eigentlich" konvertierbar zu ". 'Klasse ' kann in 'Klasse '(wenn auch nicht in' Class '; Sie benötigen _both_' extends 'Wildcards). – SLaks

+1

@Codebender 'Klasse ' kann Subtypen über Generika haben, obwohl die Klasse final ist und nicht unterklassifiziert werden kann. 'extends' hat eine breitere Bedeutung, wenn es in einer Bindung verwendet wird. – Radiodef

1

Sie könnten eine Hilfsmethode hinzufügen, die verwendet eine Variable vom Typ anstelle von Wildcard

public void register(Receiver<? extends T> receiver) 
{ 
    register2(receiver); 
} 

private <S extends T> void register2(Receiver<S> receiver) 
{ 
    Set<Class<? extends S>> interests = receiver.getInterests(); 
    ... 
} 

Auf der anderen Seite, Methode

public Set<Class<? extends T>> getInterests(); 

wahrscheinlich wäre, soll um eine kovariante Set oder schreibgeschützte Menge zurückzugeben. Wildcard sollte idealerweise

public Set<? extends Class<? extends T>> getInterests(); 

verwendet werden, aber ich weiß, es gibt zu viele verdammte Platzhalter ...