Estoy teniendo algunos problemas con un método que devuelve una lista genérica. El código es básicamente esto:

public class MyClass{
    private List<MyListElement> myList = new ArrayList<MyListElement>();

    public <E> List<E> getGenericList(){
        return new ArrayList<E>();
    }

    public void thisWorks(){
        List<MyListElement> newList = getGenericList();
        myList.addAll(newList);
    }

    public void thisDoesntWork(){
        myList.addAll(getGenericList());
    }

    public void thisDoesntWorkEither(){
        for(MyListElement elem : getGenericList()){
            fiddle();
        }
    }
}

¿Por qué el thisDoesntWork() método no funciona, y es hay alguna otra manera alrededor de ella (aparte de hacer el thisWorks() manera que no siempre es práctico)?

Cuando no es práctico esto significa que usted debe no se que hacer. Incluso su thisWorks método es peligroso, porque el que está asumiendo su genericList celebrará String (que no se puede saber con certeza a partir de su código).
getGenericList() devuelve una Lista con<E>, pero usted necesita llamar a addAll() con una Lista de<Cadena>. Lista de<> no es lo mismo que la Lista de<Cadena>, de ahí el error. Entonces, ¿por qué es myList declararse la Lista de<Cadena> en lugar de la Lista de<>?
No hay manera alrededor de ella. La fuente de datos original contiene objetos, pero tenemos que ser capaces de tratar el contenido como cadenas. Esto podría, en teoría, llevar a ClassCastExceptions sí, pero espero que podamos ser capaces de seguir la pista de qué tipo de lista de contenidos.
El pase de Object a String normalmente se realiza mediante toString(). Acaba de decir
Ese es un buen punto, pero la Cadena fue sólo un ejemplo. Tengo que ser capaz de manejar otros tipos también. En cualquier caso, si los elementos no son Cadenas de caracteres en realidad, la adición de los resultados de toString() para las listas es probable que llevar a aún más confusión que una ClassCastException haría. He editado la pregunta para reflexionar que no es en realidad Cadena relacionadas.

OriginalEl autor MatsT | 2012-12-17

