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?
Yes, it is mandatory to specify it. If you remove it and its usage in generic classes and methods they will become normal classes and methods.
A Generic class simply means that the items or functions in that class can be generalized with the parameter(example T) to specify that we can add any type as a parameter in place of T like Integer, Character, String, Double or any other user-defined type.
Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.
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.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With