2014-12-18 7 views
5

Ich habe Probleme mit Java-Generika - speziell mit Wildcard-Capture. Hier ist eine vereinfachte Version des Codes, den ich habe, der das Problem zeigt, das ich sehe. Es macht mich verrückt:Wie behebe ich dieses Wildcard-Capture-Problem bei der Verwendung von Java-Generics?

public class Task { 

    private Action<ActionResult, ? extends ActionSubject> action; 
    private ActionSubject subject = new ActionSubjectImpl(); 

    private List<ActionResult> list = new ArrayList<>(); 

    public static void main(String[] args) { 
     Task task = new Task(); 
     task.setAction(new ActionImpl()); 
     task.doAction(); 
    } 

    public void setAction(Action<ActionResult, ? extends ActionSubject> action) { 
    this.action = action; 
    } 

    public void doAction() { 
     list.add(action.act(subject)); 
    }  

    public static class ActionResult { } 

    public interface Action<T, U> { 
     public T act(U argument); 
    }  

    public interface ActionSubject { 
     public String getName(); 
    } 

    public static class ActionImpl implements Action<ActionResult, ActionSubjectImpl>{ 
     @Override 
     public ActionResult act(ActionSubjectImpl argument) { 
      // Code that requires ActionSubjectImpl specifically instead of the interface. 
      // This classes implmentation of action should only support ActionSubjectImpl as an 
      // argument. 
      return new ActionResult(); 
     } 
    } 

    public class ActionSubjectImpl implements ActionSubject { 
     @Override 
     public String getName() { 
      return "I am a subject"; 
     } 
    } 
} 

Paket Deklaration und Importe sind nicht enthalten - sonst ist dies abgeschlossen. Dies kompiliert nicht. Das Problem ist, mit dem Fragment list.add(action.act(subject)); wo ich die Fehlermeldung sehe:

incompatible types: ActionSubject cannot be converted to CAP#1 
where CAP#1 is a fresh type-variable: 
    CAP#1 extends ActionSubject from ? extends ActionSubject 

ich von anderen Beiträge sehen können, dass Hilfsmethoden als eine Möglichkeit vorgeschlagen, Dinge wie diese zu arbeiten, aber ich habe nicht in der Lage gewesen, erstelle eine, die funktioniert.

Die Action action hat die Typparameter wie so: Action<ActionResult, ? extends ActionSubject> und die ActionSubject, die ich in die act Methode am Übergang von Interface-Typ ist ‚ActionSubject‘ und konkreten Typ ‚ActionSubjectImpl‘ obwohl das Codefragment in Frage das nicht sehen konkrete Art des Kurses. Der zweite Typparameter von Action sollte jeden Typ unterstützen, der sich erweitert ActionSubject - und es ist in Ordnung, wenn ich action auf new ActionImpl() setze, wo der zweite Typ ActionSubjectImpl ist.

Ich würde mich über jeden Kommentar darüber, was ich hier falsch mache, in meinen Definitionen und der Verwendung von Generika freuen. Ich vermisse etwas Grundlegendes hier. Ich könnte das anders programmieren, aber bis ich verstehe, was schief läuft, kann ich nicht weitermachen.

Danke.

Antwort

10

Hier ist Ihr Missverständnis: Sie sagten:

Der zweite Typ Parameter Action sollte jede Art unterstützen, die ActionSubject

erstreckt Dies ist nicht korrekt. Der zweite Typparameter von Action ist darauf beschränkt, eine spezifische Unterklasse von ActionSubject zu sein, z. B. MyActionSubject. Sie können also keine willkürliche ActionSubject Instanz übergeben, weil das ein generischer Typ ist.

Wenn Sie beliebige Subtypen von ActionSubject haben möchten, verwenden Sie einfach ActionSubject als zweiten Typparameter anstelle von ? extends ActionSubject.

+0

Hallo. Wenn ich das tun task.setAction (new ActionImpl()); 'scheitert mit' ActionImpl kann nicht in Action 'umgewandelt werden, da mein' ActionImpl' 'Action ' –

+1

Vielleicht möchten Sie die Das Feld ist 'private Action action;'? Oder verwenden Sie 'Task ' und machen Sie es 'private Action Aktion;'? – MForster

+0

Ich werde zur Kompilierzeit (innerhalb der Task) nicht wissen, welche 'Action'-Implementierung und damit welche' ActionSubject'-Implementierung verwendet wird, also ist die erste Option ein Nein - ich habe hier nur 'ActionSubjectImpl' eingebettet, um dies zu demonstrieren. Aber die zweite Option ist interessant - und sie funktioniert für mein Codebeispiel. Ich werde es mit meinem echten Code testen und wenn das in Ordnung ist, werde ich dies als beantwortet markieren. Vielen Dank! –

Verwandte Themen