4 Comentarios

  1. 7

    El compilador no puede deducir lo que el tipo para elegir el parámetro de tipo <E> del método genérico getGenericList() en thisDoesntWork().

    En este caso es necesario indicar explícitamente el Tipo para el tipo de argumento llamando <MyListElement>getGenericList()

    Alternativamente, usted puede cambiar la firma de getGenericList() a aceptar un Class<E> argumento. A continuación, habría que invocar getGenericList(MyListElement.class) en tanto thisWorks() y thisDoesntWork(). Hay que admitir que es un poco más detallado, pero definitivamente más intuitivo para los clientes de su método.

    Yo diría que como regla general, trate de hacer el tipo de los argumentos de sus métodos genéricos se inferrable de que el método de argumentos.

    Sería aceptable tener un getGenericList() Y un getGenericList(Clase<E>) versión? Que iba a dejar que la persona que llama escoger lo que uno quiere utilizar.
    Que es aceptable, aunque no es mi estilo personal.
    Puede usted por favor me explique cómo se puede añadir una lista de cadenas de milista, que es de un tipo diferente?
    Gracias por poitning que fuera, mi respuesta refleja todavía la cuestión del tipo de original, que era de la Cadena. He editado mi respuesta para que coincida con la forma actual de la cuestión.

    OriginalEl autor bowmore

  2. 3

    Puede cambiar thisDoesntWork() así:

      public void thisDoesntWork(){ //well, it works now
          myList.addAll(this.<String>getGenericList());
      }

    Usted necesita decirle al compilador qué tipo getGenericList() está tratando.

    ¿Qué sucede cuando la lista Genérica no es una Cadena?
    Desde myList está a la espera de un String, sabemos que estamos tratando con Strings. Si se tratara de algún otro tipo, el código tendría que cambiar en consecuencia.
    getGenericList() es sólo un ejemplo de método para simplificar el código tanto como sea posible. En el real de la aplicación devolverá una lista real y en la teoría de los objetos de su interior, podría ser algún otro tipo. Supongo que el resultado es una ClassCastException.
    no contiene nada, pero eso es irrelevante. Estamos tratando de decirle al compilador qué tipo de inferir para E
    No estamos hablando de que el tiempo de ejecución (en tiempo de ejecución no hay ninguna diferencia entre las listas de diferentes tipos). Estamos hablando del tiempo de compilación. En tiempo de compilación, cada expresión tiene un tipo definido, que se infiere por el compilador.

    OriginalEl autor GriffeyDog

  3. 3

    El tipo de argumento para el método genérico <E> getGenericsList() se puede pasar a la hora de la llamada:

    this.<String>getGenericsList()

    de lo contrario el compilador realiza sus mejores esfuerzos para deducirlo del contexto. Cuando se asigna el objeto devuelto a un List<String> de referencia, el compilador de ahí se deduce que pasa String como el tipo argumento.

    Dada la Lista de API:

    List<E> {
      void addAll(Collection<? extends E> c);
    }

    que el compilador no parecen ser capaces de inferir el tipo correcto, y para ser honesto no sé si esto es debido a que no es suficientemente inteligente, o porque no quieren llevar a la responsabilidad por diseño.

    Incluso hice una prueba para ver si el problema es el comodín, o si addAll() no se puede inferir el tipo de argumentos del tipo en parámetros, pero nada parece funcionar:

    public class GenericsList {
    
        public static void main(String[] args) {
            //same signature as Java API
            List<String> base = new List<String>();
            base.addAll(GenericsList.getList()); //ERROR!
    
            //addAll() doesn't use a wildcard
            List2<String> base2 = new List2<String>();
            base2.addAll(getList2()); //ERROR!
    
            //what about a generic method?
            addAll(base, getList()); //ERROR!
        }
    
        static <E> List<E> getList() {
            return new List<E>();
        }
    
        static <E> void addAll(List<E> src, List<E> other) {}
    
        static <E> List2<E> getList2() {
            return new List2<E>();
        }
    
        static class List<E> {
            void addAll(List<? extends E> other) {}
        }
    
        static class List2<E> {
            void addAll(List2<E> other) {}
        }
    
    }

    OriginalEl autor Raffaele

  4. 0

    Este código va a trabajar para usted.
    getGenericList() debe saber lo que es volver y que debe ser compatible con el tipo de lista.

    Usted no necesita la echó a la Cadena o cualquier otro según lo sugerido por otros como va a restringir su getGenericList método de intención por la vinculación que para el tipo de cadena.

    public class MyClass{
        private List<MyListElement> myList = new ArrayList<MyListElement>();
    
        public <E extends MyListElement> List<E> getGenericList(){
            return new ArrayList<E>();
        }
    
        public void thisWorks(){
            List<MyListElement> newList = getGenericList();
            myList.addAll(newList);
        }
    
        public void thisDoesntWork(){
            myList.addAll(getGenericList());
        }
    
        public void thisDoesntWorkEither(){
            for(MyListElement elem : getGenericList()){
                fiddle();
            }
        }
    }
    Exactamente no es necesario para la fundición de la lista para cualquier cosa
    Si MyListElement o sus subclases sería el único de los elementos que podrían estar en la lista, no sería un problema. Su solución se cae a pedazos cuando la getGenericList debe ser capaz de devolver otro tipo de listas.
    Lista de<MyListElement> newList = getGenericList(); no entiendo esto. Si getGenericList() debe devolver otro tipo de listas, a continuación, no puede ser asignado a newList que es la Lista de tipo<MyListElement>. Y también en la respuesta que usted ha aceptado, la solución se le pide que envíe tipo de clase a la getGenericList método.

    OriginalEl autor LPD

Dejar respuesta

Please enter your comment!
Please enter your name here