使用 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 和接口。
然而,在您的情况下,C3
和 B
都是 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 很有帮助。
对于下面的代码,
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 和接口。
然而,在您的情况下,C3
和 B
都是 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 很有帮助。