使用 instanceof 进行编译时检查

compile time check using instanceof

对于下面的代码,

package java_instanceof;

        /*
         *                   
         *                     Object                  I0 
         *   I1    I2         ^        \              . ^
         *     .    .         |         \           .   |
         *       .   .        |          \ ______ .     |
         *         .  .       C1          |__B___|     I3
         *           . .     /                      .        
         *             ..   /                   .            
         *               C2                  .              
         *                ^               .                                    
         *                |            .                   
         *                |        .                      
         *                |    .
         *                C3 
         *                                           
         */ 

interface I0{}; interface I1{}; interface I2 {};
interface I3 extends I0{};

class C1{}; class B implements I0{};
class C2 extends C1 implements I1, I2 {}
class C3 extends C2 implements I3 {}

public class Example {

    public static void main(String[] args) {


        Object o;  Object[]  oa;
        I0    i0;  I0[]      i0a;
        I1    i1;  I1[]      i1a; 
        I2    i2;  I2[]      i2a;
        I3    i3;  I3[]      i3a;
        C1    c1;  C1[]      c1a;
        C2    c2;  C2[]      c2a;
        C3    c3;  C3[]      c3a;
        B     b;   B[]        ba;

        //Compile time check
        boolean value1 = c3 instanceof B;  //compile time check error
        boolean value2 = b instanceof C3;  // compile time check error


    }

}

作为初学者,我想知道,javac 是如何引发编译时错误Incompatible conditional operand type 的?编译时是否知道完整的 class 层次结构?

!当然,层次结构,可能是 "implements" 或 "extends" 等在编译时是已知的。

如果没有这些检查,您将无法利用 OOPS,即使是在进一步深入您尝试编码的关系树中进行编程时也是如此。

考虑一个 Object Class 本身的例子,如果 Object 不是所有 class 的父对象,你可能无法覆盖toString()、hashcode()、clone() 基本上来自 Object Class 的方法。所以你在任何 IDE 的智能中得到这些方法,因此这些方法甚至在执行之前就已经预编译了。

是也不是。当然,编译文件及其导入的文件中所有 classes 和接口的 class 层次结构在编译时是已知的。但是,在 运行-time 可能会有额外的 classes 和接口。

然而,在您的情况下,C3B 都是 class,然后可用信息足以确定 c3 永远不能引用B 的实例和 b 永远不能引用 C3 的实例。之所以如此,是因为 classes 继承自单个(或者,在 Object 的情况下,没有)superclass.

有了接口,情况就不同了。以下片段不会导致编译时错误:

I1 i1 = ... ;
boolean v = i1 instanceof B;

因为有人可能会声明 B 的子 class,它也实现了 I1

是的,编译器首先查看方法的词法层次结构,然后是 class 层次结构,最后是全局范围。有关编译器工作原理的更多相关信息,您可以参考 Keith Cooper-Method 的书 "Engineering a Compiler" 和 class 调用主题。

对于您的第一个问题,您可能会发现此 http://codereply.com/answer/42s61x/instanceof-incompatible-conditional-operand-types.html 很有帮助。