2010-03-17 13 views
21

Sono sicuro che a questa domanda è stata data risposta in precedenza, ma non riesco davvero a trovarla.casting Collection <SomeClass> alla raccolta <SomeSuperClass>

Ho una classe java SomeClass e una classe astratta SomeSuperClass. SomeClass estende SomeSuperClass.

Un altro metodo astratto ha un metodo che restituisce un valore Collection<SomeSuperClass>. In una classe di implementazione, ho un Collection<SomeClass> myCollection

Capisco che non posso tornare myCollection, perché Collection<SomeClass> non eredita da Collection<SomeSuperClass>. Tuttavia, so che tutto in myCollection è un SomeSuperClass perché, dopo tutto, sono gli oggetti SomeClass che si estendono SomeSuperClass.

Come posso fare questo lavoro?

I.e. Voglio

public class A 
{ 
    private Collection<SomeClass> myCollection; 

    public Collection<SomeSuperClass> getCollection() 
    { 
    return myCollection; //compile error! 
    } 
} 

L'unico modo che ho trovato è colata attraverso un tipo non generico e ottenere avvisi incontrollati e quant'altro. Ci deve essere un modo più elegante, però? Ritengo che anche usando Collections.checkedSet() e gli amici non siano necessari, dal momento che è staticamente certo che la collezione restituita contiene solo oggetti SomeClass (questo non sarebbe il caso del downcasting invece del upcasting, ma non è quello che sto facendo). Cosa mi manca?

Grazie!

risposta

11

Non è possibile farlo. Avete una collezione <SomeClass> e desidera restituire un insieme <SuperClass>

Ora immaginate che qualcuno ha Collezione tornato - e tenta di inserire un diversa sottoclasse di SuperClass, SomeOtherClass. Questo dovrebbe essere consentito sulla vostra collezione SuperClass - ma non può perché è in realtà una raccolta <SomeClass>, all'insaputa di tutti, ma il membro privato di A.

+0

Aha! Grazie :-) Suona come se avessi bisogno di una vista immutabile. – skrebbel

+0

Hmm c'è il supporto della libreria standard per le viste immutabili? :-) – skrebbel

+0

Perché la 'mia soluzione' è possibile? Mi manca qualcosa (vedi la mia risposta qui sotto) –

-3

Una collezione di sottotipo non è sostituibile per SuperTipo.

+0

Beh, chiaramente lo so. Il mio problema era che volevo aggirare il problema. Il mio vero problema era che non capivo * perché * una collezione di Sottotipo non è sostituibile per SuperType.Rispondendo a una domanda che dice "Non posso fare X, c'è una soluzione" con "Non puoi fare X" sembra che tu stia solo provando a segnare punti di stackoverflow. – skrebbel

+1

Ha mancato il bit nel mezzo di un 'modo più elegante'. Sono corretto ... – Everyone

+0

Potresti voler dare un'occhiata a http://stackoverflow.com/questions/15496/hidden-features-of-java/55221#55221 – Everyone

0

Non so perché; forse qualcun altro può spiegarlo; ma funziona se si fa:

public abstract class SomeSuperClass<E> { 
    abstract public Collection<SomeSuperClass<E>> getCollection(); 
} 

e:

public class Someclass extends SomeSuperClass { 
    @Override 
    public Collection<Someclass> getCollection() { 
     // TODO Auto-generated method stub 
     return null; 
    } 
} 
+0

Sarei molto interessato anche a questo. Sicuro che non stai ricevendo avvertimenti non controllati in qualche modo? Ad ogni modo, stai estendendo una classe generica senza rendere la sottoclasse generica, che suona come una cosa strana per iniziare .. – skrebbel

+0

