为什么 instanceof 有时不能编译,有时返回false?

3
在下面的例子中:
  • test instanceof java.util.Map 返回false

  • test instanceof 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);
    }
}
1个回答

6

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

例如:

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.中,我们正在将引用测试与一个接口(java.util.Map)进行比较。编译器不能确定test不是java.util.Map的实例。事实上,可能发生的情况是test引用了一个类实现了java.util.Map并扩展了Test类的对象。因此,没有编译错误,但在运行时返回false。
在2.中,我们正在将引用测试与一个类进行比较。在这种情况下,编译器可以确定由test变量引用的对象不能扩展java.util.Map,因为Test类没有扩展java.util.Map,并且Test的每个子类都将扩展Test类(或其子类之一),因此它不能同时扩展java.util.Map。
在3.中,我们正在将引用testFinal与一个接口进行比较。它看起来与1.相似,但却非常不同,因为TestFinal类无法被子类化,因此TestFinal的实例也无法是java.util.Map的实例。
在4.中,我们正在将引用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是对接口的引用。理论上,可能存在实现Map或扩展HashMap的List的实例。
7.类比于1。 8.类比于2。
结论:
A. null instanceof AnyClass(或AnyInterface)总是返回false。 B. myreferenceToAClass instanceof MyInterface根据上下文可能返回true或false。 C. myreferenceToAnInterface instanceof AnyClass(或AnyInterface)根据上下文可能返回true或false。 D. 如果myreference的类不属于MyClass的层次结构树,则编译错误;如果myreference的类属于MyClass的层次结构树,则根据上下文返回true或false。

你为什么会在发布问题后立即回答它呢? - Will Molter
1
@WillMolter 这是一个自问自答的问题 - Andy Turner
啊,我不太熟悉立刻这样做,而不是再纠结一会儿。 - Will Molter
@WillMolter 在“发布您的问题”按钮下面有一个复选框,“回答您自己的问题”。 - Andy Turner
鼓励自问自答:http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/ - Luigi Rubino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接