Why “t instanceof T” is not allowed where T is a type parameter and t is a variable?

后端 未结 7 1706
Happy的楠姐
Happy的楠姐 2021-01-05 11:03

Eclipse says that the instanceof operation is not allowed with Type Parameter due to generic type eraser.

I agree that at runtime, no type information stays. But con

相关标签:
7条回答
  • 2021-01-05 11:27

    Because of type erasure, this never works. At runtime, you only know that your class has a type parameter T, but not which type it is for a given instance. So you can't determine whether an object is of type T to begin with, because you don't know what T is, not because it would cause some sort of trouble.

    If you need to do this sort of runtime check, pass a type token to your object explicitly:

    SomeClass(Object o, Class<T> type) {
        System.out.println(type.isInstance(o));
    }
    
    0 讨论(0)
  • 2021-01-05 11:28

    If you need T at runtime, you need to provide it at runtime. This is often done by passing the Class<T> which T has to be.

    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);
    
    0 讨论(0)
  • 2021-01-05 11:30

    After compiling statement o instanceof T would be o instanceof Object and because all types derives from Object, it will always evaluate to true. Allowing this kind of tests would give false positive results

    0 讨论(0)
  • 2021-01-05 11:33

    But if I instantiate this class of type Integer, then the corresponding object will have a field t of type Integer.

    Actually, it wouldn't. It'd have a field t of type Object. As you've said, generics are almost entirely syntactic sugar (the exception is that when you extend a generic class and specify a type parameter, the type remains as metadata in the class file).

    0 讨论(0)
  • 2021-01-05 11:35

    But if I instantiate this class of type Integer, then the corresponding object will have a field t of type Integer

    No, it won't. It will have a field of type Object. Just everytime you access it, it will be cast to an Integer.

    Consider the following code:

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

    Works. Gives you a bunch of compiler warnings, but works. Because the field T is actually of type Object and can be cast to anything.

    0 讨论(0)
  • 2021-01-05 11:37

    The generic type arguments are not known at runtime, so there is no class you can compare with. T is only known at compile time. Generics do only help the developer to write code easier. But at runtime, the arguments are just Object instances.

    0 讨论(0)
提交回复
热议问题