为什么 instanceof 有时不编译,有时 returns false?

Why instanceof sometimes doesn't compile and sometimes returns false?

在下面的例子中

但是

为什么?他们长得很像!

import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;

public class InstanceofTest {
    public static class Test {}
    public static void main(String[] args) {
        // -- left operand references a Class instance
        Test test = null;

        // 1. outputs: false
        System.out.println(test instanceof Map);

        // 2. COMPILATION ERROR
        System.out.println(test instanceof HashMap);


        // -- left operand references an Interface instance
        Map mymap = new HashMap();

        // 3. outputs: false
        System.out.println(mymap instanceof Set);

        // 4. outputs: false
        System.out.println(mymap instanceof HashSet);
    }
}

instanceof 运算符在 Java 中用于测试引用是否指向某个对象,该对象是特定 class 或接口的实例。

例如:

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

对于 null 引用,instanceof 总是 returns false

System.out.println(null instanceof Object); // false, null doesn't reference any object

有时编译器肯定知道引用永远不可能是特定 class 的实例,因为引用的类型不在特定 class 的层次结构树中。 例如,在以下示例中,编译器会报错: "不兼容的条件操作数类型 String 和 Map"

String myString="test string";
System.out.println(myString instanceof java.util.Map);

现在,事情变得有趣了。在下面的示例中,我们有一个 non final class Test 和一个 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); 
    }
}

为什么在 1. 中 return false,但在 2., 3., 4. 中不编译?

在 1. 中,我们正在针对 Interface (java.util.Map) 进行参考测试。编译器无法确定 test 不是 java.util.Map 的实例。事实上,测试可能会引用一个对象,该对象的 class 实现了 java.util.Map 并扩展了 class 测试。因此,没有编译错误,但在运行时 returns false。

在 2. 中,我们正在针对 Class 进行参考测试。在这种情况下,编译器可以确定 test 变量引用的对象不能扩展 java.util.Map,因为 Test class 不会扩展 java.util.Map,并且每个 subclass of Test 将扩展 class 测试(或其子 class 之一),因此它不能同时扩展 java.util.Map。

在 3. 中,我们正在针对 Interface 测试参考 testFinal。它看起来与 1. 类似,但它有很大不同,因为 class TestFinal 不能被 subclassed,所以 TestFinal 的实例不可能也是 java.util.Map 的实例.

在 4. 中,我们正在针对 Class 测试参考 testFinal。和2.一样,编译器可以确定testFinal变量引用的对象不能extend java.util.Map.

还有一个案例值得考虑:

    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);

在5.、6.中,myList是对Interface的引用,理论上可以存在一个实现了Map或者扩展了HashMap的List实例。

  1. 类似于1.

  2. 类似于2.

结论:

一个。 null instanceof AnyClass(或AnyInterface) 总是 returns false

乙。 myreferenceToAClass instanceof MyInterface 可能 return 真或假,取决于上下文

C。 myreferenceToAnInterface instanceof AnyClass(或AnyInterface) 可能 return 真或假,取决于上下文

D. myreferenceToAClass instanceof MyClass: - 如果 myreference 的 class 不属于 MyClass 的层次结构树,则会出现编译错误 - 如果 myreference 的 class 属于 MyClass 的层次结构树

,returns true 或 false,取决于上下文