6

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 consider the following generic declaration of class :

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

At runtime, no T would be present! But if I instantiate this class of type Integer, then the corresponding object will have a field t of type Integer.

Then, why can't I check the type of a variable with T which can be replaced by Integer at runtime. And I would be actually doing something like "o instanceof Integer".

Under which cases, allowing instanceof with a Type Parameter can cause trouble so that it is prohibited?

whitehat
  • 2,381
  • 8
  • 34
  • 47
  • 7
    You've already said "At runtime, no T would be present", so it sounds like you're already aware of *type erasure*. So I'm not sure why you're confused about this behaviour? – Oliver Charlesworth Jan 05 '12 at 11:49
  • 1
    Just because its not allowed doesnt mean it can cause rouble. T is a generic type and can in fact be about anything, using it instanceof just doent make any sense. – Peter Jan 05 '12 at 11:52
  • possible duplicate of [Java: Instanceof and Generics](http://stackoverflow.com/questions/1570073/java-instanceof-and-generics) – millimoose Jan 05 '12 at 11:56

7 Answers7

6

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.

yankee
  • 38,872
  • 15
  • 103
  • 162
5

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);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
3

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

Novakov
  • 3,055
  • 1
  • 16
  • 32
3

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));
}
millimoose
  • 39,073
  • 9
  • 82
  • 134
1

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).

gustafc
  • 28,465
  • 7
  • 73
  • 99
0

Java realize its Generics using "Erasure", it can check the type and delete the type parameter information in "COMPILE TIME", in "RUN TIME" there will only the BOUNDARIES of the type parameters, so there will not be any thing like "Integer"

Y.L.
  • 1,274
  • 6
  • 23
  • 39
0

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.

Stephan
  • 4,395
  • 3
  • 26
  • 49