Sì, è strano. Se fate la sottoclasse più concreto si ottiene: public class SomeClass estende SomeSuperClass { \t @Override \t Collezione pubblica > GetCollection() { \t \t // TODO metodo generato automaticamente stub \t \t return null; } } Non ho mai usato una tale costruzione prima, non mi sembra davvero un buon modo per me. –

+0

Your Someclass estende SomeSuperClass, che è un tipo non elaborato perché SomeSuperClass è dichiarato come . Credo che dal momento che estendi un tipo non elaborato, riceverai un avviso per questo, ma poi non riceverai ulteriori avvertimenti non controllati sui singoli metodi, anche se in realtà sono conversioni non controllate. –

0

forse, si dovrebbe fare qualche soluzione alternativa.

ad esempio, dovresti creare un "HolderClass" con estensione generica, e poi sarai in grado di mettere in condizione meteo il tuo SomeClass, superare il tuo SomeSuperClass.

un'occhiata:

public class HolderClass<E extends SomeSuperClass> { 

    private final Collection<E> myClass; 

    public HolderClass() { 
     myClass = new ArrayList<E>(); 
    } 

    public void putSomeClass(final E clazz) { 
     myClass.add(clazz); 
    } 

    public Collection<E> getMyClasses() { 
     return myClass; 
    } 

} 

e si può effettuare la raccolta in questo modo:

HolderClass<SomeSuperClass> holderClass = new HolderClass<SomeSuperClass>(); 
holderClass.putSomeClass(new SomeClass()); 
holderClass.putSomeClass(new SomeSuperClass()); 

e ora, quando si effettua chiamata a getMyClasses(), si otterrà collezione di SomeSuperClasses

20

Collection<? extends SomeSuperClass> non farà quello che vuoi?

+3

Questo è il modo corretto per farlo. Vedi: http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html – Adam

+0

Attenzione quando si utilizza in un'API: "Non utilizzare tipi di caratteri jolly come tipi di ritorno. Piuttosto che fornire una flessibilità aggiuntiva per il tuo utenti, li costringerebbe a utilizzare i caratteri jolly nel codice client. " Elemento Java efficace 28 https://stackoverflow.com/a/22815270/774398 – for3st

1

Se si crea una nuova collezione di tipo corretto è possibile popolare utilizzando la vecchia collezione

public Collection<SomeSuperClass> getCollection() 
{ 
    return new ArrayList<SomeSuperClass>(myCollection); 
} 
0

Sulla base della risposta superiore data a questa domanda: How do you cast a List of supertypes to a List of subtypes?

Io non credo che sia possibile fare

Collection<SomeSuperType> variable = 
        (Collection<SomeSuperType>)(Collection<?>) collectionOfSomeType; 

A scapito di un avviso "non controllato". Alla domanda collegata, è stata espressa preoccupazione circa la "scelleratezza" di questa risposta a causa della mancanza di sicurezza del tipo. Tuttavia, nel contesto di questa domanda (vale a dire una raccolta di sottotipi in una raccolta dei loro supertipi) non vedo problemi o possibili ClassCastExceptions. E in ogni caso, funziona abbastanza bene.

5

Java 8 ora offre un modo più ordinato di farlo utilizzando lambdas: è possibile utilizzare le funzioni map() and collect() per trasmettere gli oggetti alla classe super. Una soluzione per il tuo esempio sarebbe simile a questa:

public class A 
{ 
    private Collection<SomeClass> myCollection; 

    public Collection<SomeSuperClass> getCollection() 
    { 
     return myCollection.stream().map(x -> (SomeSuperClass) x).collect(Collectors.toList()); 
    } 
} 

È inoltre possibile utilizzare altri Collectors se necessario.

0

Sì, possiamo!

class A {@Override 
public String toString() 
{ 

    return "A"; 
} }; 
class B extends A { 
    @Override 
    public String toString() 
    {  
    return "B"; 
    } 
}; 
List<A> l1 = new ArrayList<A>(); 
l1.add(new A()); 
List<B> l2 = null; 
l2 = (List<B>)(List<? extends A>)l1; 
l2.add(new B()); 

System.out.println(Arrays.toString(l2.toArray())); 

effettuate alcune prove

Problemi correlati