curious on `instanceof` in Groovy/Java

87 Views Asked by At

I've encounter the instanceof issue in Groovy, and find the Class cannot be defined by variable, but isCase or isAssignableFrom works as expected.

Here are details :

// works
assert '' instanceof java.lang.String

// not working
Class clz = ''.getClass()
assert '' instanceof clz                 // ERROR: unable to resolve class clz
assert '' in clz                         // works

// debug info:
println clz                              // class java.lang.String
println clz.getClass()                   // class java.lang.Class

isCase() and isAssignableFrom() works, I assume because of those two are function

Class clz = ''.getClass()

// works
assert clz.isCase( '' )
assert clz.isCase( [] ) == false

// works
assert clz.isAssignableFrom( ''.getClass() )
assert clz.isAssignableFrom( [:].getClass() ) == false

But why instanceof cannot be using class-type variable ? by the way, groovy version is Groovy Version: 4.0.18 JVM: 21.0.2 Vendor: Homebrew OS: Mac OS X

2

There are 2 best solutions below

1
daggett On

https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.20.2

probably the best explanation is here ^^^

instanceof operator works at compile-time and at run-time. to make checks at compile time it requires exact class name.

more, since jdk 16 there is a new syntax (https://openjdk.org/jeps/394)

instead of

if (obj instanceof String) {
    String s = (String) obj;
    ...
}

you can use

if (obj instanceof String s) {
    ...
}

with this syntax it's obvious that you need exact type and not a class reference

1
Stephen C On

But why instanceof cannot be using class-type variable ?

If you are asking "why did they design instanceof with this restriction" ... the decisions were taken ~30 years ago, and (AFAIK) there is no extant publicly visible rationale for the design.

As noted in this answer the Java 16+ instanceof syntax extension relies on the type being known at compile time. So don't expect the restriction to be lifted.

If you need to do the equivalent of instanceof using a Class reference, you can use reflection to do it; see the Class API and the isInstance(Object) and T cast(Object) methods.

if (clz.isInstance(obj)) {
   ...
}

But once you have established that obj is an instance of some (dynamic) class, you stuck with the problem of how to use the instance. This can only be done reflectively. And if you think about it, that is another reason why supporting instanceof with Class references wouldn't be much help.