Considering the following code, I don't understand why "System.out.println( c2 instanceof D);"
will result an "illegal compile time error" but not return "false"? Many thanks for your help!
interface I { }
class A { int x = 1;}
class B extends A implements I { int y = 2;}
class C extends B { }
class D extends B{ }
class E implements I { }
C c2 = new C();`
The error from Java 8 is:
error: incompatible types: C cannot be converted to D
And indeed, C
and D
are not in the same lineage (other than both being Object
). Since the compiler can tell you at compilation time that the instanceof
will never be true, it does. The earlier a problem is caught, the better; the compiler is preventing your having code that is unnecessary or a condition that will never be satisfied. It's like the error you get when you have code that can never be reached because the logic is unambiguous and never allows execution of the code (error: unreachable statement
).
Here's a complete example:
public class Example {
interface I { }
static class A { int x = 1;}
static class B extends A implements I { int y = 2;}
static class C extends B { }
static class D extends B{ }
static class E implements I { }
public static final void main(String[] args) {
C c2 = new C();
System.out.println(c2 instanceof D);
}
}
Which fails with:
Example.java:12: error: incompatible types: C cannot be converted to D
System.out.println(c2 instanceof D);
But, if you make it so the compiler can't know for sure that the instanceof
will always be false, then it does indeed compile and you get false
at runtime:
public class Example {
interface I { }
static class A { int x = 1;}
static class B extends A implements I { int y = 2;}
static class C extends B { }
static class D extends B{ }
static class E implements I { }
public static final void main(String[] args) {
C c2 = new C();
doTheCheck(c2);
}
static void doTheCheck(Object o) {
System.out.println(o instanceof D);
}
}
Since what we're checking, o
, could be anything, the compiler doesn't alert you to the invariant check, the code compiles, and you get false
as output.
Because compiler knows that casting c2
to type D
will always doing to fail at runtime, and hence is marked as compile time error. So it doesn't allow such instanceof
to pass through.
Quoting JLS §15.20.2:
If a cast (§15.16) of the RelationalExpression to the ReferenceType would be rejected as a compile-time error, then the instanceof relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof expression could never be true.
Thats because compiler can check at compile time that such instanceof
would always return false, you can read on it in JLS:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2
If a cast of the RelationalExpression to the ReferenceType would be
rejected as a compile-time error, then the instanceof relational
expression likewise produces a compile-time error. In such a
situation, the result of the instanceof expression could never be
true.
RelationalExpression is first operand, and ReferenceType is second: RelationalExpression instanceof ReferenceType