繁体   English   中英

Java泛型和instanceof关键字

[英]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是一个NaturalNumberNaturalNumber 不是 (一定)的EvenNumber

如果在参考案例中交换IntegerNumber然后重做它,它应该是有意义的,即这将编译:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM