【问题标题】:Why instanceof sometimes doesn't compile and sometimes returns false? [duplicate]为什么 instanceof 有时无法编译,有时返回 false? [复制]
【发布时间】:2017-01-07 08:34:40
【问题描述】:

在下面的例子中

  • test instanceof java.util.Map 返回 false

  • java.util.HashMap 的测试实例无法编译

但是

  • mymap instanceof Set 返回 false 和
  • mymap instanceof HashSet 返回 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);
    }
}

【问题讨论】:

    标签: java class inheritance interface instanceof


    【解决方案1】:

    instanceof 运算符在 Java 中用于测试引用是否指向作为特定类或接口实例的对象。

    例如:

    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 总是返回 false

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

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

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

    现在,事情变得有趣了。在下面的例子中,我们有一个非最终类Test和一个最终类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.中返回false,但在2.、3.、4.中编译不出来?

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

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

    在 3. 中,我们针对 Interface 测试参考 testFinal。看起来和 1. 很像,但又大不相同,因为 TestFinal 类不能被子类化,所以 TestFinal 的实例也不可能是 java.util.Map 的实例。

    在 4. 中,我们针对 Class 测试参考 testFinal。如2.,编译器可以确定testFinal变量引用的对象不能扩展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。

    结论:

    A. null instanceof AnyClass(或 AnyInterface)总是返回 false

    B. myreferenceToAClass instanceof MyInterface 可能返回 true 或 false,具体取决于上下文

    C. myreferenceToAnInterface instanceof AnyClass(或 AnyInterface)可能返回 true 或 false,具体取决于上下文

    D. myreferenceToAClass instanceof MyClass: - 如果 myreference 的类不属于 MyClass 的层次结构树,则编译错误 - 返回真或假,取决于上下文,如果 myreference 的类属于 MyClass 的层次结构树

    【讨论】:

    • 好奇你为什么发帖然后马上回答这个问题?
    • @WillMolter 这是一个self-answered question
    • 啊,我不熟悉立即这样做,而不是在困惑了一会儿之后
    • @WillMolter 在“发布您的问题”按钮下有一个复选框,“回答您自己的问题”。
    • 明确鼓励回答您自己的问题:blog.stackoverflow.com/2011/07/…
    猜你喜欢
    • 1970-01-01
    • 2021-03-23
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    • 1970-01-01
    • 2016-03-29
    • 2012-04-18
    相关资源
    最近更新 更多