• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

instanceof operator with an interface versus class

 
Thomas Hauck
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Why does compilation for an unrelated interface succeed when using the 'instanceof' operator
but not for class?


For the code below in Example 1,



compiles even though reference variable 'c' has no relation to interface 'X'.

When the same operation is attempted with class 'A',
('c' has no relation to class 'A'), the compilation will not succeed.






Example 1:


Question: Does this have to do with the fact that an interface is purely abstract?
 
Paul Clapham
Sheriff
Posts: 21551
33
Eclipse IDE Firefox Browser MySQL Database
  • Likes 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No, it isn't. At your "// line 2" all the compiler knows is that variable c can be assigned to type C, which is a non-final class. So it's possible that it actually refers to an object of some class D, a subclass of C which implements the interface X. And since that's a possibility, there's no reason to reject it.

On the other hand if C were a final class, then that possibility wouldn't exist and the compiler would fail that line of code. Try it and see.
 
Henry Wong
author
Marshal
Pie
Posts: 22089
88
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thomas Hauck wrote:Why does compilation for an unrelated interface succeed when using the 'instanceof' operator
but not for class?


For the code below in Example 1,



compiles even though reference variable 'c' has no relation to interface 'X'.


What if we change your code somewhat like this?



Then shouldn't those two lines compile?

Henry
 
Thomas Hauck
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the reply.

I have changed the original Example 1 above and
placed the object creation within TestClass in Example 2.

I. My first observation is 'class C' is independent of
1. interface X and
2. class A.

In example 2, 'class C'

1) does not extend A
2) does not implement X .

Is this observation correct?
----- ----- ----- -----
II. Next observation is that reference variable 'c' of class C,
has no relationship to interface X and will compile when used with the instanceof operator on line 2 .

Is this correct?

--------
III. Reference variable 'c' of class C has no relationship to class A and will not compile when used with the instanceof operator on line 1.
if (c instanceof A) // line 1 // compilation fails
System.out.println("c is a A");
--------

Example 2:


I wanted to generalize these results to determine if

a) when instanceof is used with an unrelated interface this code will compile. // line 2
b) When instanceof is used with an unrelated class this code will not compile. //line 1

Question: Are statements a) and b) above supported by the code in Example 2?


Thanks in advance.
 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thomas Hauck wrote:I wanted to generalize these results to determine if

The general conclusion when someExpression instanceof ReferenceType will result in a compiler error is: If a cast of the someExpression 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 (based on JLS 15.20.2. Type Comparison Operator instanceof).

First an obvious example of a compiler error (Incompatible conditional operand types String and Number):

Because the cast (Number) "foo" results in a compiler error, so must the expression "foo" instanceof Number

A more subtle example of a simillar compiler error (Incompatible conditional operand types Integer and Cloneable):

