2014-12-18 7 views
5

Sto riscontrando problemi nell'utilizzo di java generics, in particolare con l'acquisizione di caratteri jolly. Ecco una versione semplificata del codice che ho che mostra il problema che sto vedendo. Mi sta facendo impazzire:Come si risolve questo problema di acquisizione di caratteri jolly quando si utilizzano i 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"; 
     } 
    } 
} 

La dichiarazione del pacco e le importazioni non sono incluse - altrimenti questo è completo. Questo non viene compilato. Il problema è con il frammento list.add(action.act(subject)); dove sto vedendo il messaggio di errore:

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

posso vedere da altri posti che metodi di supporto sono suggeriti come un modo ottenere le cose come questo per funzionare, ma non sono stato in grado di ne trovi uno che funzioni.

Il Action action ha i parametri di tipo in questo modo: Action<ActionResult, ? extends ActionSubject> e la ActionSubject che sto passando per il metodo act è di tipo di interfaccia 'ActionSubject' e di tipo concreto 'ActionSubjectImpl' anche se il frammento di codice in questione non vedrà la tipo concreto naturalmente. Il secondo parametro di tipo Action dovrebbe supportare qualsiasi tipo che si estende ActionSubject - e va bene quando si imposta action su new ActionImpl(), dove il secondo tipo è ActionSubjectImpl.

Gradirei qualsiasi commento su ciò che sto facendo male qui nelle mie definizioni e uso di generici. Potrei mancare qualcosa di base qui. Potrei codificarlo in un modo diverso, ma finché non avrò capito cosa sta andando male non potrò andare avanti.

Grazie.

risposta

10

Ecco il vostro equivoco: Lei ha detto:

Il secondo parametro tipo di Action dovrebbe supportare qualsiasi tipo che si estende ActionSubject

Questo non è corretto. Il secondo parametro di tipo Action è vincolato per essere una sottoclasse specifica di ActionSubject, ad esempio MyActionSubject. Quindi non puoi passare in un'istanza arbitraria ActionSubject, perché è un tipo più generico.

Se si desidera avere sottotipi arbitrari di ActionSubject, utilizzare solo ActionSubject come secondo parametro di tipo anziché ? extends ActionSubject.

+0

Ciao. Se faccio ciò 'task.setAction (new ActionImpl());' fallisce con 'ActionImpl non può essere convertito in Action ' dato che il mio 'ActionImpl' implementa' Action ' –

+1

Forse vuoi il campo deve essere 'private Action action;'? Oppure utilizzare 'Attività ' e renderlo 'Azione privata azione;'? – MForster

+0

Non saprò in fase di compilazione (all'interno di Task) quale implementazione di Action e quindi quale implementazione di ActionSubject verrà utilizzata, quindi la prima opzione è un no go - ho incluso solo ActionSubjectImpl qui incorporato per dimostrarlo. Ma la seconda opzione è interessante - e funziona per il mio esempio di codice. Lo metterò alla prova con il mio vero codice e se ciò va bene, segnerò questo come risposta. Grazie! –

Problemi correlati