Pregunta ¿Por qué "t instanceof T" no está permitido donde T es un parámetro de tipo yt es una variable?


Eclipse dice que la instancia de operación no está permitida con el parámetro de tipo debido a un borrador de tipo genérico.

Estoy de acuerdo en que en tiempo de ejecución, no queda información de tipo. Pero considere la siguiente declaración genérica de clase:

class SomeClass<T>{
    T t;
    SomeClass(Object o){
        System.out.println(o instanceof T);   // Illegal
    }   
}        

¡En tiempo de ejecución, ningún T estaría presente! Pero si instanciar esta clase de tipo Entero, entonces el objeto correspondiente tendrá un campo t de tipo Entero.

Entonces, ¿por qué no puedo verificar el tipo de variable con T que puede ser reemplazado por Integer en tiempo de ejecución? Y estaría haciendo algo así como "o instanceof Integer".

¿Bajo qué casos, permitiendo una instancia con un parámetro de tipo puede causar problemas para que esté prohibido?


6
2018-01-05 11:47


origen


Respuestas:


Si necesita T en tiempo de ejecución, debe proporcionarlo en tiempo de ejecución. Esto a menudo se hace pasando la Clase <T> que T tiene que ser.

class SomeClass<T> {
    final T t;

    public SomeClass(Class<T> tClass, T t) {
        if(!tClass.isAssignableFrom(t.getClass()) throw new IllegalArgumentException("Must be a " + tClass);
        this.t = t;
    }

    private SomeClass(T t) {
        this.t = t;
    }

    public static <T> SomeClass<T> of(Class<T> tClass, T t) {
        if(!tClass.isAssignableFrom(t.getClass()) throw new IllegalArgumentException("Must be a " + tClass);
        return new SomeClass(t);
    }
} 

// doesn't compile
SomeClass<Integer> intSomeClass = SomeClass.of(Integer.class, "one");

Class clazz = Integer.class;
// compiles with a warning and throws an IAE at runtime.
SomeClass<Integer> intSomeClass = (SomeClass<Integer>) SomeClass.of(clazz, "one");

// compiles and runs ok.
SomeClass<Integer> intSomeClass = SomeClass.of(Integer.class, 1);

5
2018-01-05 11:52



Pero si instanciar esta clase de tipo entero, entonces el   objeto correspondiente tendrá un campo t de tipo Entero

No, no lo hará. Tendrá un campo de tipo Object. Solo cada vez que acceda, se convertirá en un Entero.

Considera el siguiente código:

SomeClass<Integer> c = new SomeClass<Integer>();
SomeClass untyped = (SomeClass)c; // Which type was it?
SomeClass<String> stringTyped = (SomeClass<String>)untyped; // Now it's STRING??

Trabajos. Te da un montón de advertencias de compilación, pero funciona. Porque el campo T es en realidad de tipo Object y se puede convertir a cualquier cosa.


5
2018-01-05 11:54



Después de compilar el extracto o instanceof T sería o instanceof Object y dado que todos los tipos se derivan de Object, siempre se evaluará como verdadero. Permitir este tipo de pruebas daría resultados falsos positivos


3
2018-01-05 11:51



Porque tipo borradoesto nunca funciona En tiempo de ejecución, solo sabes que tu clase tiene un parámetro de tipo T, pero no de qué tipo es para una instancia determinada. Entonces no puedes determinar si un objeto es de tipo T para empezar, porque no sabes qué T es, no porque causaría algún tipo de problema.

Si necesita hacer este tipo de comprobación de tiempo de ejecución, pase un token de tipo a su objeto explícitamente:

SomeClass(Object o, Class<T> type) {
    System.out.println(type.isInstance(o));
}

2
2018-01-05 11:53



Pero si instanciar esta clase de tipo Entero, entonces el objeto correspondiente tendrá un campo t de tipo Entero.

En realidad, no sería así. Tendría un campo t de tipo Object. Como dijiste, los genéricos son azúcar sintáctica casi en su totalidad (la excepción es que cuando extiendes una clase genérica y especificas un parámetro de tipo, el tipo permanece como metadatos en el archivo de clase).


1
2018-01-05 11:53



Los argumentos de tipo genérico no se conocen en tiempo de ejecución, por lo que no hay clases con las que pueda comparar. T solo se conoce en tiempo de compilación. Los genéricos solo ayudan al desarrollador a escribir código más fácilmente. Pero en el tiempo de ejecución, los argumentos son justos Object instancias.


0
2018-01-05 11:52



Java realiza sus genéricos usando "Erasure", puede verificar el tipo y eliminar la información del parámetro de tipo en "TIEMPO DE COMPILACIÓN", en"Tiempo de ejecución"solo habrá el LÍMITES de los parámetros de tipo, por lo que no habrá nada como "Entero"


0
2017-10-09 02:01