2015-06-16 11 views
7

Si consideri la seguente configurazione:Come sostituire un tipo parametrico con uno più specifico

Abbiamo un'interfaccia SuperType che viene parametrizzato in questo modo:

public interface SuperType<V> { 
} 

SuperType supporta metodo di concatenamento. Quindi definisce un altro parametro di tipo che cattura il sottotipo concreta applicazione restituito da ciascun metodo come questo:

public interface SuperType<V, S extends SuperType<V, S>> { 

    public S doSomething(); 
} 

Consideriamo un'implementazione di SuperType<V, S extends SuperType<V, S>>:

public class SubType<V> implements SuperType<V, SubType<V>> { 

    private final V value; 

    public SubType(V value) { this.value = value; } 

    public SubType<V> doSomething() { return this; } 
} 

Qualcuno istanzia SubType<V> utilizzando ad esempio stringhe ma fornisce Object per il parametro di tipo V:

Object s = "Java Generics"; 
SubType<Object> x = new SubType<>(s); 

Ora vogliamo definire un altro metodo per SuperType<V, S extends SuperType<V, S>> che prende un parametro di tipo più specifico di V e restituisce lo stesso tipo di implementazione S ma ora parametrizzati con W extends V:

public interface SuperType<V, S extends SuperType<V, S>> { 

    public S doSomething(); 

    public <W extends V, T extends SuperType<W, T>> T doMoreSpecific(Class<W> typeToken); 
} 

Questa nuova definizione interfaccia è destinato a sostenere:

Object s = "Java Generics"; 
SubType<Object> x = new SubType<>(s); 
SubType<String> y = x.doMoreSpecific(String.class); 

Qui ho difficoltà a implementare SubType<V>. Quello che voglio fornire come un'implementazione è:

public class SubType<V> implements SuperType<V, SubType<V>> { 

    private final V value; 

    public SubType(V value) { this.value = value; } 

    public SubType<V> doSomething() { return this; }; 

    public <W extends V> SubType<W> doMoreSpecific(Class<W> typeToken) { 
     return new SubType<>((W) value); 
    } 
} 

mia domanda è:

Come devo definire la firma per il metodo doMoreSpecific() nel tipo SuperType<V, S extends SuperType<V, S>> in modo che l'applicazione fornita da SubType<V> implements SuperType<V, SubType<V>> è accettabile?

In caso contrario, quale implementazione e definizione del metodo di interfaccia farebbe il trucco?

Oppure, perché non possiamo farlo in Java?

+1

solo un CommNet, in un'interfaccia, tutti i metodi sono astratti, quindi la definizione esplicita è ridondante –

+4

'S si estende ' non è la sintassi valida che rende la vostra domanda difficile da capire ... – assylias

+0

Spero fissato l'errori di sintassi . Ero pigro per definire tutti i tipi nel mio IDE :). Scusate. – Harmlezz

risposta

3

Utilizzando la seguente firma:

<W extends V> SuperType<W, ?> doMoreSpecific(Class<W> typeToken); 

Ci potrebbero essere alcuni casi non sicuri però che non sono stato in grado di trovare ancora, ogni critica è il benvenuto!

+0

La tua soluzione fa il trucco ma non sono in grado di implementare il metodo in una classe astratta o come metodo predefinito. Se lo faccio, perderò il tipo di implementazione concreta, che potrebbe implementare anche più interfacce. anche nella mia domanda, ma ho cercato di evitare molti dettagli, tuttavia, se non viene trovata una soluzione migliore, prenderò la soluzione. – Harmlezz

+1

@Harmlezz: puoi mantenere la vecchia definizione come 'doMoreSpecific0' e' doMoreSpecific' richiama semplicemente 'doMoreSpecific', l'inferenza sembra preoccupante re qui per ottenere 'T'. – ZhongYu

0

Non si può fare ciò che il vostro codice suggerisce che si desidera, si dispone di un metodo di digitato : W viene dedotto dal tipo di parametro, ma il tipo di parametro è noto solo al luogo di chiamata. cioè non c'è una versione del metodo doMoreSpecific() che può essere specificata nell'interfaccia SuperType (che deve essere implementata).

Il più vicino si potrebbe ottenere è quello di rendere W un tipo di parametro generico di SuperType, ma poi l'implementazione avrebbe funzionato esattamente per una classe W, che sarebbe il ridondante typeToken, che chiaramente non è quello che si vuole.

+1

Ho avuto una discussione con un collega sul mio problema e mi ha detto che ciò che mi piace non è disponibile in _Java_ ma in _Scala_: un costruttore di tipi. A mio parere, il problema che devo affrontare è che non sono in grado di estrarre il tipo _raw dal tipo parametrizzato per formulare il nuovo tipo da restituire. Per esempio se potessi estrarre il tipo grezzo da 'S', diciamo' raw: S' di quanto potrei definire la firma come segue: 'public raw: S estende SuperType doMoreSpecific (classe typeToken);" Sei d'accordo? ? – Harmlezz

0

Non so che cosa la vostra intenzione esatta è dietro doMoreSpecific, ma se si tratta solo di colata da SubType<Object> a SubType<String> si potrebbe fare quanto segue (anche se questo non è molto buona pratica ...):

Object s = "Java Generics"; 
SubType<Object> x = new SubType<>(s); 
SubType<String> y = (SubType<String>) (SubType<?>) x; 

Nota 1: questo darà ancora un avvertimento.

Nota 2: questa trasmissione funziona anche se s non è di tipo String! Ma riceverai una ClassCastException quando chiami y.doSomething(). (Che avresti anche nel tuo esempio per quel caso).

Per esempio: il seguente pezzo di codice (brutto) avrebbe funzionato, troppo (fatta eccezione per le linee evidenziate):

ArrayList<?> lo = new ArrayList<Object>(); 
    ArrayList<Integer> li = (ArrayList<Integer>) lo; 
    ArrayList<String> ls = (ArrayList<String>) lo; 

    li.add(5); 
    ls.add("five"); 

    System.out.println(lo);  // prints "[5, five]" 

    System.out.println(li.get(0)); // prints "5" 
    System.out.println(li.get(1)); // ClassCastException 

    System.out.println(ls.get(0)); // ClassCastException 
    System.out.println(ls.get(1)); // prints "five" 

Nota 3: Questo dimostra perfettamente come i generici nel lavoro fatto: Tutto quello che fanno è inserire automaticamente i calchi nelle posizioni richieste per te.

Problemi correlati