2010-03-17 19 views
21

Estoy seguro de que esto ha sido respondido antes, pero realmente no lo puedo encontrar.colección de fundición <SomeClass> para Colección <SomeSuperClass>

Tengo una clase java SomeClass y una clase abstracta SomeSuperClass. SomeClass extiende SomeSuperClass.

Otro método abstracto tiene un método que devuelve Collection<SomeSuperClass>. En una clase de implementación, tengo un Collection<SomeClass> myCollection

entiendo que no puedo acaba de regresar myCollection, porque Collection<SomeClass> no hereda de Collection<SomeSuperClass>. Sin embargo, sé que todo en myCollection es SomeSuperClass porque después de todo, son SomeClass objetos que extienden SomeSuperClass.

¿Cómo puedo hacer esto?

I.e. Quiero

public class A 
{ 
    private Collection<SomeClass> myCollection; 

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

La única forma que he encontrado es la fundición a través de un tipo no genérico y conseguir advertencias y todo eso sin marcar. Sin embargo, debe haber una manera más elegante? Siento que también usar Collections.checkedSet() y amigos no es necesario, ya que es estáticamente cierto que la colección devuelta solo contiene objetos SomeClass (este no sería el caso cuando downcasting en lugar de upcasting, pero eso no es lo que estoy haciendo). ¿Qué me estoy perdiendo?

Gracias!

Respuesta

11

No puede hacer esto. Tiene una colección <SomeClass> y desea devolver una colección <SuperClass>

Ahora imagina que alguien tiene su cobro devuelto - y se intenta insertar un diferente subclase de SuperClass, SomeOtherClass. Esto se debe permitir en su colección SuperClass - pero no puede porque es en realidad una colección <SomeClass>, sin que nadie más que el miembro privada de A.

+0

Aha! Gracias :-) Parece que necesito una vista inmutable. – skrebbel

+0

Hmm ¿hay compatibilidad de biblioteca estándar para vistas inmutables? :-) – skrebbel

+0

¿Por qué es posible 'mi solución'? Me estoy perdiendo algo (mira mi respuesta a continuación) –

-3

Una colección del subtipo no es sustituible de supertipo.

+0

Bueno, claramente lo sé. Mi problema era que quería evitar eso. Mi verdadero problema era que no entendía * por qué * una colección de SubType no es sustituible para SuperType.Respondiendo a una pregunta que dice "No puedo hacer X, hay una solución" por "No puedes hacer X", suena como si estuvieras intentando puntuar puntos de acumulación de potencia. – skrebbel

+1

Perdí la mitad en el medio de una "manera más elegante". Me corrigen ... – Everyone

+0

Es posible que desee echar un vistazo en http://stackoverflow.com/questions/15496/hidden-features-of-java/55221#55221 – Everyone

0

No estoy seguro de por qué; tal vez alguien más pueda explicar esto; pero funciona si lo hace:

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

y:

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

Estaría muy interesado en eso también. ¿Seguro que no estás recibiendo advertencias sin control de alguna manera? De cualquier forma, estás ampliando una clase genérica sin hacer que la subclase sea genérica, eso suena raro para empezar ... – skrebbel

+0

Sí, es extraño. Si usted hace la subclase más concreto que se obtiene: clase pública se extiende Someclass SomeSuperClass { \t @ Override \t Colección público > getCollection() {// \t \t método generada automáticamente TODO código auxiliar \t \t devolver nulo; \t} } Nunca antes había usado una construcción así, realmente no parece una buena forma para mí. –

+0

Su Someclass extiende SomeSuperClass, que es un tipo sin formato porque SomeSuperClass se declara como . Creo que, dado que extiendes un tipo sin formato, recibirás una advertencia al respecto, pero luego no recibirás más advertencias sin marcar en los métodos individuales, a pesar de que en realidad son conversiones no verificadas. –

0

tal vez, usted debe hacer algunas solución.

por ejemplo, debe hacer un poco de "HolderClass" con una extensión genérica, y entonces podrá ponerle tiempo a su SomeClass, capear su SomeSuperClass.

echar un vistazo:

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; 
    } 

} 

y usted puede hacer la colección de esta manera:

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

y ahora, cuando se hace la llamada a getMyClasses(), obtendrá colección de SomeSuperClasses

20

¿Collection<? extends SomeSuperClass> no hará lo que usted quiere?

+3

Esta es la forma correcta de hacerlo. Consulte: http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html – Adam

+0

Tenga cuidado al usar en una API: "No use tipos de comodines como tipos de devolución. En lugar de proporcionar flexibilidad adicional para su usuarios, les obligaría a usar tipos de comodines en el código del cliente ". Artículo Java 28 efectivo https://stackoverflow.com/a/22815270/774398 – for3st

1

Si crea una nueva colección del tipo correcto puede rellenarlo utilizando la antigua colección

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

Sobre la base de la respuesta superior dado a esta pregunta: ¿ How do you cast a List of supertypes to a List of subtypes?

yo creo que es posible hacer

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

A expensas de una advertencia de "desmarcado". En la pregunta vinculada, se ha expresado preocupación sobre el "hackiness" de esta respuesta debido a la falta de seguridad de tipo. Sin embargo, en el contexto de esta pregunta (es decir, fundir una colección de subtipos en una colección de sus supertipos) no veo problemas ni posibles ClassCastExceptions. Y en cualquier caso, funciona bastante bien.

5

Java 8 ahora ofrece una manera más clara de hacerlo usando lambdas: puede usar las funciones map() and collect() para convertir los objetos a su súper clase. Una solución para su ejemplo sería el siguiente:

public class A 
{ 
    private Collection<SomeClass> myCollection; 

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

También puede utilizar otra Collectors si es necesario.

0

Sí, podemos!

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())); 

favor probarlo

Cuestiones relacionadas