Reason why:
  • Integer is a final class
  • Integer does not implement Cloneable
  • So you can't do (Cloneable) anInteger
  • Thus anInteger instanceof Cloneable will also not compile


  • But this example compiles without any problem:

    Reason why: the Number class is not final, so there could be a subclass that implements the Cloneable interface. That's also why (Cloneable) aNumber will compile (but will throw a ClassCastException at runtime).

    An example with 2 unrelated classes will always result in compiler error (similar to the 1st obvious example):


    Hope it helps!
    Kind regards,
    Roel
     
    John Lerry
    Ranch Hand
    Posts: 145
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I would just be sure you have got it right.

    Roel De Nijs wrote:
    But this example compiles without any problem:

    Reason why: the Number class is not final, so there could be a subclass that implements the Cloneable interface. That's also why (Cloneable) aNumber will compile (but will throw a ClassCastException at runtime).


    The code compiles as the Number class is NOT final and then MAY (not sure that it does) implement the interface Cloneable but then a ClassCastException is throws because the JVM sees that the type of the object is an Integer that is a class final and therefore could not implement the interface Cloneable (type cast).
    Is that correct?

    Roel De Nijs wrote:
    An example with 2 unrelated classes will always result in compiler error (similar to the 1st obvious example):



    The code does not compile because the class Fish is not in the same class hierarchy Car.
    Is that correct?
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    John Lerry wrote:The code compiles as the Number class is NOT final and then MAY (not sure that it does) implement the interface Cloneable but then a ClassCastException is throws because the JVM sees that the type of the object is an Integer that is a class final and therefore could not implement the interface Cloneable (type cast).
    Is that correct?

    Almost, you are very close! Because Integer IS-NOT-A Cloneable, the JVM throws a ClassCastException at runtime. It doesn't matter if the Integer class is final or not, it only matters if the Integer class implement the Cloneable interface. Because it doesn't, you'll get the ClassCastException at runtime.

    Just to be complete: If a class is not final, other classes can extend from this class and you can implement any interface you want. So you could create for example this classAnd then you could write this code:That's why you don't get a compiler error if your class isn't final. If the class is final, you can't create any subclasses (which could implement an interface which wasn't implemented by the super class).

    John Lerry wrote:The code does not compile because the class Fish is not in the same class hierarchy Car.
    Is that correct?

    Spot-on!

    Hope it helps!
    Kind regards,
    Roel
     
    John Lerry
    Ranch Hand
    Posts: 145
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Let's see if I understand:



    I try to analyze this code. The code does not return an compile time error because the reference (n) is of type Number that is NOT a final class.
    Not even return a runtime error because the object is of type MyCoolNumber that actually implements the interface Cloneable.
    Therefore control on the type of class (so if final or not) occurs at compile time while the control on the implementation of interface (if it happens or not) occurs at runtime.

    Is that correct?
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    John Lerry wrote:I try to analyze this code. The code does not return an compile time error because the reference (n) is of type Number that is NOT a final class.
    Not even return a runtime error because the object is of type MyCoolNumber that actually implements the interface Cloneable.
    Therefore control on the type of class (so if final or not) occurs at compile time while the control on the implementation of interface (if it happens or not) occurs at runtime.

    Is that correct?

    The 1st and 3rd statements are absolutely correct! The 2nd isn't, because you'll never get a runtime exception when you use the instanceof operator: if the object is an instance of the type, the expression evaulates to true, false otherwise. Casting is a risky operation (as you know by now), so to prevent runtime exceptions from occuring, you should use the instanceof operator to verify if the cast is ok (true is returned) or not (false is returned).
    Have a look at this code snippet:Some observations about this code:
  • no compiler error, because class Number is not final (as you mentioned in your 1st statement)
  • line1 will always print true or false, depending if the subclass of Number implements Cloneable or not. line1 will never throw a runtime ClassCastException
  • line2 throws a runtime ClassCastException if the subclass of Number doesn't implement Cloneable (as you mentioned in your 2nd statement). line2 will print to the console (and not throw the runtime ClassCastException) if the subclass of Number implements Cloneable


  • Hope it helps!
    Kind regards,
    Roel
     
    John Lerry
    Ranch Hand
    Posts: 145
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    putting a moment by the instanceof operator, we understand that avoids that there is an exception at runtime, I would understand if I have understood the concept.

    I would like to better analyze this code:


    In general you can make a cast between a class and an interface if the class is NOT declared final, otherwise there will be an error in compilation.
    Also should be checked whether or not the class implements the interface.
    In the specific example the object is of type MyCoolNumber that implements the interface (Cloneable) then cast from MyCoolNumber to Cloneable not throw an exception at runtime.

    Is it correct?
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    John Lerry wrote:In general you can make a cast between a class and an interface if the class is NOT declared final, otherwise there will be an error in compilation.

    True! Example:

    John Lerry wrote:Also should be checked whether or not the class implements the interface.

    Indeed! If you want to safely perform a cast, you should always first perform an instanceof check first. Example:

    John Lerry wrote:In the specific example the object is of type MyCoolNumber that implements the interface (Cloneable) then cast from MyCoolNumber to Cloneable not throw an exception at runtime.

    Exactly! And in this example there was no need to verify if the cast would have been valid, because reference variable n refers to a MyCoolNumber instance (which obviously implement Cloneable). But for example in this code, it's really needed if you want to safely cast without the risk of a runtime exception being thrown.

    Hope it helps!
    Kind regards,
    Roel
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic