【问题标题】:Java Generics - Cannot convert from <? extends MyObject> to <MyObject> [duplicate]Java 泛型 - 无法从 <?将 MyObject> 扩展到 <MyObject> [重复]
【发布时间】:2015-01-24 19:48:28
【问题描述】:

为什么下面的代码会出现编译错误?

public MyObject(Builder<? extends MyObject> builder) {
    // Type mismatch: cannot convert from MyObject.Builder<capture#5-of ? extends MyObject> to MyObject.Builder<MyObject>
    Builder<MyObject> myObjBuilder = builder;
}

如果 Builder 类型是 MyObject 的子类,那么为什么不能将 builder 分配给只键入 MyObject 呢?我需要这样做,因为我无法将 MyObject 类型的对象与构建器一起使用。以这段代码为例:

public MyObject(Builder<? extends MyObject> builder) {
    // The method getData(capture#8-of ? extends MyObject) in the type Builder<capture#8-of ? extends MyObject> is not applicable for the arguments (MyObject)
    this.data = builder.getData(this);
}

我觉得应该允许这样做。或者我在这里错过了什么?有没有办法做到这一点,而无需将 builder 转换为 (Builder&lt;MyObject&gt;) 并且必须使用 @SuppressWarnings ?

另请注意,我需要 Builder 为 &lt;? extends MyObject&gt;,因为 MyObject 及其 Builder 将被子类化(因为它是抽象的)。

感谢您的帮助!

【问题讨论】:

标签: java generics


【解决方案1】:

因为Foo&lt;? extends Bar&gt; 不是Foo&lt;Bar&gt;

Foo有一个方法:

void add (T t)

那么按照约定,你只能添加T 对象。现在如果T 被实例化为? extends Bar,我们不知道类型。接受Bar 可能会导致问题行为:如果您有一个ArrayList&lt;Foo&gt;,您希望ArrayList 只包含Foo 实例。如果您将ArrayList&lt;Foo&gt; 视为ArrayList&lt;SuperFoo&gt;,则无法保证ArrayList&lt;Foo&gt; 仅包含Foo

某些语言启用covariance:如果您只使用T 作为输出,您可以说Foo&lt;T&gt;Foo&lt;SuperT&gt; 相同(与输入相同)。但目前 Java 不支持这一点。但是 C# 在接口级别上确实如此。

【讨论】:

  • 但是add(Object) 方法实际上确实 接受Object 的任何子类,不是吗?
  • @MCEmperor:是的子类。但是在这里你想“超类”它。因此,您想将ArrayList&lt;Integer&gt; 转换为ArrayList&lt;Object&gt;。这意味着add(Integer) 将接受Object。显然这是不可能的。
  • 我阅读了协方差和不变性,现在这一切对我来说都很有意义。但是,就我的情况而言,我知道对 MyObject 类型的 Builder 的强制转换在运行时将是类型安全的,所以我想即使它很丑也可以这样做。谢谢大家!
  • @User12345:当然,您可以进行显式类型转换,但是如果您在运行时将项目添加到ArrayList,您可能会收到错误,因此请仅在绝对必要时使用它.
猜你喜欢
  • 1970-01-01
  • 2019-11-05
  • 2021-11-17
  • 1970-01-01
  • 2021-08-06
  • 1970-01-01
  • 2021-10-12
  • 2014-10-08
  • 2017-10-17
相关资源
最近更新 更多