The instanceof operator is used in Java to test if a reference points to an object that is an instance of a specific class or interface.
For example:
String myString="test string";
System.out.println(myString instanceof String); // true, myString is a String
System.out.println(myString instanceof Object); // true, myString is a String, and so it is an Object, too
For null references, the instanceof always returns false:
System.out.println(null instanceof Object); // false, null doesn't reference any object
Sometimes the compiler knows for sure that a reference can never be an instance of a specific class, because the type of the reference it is not in the hierarchy tree of the specific class.
For example, in the following example the compiler complains:
"Incompatible conditional operand types String and Map"
String myString="test string";
System.out.println(myString instanceof java.util.Map);
Now, things get interesting. In the following example, we have one non final class Test and one final class TestFinal.
public class InstanceofTest {
public static class Test {}
public static final class TestFinal {}
public static void main(String[] args) {
Test test = null;
// 1. outputs: false
System.out.println(test instanceof java.util.Map);
// 2. COMPILATION ERROR
System.out.println(test instanceof java.util.HashMap);
TestFinal testFinal = null;
// 3. COMPILATION ERROR
System.out.println(testFinal instanceof java.util.Map);
// 4. COMPILATION ERROR
System.out.println(testFinal instanceof java.util.HashMap);
}
}
Why does it return false in 1., but it doesn't compile in 2., 3., 4.?
In 1., we are testing the reference test against an Interface (java.util.Map). The compiler cannot be sure that test isn't an instance of java.util.Map. In fact, it may happen that test references an object whose class implements java.util.Map and extends the class Test. So, there isn't a compilation error, but it returns false at runtime.
In 2., we are testing the reference test against a Class. In this case, the compiler can be sure that the object referenced by the test variable cannot extend java.util.Map, because Test class doesn't extend java.util.Map, and every subclass of Test will extend the class Test (or one of its subclasses), so it cannot extend java.util.Map at the same time.
In 3., we are testing the reference testFinal against an Interface. It looks similar to 1., but it's quite different, because the class TestFinal cannot be subclassed, so there's no way that an instance of TestFinal could be an instance of java.util.Map too.
In 4., we are testing the reference testFinal against a Class. As in 2., the compiler can be sure that the object referenced by the testFinal variable cannot extend java.util.Map.
There is still another case that is worth considering:
List myList = new ArrayList();
// 5. outputs: false
System.out.println(myList instanceof java.util.Map);
// 6. outputs: false
System.out.println(myList instanceof java.util.HashMap);
ArrayList myArrayList = new ArrayList();
// 7. outputs: false
System.out.println(myArrayList instanceof java.util.Map);
// 8. COMPILATION ERROR
System.out.println(myArrayList instanceof java.util.HashMap);
In 5., 6., myList is a reference to an Interface, theoretically it could exist an instance of List that implements Map or that extends HashMap.
is analogous to 1.
is analogous to 2.
Conclusion:
A. null instanceof AnyClass (or AnyInterface) always returns false
B. myreferenceToAClass instanceof MyInterface may return true or false, depending from the context
C. myreferenceToAnInterface instanceof AnyClass (or AnyInterface) may return true or false, depending from the context
D. myreferenceToAClass instanceof MyClass:
- compilation error if myreference's class doesn't belong to MyClass's hierarchy tree
- returns true or false, depending from the context, if myreference's class belongs to MyClass's hierarchy tree