【问题标题】:java generic ambiguityjava泛型歧义
【发布时间】:2013-03-13 03:24:57
【问题描述】:

如果有一个泛型类型node<E> 有两个操作,如setData(E Type)E getData() 并让s0 成为node 的实例node<? extends Number> 那么为什么编译器不允许我使用s0.setData(Number Type) 至少?我可以理解为什么不允许其他类型,但为什么不允许 setData 放入 Number 类型,因为我们确定节点的类型至少是 number?

我的代码如下所示:

class Node<E> {
private E data;
// ...
public void setData(E obj) { data = obj; } // (1)
public E getData() { return data; } // (2)
// ...
}
Node<? extends Number> s0 = new Node<Number>();
s0.setData(200); //this is not allowed why?
Node<Number> s0 = new Node<Number>();
s0.setData(100); //But this is allowed!

【问题讨论】:

  • 你是如何测试代码的?
  • 显示一些代码,很难理解你的意思。

标签: java wildcard bounded-wildcard


【解决方案1】:

您已将类型声明为 Node&lt;? extends Number&gt;。你分配给它的是无关紧要的。

就编译器而言,它可以是以下任何一种:

  • Node&lt;Integer&gt;
  • Node&lt;Float&gt;
  • Node&lt;Double&gt;

而且它无法知道实际类型是哪个类型。

您正在尝试传递(自动装箱的)Integer,但编译器无法知道 actual 类型可以接受 Integer

【讨论】:

  • 为什么不呢,我们不是告诉它它至少可以是一个数字或它的任何子类型 via 吗?扩展 Number 并且整数不是 Number 的子类型吗?
  • 为什么不呢?因为您可以将Node&lt;Float&gt; 分配给变量Node&lt;? extends Number&gt; s0。如果用Integer 调用Node&lt;Float&gt;setData() 方法,你认为会发生什么?
  • 参考我贴的代码,为什么我不能添加任何子类型?在同一类型中,当类型只是 Node 时,您可以执行 setData(200)
  • 不!类型不是Node&lt;Number&gt;!类型为Node&lt;? extends Number&gt;。您已分配 Node&lt;Number&gt;,但编译器仅查看已声明 类型。这一切都在我的回答中进行了解释 - 请仔细阅读。
【解决方案2】:

实质上:因为Node&lt;Integer&gt; 不是Node&lt;Double&gt;It is not even a Node&lt;Number&gt;.

例子:

Node<? extends Number> s0 = new Node<Integer> ();
s0.setData(Double.valueOf(2.0d)); //that's not possible...

实际上,因为我们不知道s0 的泛型类型是什么,所以除了null 之外,您将无法调用setData 方法...

【讨论】:

  • 但是我们不确定它至少可以是一个数字,那么为什么不允许输入一个数字呢?
  • @VishakhPC 在我的示例中,s0 实际上是整数,因此编译器没有理由允许您在其中添加 Doubles 或 BigDecimals。
【解决方案3】:

假设您有参考 Node&lt;? extends Fruits&gt; s0。这意味着它可以指向

Node<? extends Fruit> s0 = new Node<Fruit>; 

还有

Node<? extends Fruit> s0 = new Node<Apple>; 

Node<? extends Fruit> s0 = new Node<Banana>; 

您认为,将Fruit 添加到 Bananas 或 Apples 是否安全?还是香蕉变苹果?如果 Apple 和 Banana 包含 Fruit 没有的方法会怎样。

【讨论】:

  • 我们知道节点至少可以是水果,那么为什么不允许添加水果的子类型。为什么扩展不允许添加操作,只有超级允许?我总是可以执行 s0.setFruit(Apple) 并使用 getFruit() 将其取回我在哪里违反了类型安全?
  • 如果 Java 允许通过 Node&lt;? extends Fruit&gt; s0 添加任何水果,那么这意味着也可以将香蕉添加到苹果中。看看Node&lt;? extends Fruit&gt; s1 = new Node&lt;Apple&gt;; s1.add(new Banana()); 是正确的,因为Banana extends Fruit
猜你喜欢
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多