La conversión de tipo List <ChildClass> a List <BaseClass>

Mukul Chandel:

Tengo una estructura de clases como esto:

public class BaseClass {

}

public class ChildClass extends BaseClass {

}

Digamos que tengo un método getList que los rendimientos List<BaseClass>:

public List<BaseClass> getList() {
     List<BaseClass> b = new ArrayList<>();
     return b;
}

List<BaseClass> b = getList();

Quiero hacer el tan genérico método anterior getList () que, o bien puede devolver un objeto de tipo List<BaseClass>o List<ChildClass>función de algunas condiciones y asignar el valor devuelto a un objeto de tipo List<BaseClass>solamente . La razón de esto es que estoy tratando con un poco de código heredado donde los objetos son de tipo List<BaseClass>y me quieren evitar refactorización a algo parecido a List<? extends BaseClass>como esta podría bloquear las operaciones existentes como add () de estos objetos de lista.

Yo entiendo que List<BaseClass>, y List<ChildClass>no son covarient.

Sin embargo, mediante el siguiente técnicas Soy capaz de lanzar List<ChildClass>a List<BaseClass>y yo estoy confundido que la forma en que está sucediendo detrás de las escenas y si es correcto o no.

Usando conversión explícita:

List<BaseClass> b = new ArrayList<>();
List<ChildClass> c = new ArrayList<>();
b = c; // gives compilation error
b = (List<BaseClass>) c; // gives compilation error
b = (List<BaseClass>)(List<?>) c; // this works

El uso de los genéricos:


public List<ChildClass> getChildClassList() {
   // code to fetch/generate list and return
}

public List<BaseClass> getBaseClassList() {
   // code to fetch/generate list and return
}

public static <T extends BaseClass> List<T> getList() {
    if(something) {
        List<ChildClass> c = getChildClassList();
        return (List<T>) c; // this cast is required here.
    } else {
        List<BaseClass> b = getBaseClassList();
        return (List<T>) b;
    }
}

List<BaseClass> = getList(); // This works perfectly fine but,
                             // I dont understand how casting is happening here.
                             // Also with cast to List<T> inside getList how is the final return type determined?

El uso de comodines:


public List<ChildClass> getChildClassList() {
   // code to fetch/generate list and return
}

public List<BaseClass> getBaseClassList() {
   // code to fetch/generate list and return
}

public List<? extends BaseClass> getList() {
    if(something) {
        List<Child> c = getChildClassList();
        return c;
    } else {
        List<Base> b = getBaseClassList();
        return b;
    }
}

List<BaseClass> = getList(); // Gives compilation error saying incompatible types

// Casting this, however, works fine
List<BaseClass> = (List<BaseClass>) getList();

Estos se sienten un poco como un truco para mí probablemente porque Java no soporta haciendo un reparto directo. Me temo que hay un problema aquí, que puede ser que falte.

Aunque, estos funcionan bien para mi caso de uso, ¿hay alguna implicación con este enfoque que debería preocuparse?

¿Es seguro para escribir dicho código?

¿Es una mala manera de escribir código? Si es así, entonces, ¿cómo deben realizar esto?

Andy Turner:

¿hay alguna implicación con este enfoque que debería preocuparse?

Con el caso genérico, sí: puede llamar List<ChildClass> list = getList();, y terminar con una lista completa de cosas que no son ejemplos de ChildClass.

Fundamentalmente, no se puede hacer cualquier cosa que resulta en un tipo diferente de ser devueltos con seguridad del método. Lo mejor que puede hacer es el caso de comodín:

List<? extends BaseClass> list = getList();

porque todo en esa lista será o bien una BaseClass(de un poco de sabor), o nulo.

A continuación, puede convertir de forma segura a un List<BaseClass>copiándolo:

List<BaseClass> list2 = new ArrayList<>(list);

Tenga en cuenta que si estuviera usando algo así como la guayaba de ImmutableListesta "copia" podría ser libre:

ImmutableList<BaseClass> list2 = ImmutableList.copyOf(list);

A pesar del nombre, copyOfdevuelve el parámetro, fundido, si eso es una instancia de ImmutableList, porque se trata de un elenco covariante seguro.


En términos de la conversión lista una ChildClass: no hay mucho que se puede hacer en tiempo de compilación. Usted tiene que convertir esto en un control de tiempo de ejecución:

// Throw an exception or something if this is false.
boolean allAreChildClass = list.stream().allMatch(e -> e == null || e instanceof ChildClass);

Y luego hacer una copia de la lista, la realización de la pieza fundida.

List<ChildClass> list3 =
    list.stream().map(ChildClass.class::cast).collect(Collectors.toList());

O, si usted puede estar seguro de que listno va a ser utilizado en cualquier otro lugar, puede simplemente reparto:

List<ChildClass> list3 = (List<ChildClass>) (List<?>) list;

pero hay que ser muy seguro de que listo bien no es usado en otra parte, o de lo contrario no va a ser modificada por otra cosa que no sea el código de fundición.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=316310&siteId=1
Recomendado
Clasificación