Implications for the instanceof operator – Generics

Implications for the instanceof operator

Although the discussion here is about the instanceof type comparison operator, it applies equally to the instanceof pattern match operator.

At (1) below, we want to determine whether the object referenced by obj is an instance of the concrete parameterized type MyStack<Integer>—that is, whether it is a stack of Integer.

Click here to view code image

Object obj;

boolean isIntStack = obj instanceof MyStack<Integer>; // (1) Compile-time error!

The post-erasure code for (1) is equivalent to the following statement:

Click here to view code image

boolean isIntStack = obj instanceof MyStack;          // (1′)

The statement at (1′) cannot perform the instanceof type comparison as expected at (1), since the type erasure has removed the information about the concrete type parameter Integer—that is, the type MyStack<Integer> is non-reifiable. The compiler issues an error because the type Object cannot be safely cast to the type MyStack at runtime.

In the following code, the fact that IStack<Integer> is a supertype of MyStack<Integer> can be checked at compile time—that is, the type MyStack<Integer> can be considered a refinement of the type IStack<Integer>. Such refinement of a generic type can be checked with the instanceof type comparison operator as it is deemed safe at runtime.

Click here to view code image

IStack<Integer> iStack;

boolean isIntegerStack = iStack instanceof MyStack<Integer>;   // (2) OK.

The post-erasure code for (2) is equivalent to the following statement, where My-Stack is a subtype of IStack (i.e., the type of iStack), making the cast from IStack to MyStack safe.

Click here to view code image

boolean isIntegerStack = iStack instanceof MyStack;   // (2′)

Given that T is a formal type parameter, the following code will not compile, as the arguments of the instanceof type comparison operator are non-reifiable types.

Click here to view code image

boolean isT      = obj instanceof T;                  // (3) Compile-time error!
boolean isTStack = obj instanceof MyStack<T>;         // (4) Compile-time error!

The post-erasure code for (2) and (3) is equivalent to the following statements. Again, casting the type Object to the types Object and MyStack, respectively, is not deemed safe at runtime.

Click here to view code image

boolean isT      = obj instanceof Object;             // (3′)
boolean isTStack = obj instanceof MyStack;            // (4′)

If we just wanted to determine that an instance was some stack, the instance test can be performed against the raw type or the unbounded wildcard parameterized type, as these types are reifiable:

Click here to view code image

boolean isRawStack = obj instanceof MyStack;
boolean isAnyStack = obj instanceof MyStack<?>;       // Preferable.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *