[英]Java generics and the instanceof keyword
所以,我正在查看Oracle Java教程,特别是这段代码;
List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35)); // compile-time error
可以在这里找到。 这是我的理解(并且请纠正我,如果我错了)上面的代码将无法工作,因为编译器不知道ln
引用了EvenNumbers列表,因此这可以防止您意外添加任何可能是列表的元素的超类型。 如果是这种情况,那么为什么如果你有一个像Number num = new Integer(6);
这样的语句呢Number num = new Integer(6);
如果编写if语句,编译器能够正确地确定num是一个Integer对象; if (num instanceof Integer) {...}
?
我想我的问题是,编译器如何能够确定num
在第二个示例中引用了Integer
对象,但是在第一个示例中无法确定ln
是否引用了List<EvenNumber>
对象?
你的两个例子是彼此相反的。
Integer
是一个Number
,所以
List<Number> list;
list.add(new Integer(1)); // compiles
但EvenNumber
是一个NaturalNumber
, 而不是相反 ,所以
List<EvenNumber> list;
list.add(new NaturalNumber(1)); // compile error
因为当EvenNumber
是一个NaturalNumber
, NaturalNumber
不是 (一定)的EvenNumber
。
如果在参考案例中交换Integer
和Number
然后重做它,它应该是有意义的,即这将编译:
List<NaturalNumber> list;
list.add(new EvenNumber(2)); // compiles OK
通常,编译器能够确定很多东西,并在优化代码时使用其观察结果。
但是,Java是静态和强类型的语言,编译器在类型安全方面没有自由。
1)禁止添加到ln
列表,因为人们不确切地知道它应该包含哪种类型的元素。 在您的示例中,此规则阻止将列表置于无效状态。
2) “......编译器能够正确地确定num是一个整数......”
不是这样,编译器不能确定它(尽管如果Java是弱类型语言的话)。
3) num instanceof Integer
这是在运行时评估的,而不是在编译时评估的。 但是,以下将产生编译时错误:
num instanceof String
因为Number
永远不能是String
。
这是无法编译的主要原因是由于这种方式? extends T
? extends T
表现。 一般来说,人们应该熟悉Producer Extends,Consumer Super或PECS。
现在,我还没有看过这个特殊的代码示例,但我认为EvenNumber
的层次结构扩展了NaturalNumber
。 这使得赋值语句有效,因为EvenNumber
是一个NaturalNumber
(尽管我打赌数学家们正在NaturalNumber
这个)。
在上面突出显示的场景中,您无法向集合中添加任何内容的原因是它主要用于读取。 也就是说,列表是生产者 ,因此它与extends
绑定。
如果您想要读取和写入集合,您只需要保留通配符。
你的第二个例子与泛型完全无关 ,而是简单的继承。 由于Integer
继承自Number
,我们可以说Integer
是一个Number
,因此可以被视为一个数字。 任何继承的类都具有此功能。 检查Liskov替代原则以获取更多信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.