views:

136

answers:

2

In the following code, the type of x is I (although x also implements J but thats not known at compile time) so why is it that the code at (1) doesn't result in a compile time error. Because at compile time only the type of the reference is considered.

public class MyClass {
    public static void main(String[] args) {
        I x = new D();
        if (x instanceof J) //(1)
            System.out.println("J");
    }
}

interface I {}

interface J {}

class C implements I {}

class D extends C implements J {}
+8  A: 

instanceof is used used for runtime determination of an object's type. You are trying to determine if x is really an object of type J when the program is running, so it compiles.

Were you thinking it should result in a compile-time error because you think the compiler does not know x's type?

Edit

As Kirk Woll has commented (thanks Kirk Woll!), if you were checking if x is an instanceof a concrete class, and the compiler can determine x's type, then you will get an error at compile time.

From the Java Language Specification:

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.

As an example of this:

import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;

class SerializableClass implements Serializable
{
   private writeObject(ObjectOutputStream out) {}
   private readObject(ObjectInputStream in) {}
}

public class DerivedSerializableClass extends SerializableClass
{
   public static void main(String[] args)
   {
      DerivedSerializableClass dsc = new DerivedSerializableClass();

      if (dsc instanceof DerivedSerializableClass) {} // fine
      if (dsc instanceof Serializable) {} // fine because check is done at runtime
      if (dsc instanceof String) {} // error because compiler knows dsc has no derivation from String in the hierarchy

      Object o = (Object)dsc;
      if (o instanceof DerivedSerializableClass) {} // fine because you made it Object, so runtime determination is necessary
   }
}
birryree
+1, and if it *weren't* a runtime operator, what on earth would be the point of it? The `if` statements using it would make no sense.
Kirk Woll
Well from what I read there is an initial compile time check when using the instanceof operator which determines if the source and destination have a subtype-supertype relationship. Then the actual object of the source is used to determine if the source is a subtype of Destination type.
Please correct my understanding on how this should work. So in this code although the object refered to by x is a subtype of J but there is no relation between I and J. So since x is of type I in the code above i.e I x = new D();, should this play a role at compile time?
@user439526, ah, that's what you mean. Good point. The reason you are not seeing a problem with your example is because you are using `instanceof` on *interfaces* and not on *classes*. The compiler can never know whether a given type *doesn't* implement an interface because a potential subclass could implement it. This is different with classes, as you point out, and if your example had used two incompatible classes rather than interfaces, you would indeed have gotten a compiler error.
Kirk Woll
could you illustrate this with an example
@user439526: Your sample code *is* an example. In this case, x is-a J since the actual type is D, which implements J. So not only should it compile, it should return true and `J` should be printed. An example of instanceof giving a compile error would be `String s; ... if (s instanceof Integer)`. The class hierarchies there are disjoint and the compiler knows that a String cannot be an Integer.
Mark Peters
OK so basically the compile time test is about determining weather the <source type> and <destination type> are in the same joint hierarchy and an error will be thrown if they are not?
@user439526: Yes, that is correct. If the compiler knows the object's type, it can determine if it could be an instance of any type of concrete class in the hierarchy at compile time.
birryree
+2  A: 

instanceof is a run-time operator, not compile-time, so it's being evaluated using the actual type of the object being referenced.

EboMike
But it can produce compile errors ...
EJP
Yeah, if it gets static input (i.e. classes rather than references). I should edit my answer, although kuropenguin already gave a very exhaustive answer, so that's moot.
EboMike