La matriz genérica arroja ClassCastException cuando se hace referencia directa (no lo hace cuando se llama a través del método auxiliar)

¡Esto es magia! Mira este código simple:

public class ArrayOFMagic<T> {

    protected T[] array;

    protected int showMeYouRLength() {
        return array.length;
    }

    ArrayOFMagic() {
        array = (T[]) new Object[10];
    }

    protected void set(T value, int index) {
        array[index] = value;
    }

    public static void main(String[] args) {
        ArrayOFMagic<Integer> arrayOFMagic = new ArrayOFMagic<Integer>();
        System.out.println(arrayOFMagic.showMeYouRLength());
        System.out.println("MAGIC INCOMING");
        System.out.println(arrayOFMagic.array.length);
    }

}

Salida:

10
EXCEPCIÓN MÁGICA
Excepción en el hilo "principal" java.lang.ClassCastException: [Ljava.lang.Object; no se puede enviar a [Ljava.lang.Integer; en ArrayOFMagic.main (ArrayOFMagic.java:25)

Llamo a array.length dos veces. Una vez a través del método y una vez directamente. Continúa cuando se usa el método y genera una excepción cuando se llama directamente. Oo alguien explicar?

editar: Solo para aclarar: la clase funciona bien cuando no se llama directamente. ¡Puede tener setters / getters en elementos de matriz y todo ...!

Respuesta 1

Respuesta ACTUALIZADA:

DESCARGO DE RESPONSABILIDAD : Esta respuesta no es mía, le pregunté a un ex empleado de Sun que trabajaba en genéricos en Java por qué sucede esto. Su respuesta:

La primera llamada accede al miembro desde dentro de la propia clase genérica, que se borra a su límite inferior (en este caso, Object), por lo que no hay conversión en la referencia a array.length.

Pero la segunda llamada está en una instancia parametrizada de un tipo genérico , por lo que la variable de tipo (la matriz) está vinculada a Integer.

El campo de matriz se declara de tipo T [], que está vinculado a Integer []. El código de acceso que emite el compilador lo convierte a ese tipo, y el reparto se produce (en todos los sentidos de la palabra).

ANTIGUA RESPUESTA: Aquí hay una mejor manera de implementar su clase (como una adición a la respuesta de zhong.j.yu).

import java.util.ArrayList;
import java.util.List;

public class NotSoMagical<T> {

    public List<T> arrayList;

    protected int length() {
        return arrayList.size();
    }

    NotSoMagical() {
        arrayList = new ArrayList<T>(10);
    }

    protected void set(T value, int index) {
        arrayList.set(index, value);
    }

    public static void main(String[] args) {
        NotSoMagical<Integer> notMagicalAtAll = new NotSoMagical<Integer>();
        System.out.println(notMagicalAtAll.length());
        System.out.println("MAGIC INCOMING");
        System.out.println(notMagicalAtAll.arrayList.size());
    }

}
Respuesta: 2

Cuando se usa un tipo genérico, el compilador crea conversiones ocultas, por lo que la excepción ocurre debido a la creación incorrecta de la matriz. Pero puede crear la matriz con el tipo correcto cambiando el constructor usando java.lang.reflect.Array :

ArrayOFMagic(Class<T> elementType) {
    array = (T[]) Array.newInstance(elementType, 10);
}
Respuesta: 3

Posible duplicado: ¿Qué es "String args []"? en Java Así que recientemente (bueno, hace tres días) comencé a enseñarme Java, con absolutamente cero experiencia previa en programación a menos que cuentes HTML / ...

He leído muchos artículos sobre por qué la variable ThreadLocal debe ser estática (aunque no es necesaria), pero no tuve la idea de por qué debería ser estática. Lo he leído aquí y muchos otros enlaces pero no ...

Estaba haciendo algunos experimentos y accidentalmente escribí un código, que es muy extraño y no lo entiendo todo. Incluso me sorprendió poder compilarlo. Se ve así: enum Foo {VALOR_1 {...

Por favor, consulte el siguiente código. Cuando ejecuto el código, puedo cambiar el valor de una variable final no estática. Pero si trato de cambiar el valor de una variable estática final, arroja java.lang ...