【问题标题】:Incompatible types when using static method generics使用静态方法泛型时不兼容的类型
【发布时间】:2019-01-10 05:13:42
【问题描述】:

当我尝试编译以下代码时,编译失败并出现以下错误。我不确定为什么应该这样做,因为我只返回一个实现合同的类

public interface Contract {
  static <T extends Contract> T get() {
    return new ConcreteContract();
  }
}

class ConcreteContract implements Contract {
}

Contract.java:3: error: incompatible types: ConcreteContract cannot be converted to T
    return new ConcreteContract();
           ^
  where T is a type-variable:
    T extends Contract declared in method <T>get()
1 error

有没有人知道为什么 java 会这样(或者)我错过了一些明显的东西

PS:在发布此查询之前,我已经阅读了超过 10 个 SO 的热门搜索

【问题讨论】:

  • 您忘记了“以下错误”消息
  • @AshokKoyi 你的工厂知道它正在实例化 ConcreteClass,因为它所做的 new 是 new ConcreteClass()。这并没有改变它应该声明它正在返回的内容
  • @AshokKoyi 我不知道你在说什么。但是当你说你返回 T 时,你并不是说你返回 Contract。写不同的东西会产生不同的含义。
  • @AshokKoyi 这里是另一个相关主题 - 我认为这是您误解的核心:stackoverflow.com/q/4231305/2513200 - 在定义 Java 的泛型时做出的基本设计决策,特别是选择调用站点差异

标签: java generics static-methods


【解决方案1】:

由于您的方法返回一个泛型类型T,而T 可以是任何实现Contract 的类,因此可以使用以下方法调用(例如):

OtherConcreteContract variable = Contract.get();

并且您不能将ConcreteContract 分配给OtherConcreteContract 变量(假设ConcreteContract 不是OtherConcreteContract 的子类)。

为避免该错误,您应该返回接口类型:

static Contract get() {
    return new ConcreteContract();
}

或具体类型:

static ConcreteContract get() {
    return new ConcreteContract();
}

前者(返回接口类型)通常是更好的选择。

泛型在这里帮不了你。

【讨论】:

  • @AshokKoyi 当您让您的方法具有通用返回类型时,您允许方法的调用者决定该类型是什么。因此,您的方法必须返回一个与调用者可能做出的任何选择相匹配的实例。如果调用者选择将此方法的结果分配给其他类型的变量(也实现接口),则返回 ConcreteContract 实例不起作用。
  • new ArrayList&lt;&gt; 对运行时没有影响,它只是让你不必重复你已经用变量类型声明的内容,隐含地考虑到如果你使用 &lt;&gt; 代替的是相同的泛型类型具体的。在您的情况下,您正在调用一个方法。如果你不向它提供在运行时告诉它的参数,这个方法就无法猜测它的调用者想让你做什么。
  • @AshokKoyi 泛型和推理不仅仅是或多或少的聪明。 Java 的泛型是一个完全编译时的类型安全验证工具,而大多数语言将它们的泛型定义为运行时工具,这有其优点和不便之处。但无论如何,如果您更喜欢 typescript 而不是 Java,那么直接使用它是一个非常好的选择。
  • @AshokKoyi 除非您希望编译器将其作为 Contract 类型的返回类型,否则您只需将返回类型设为“Contract”而不是通用“T”。除了你想要做的事情之外,没有任何逻辑可以做。
  • 泛型除了让编译器拒绝这样的程序之外别无他用。它们的存在纯粹是为了帮助确保类型安全,并且您坚持不关心类型安全,因此不尊重它。因此,泛型仅存在于您正在做的事情被拒绝。编译器绝对不知道它在运行时是有效的,因为如果调用者期待一个 OtherConcreteClass,它很可能在运行时无效,这显然会失败。该消息很有帮助:事实上,ConcreteClass 不能转换为 T,它就是这么说的。
【解决方案2】:

你需要将最终的返回类型强制转换为类型 T。

您指定 if T 必须是 Contract 或其子类。表示您正在限制将用作泛型的类型。

在返回时,您应该严格遵守在使用时定义的泛型类型,这就是编译器抱怨您返回类型 T 而不是您要返回的内容的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-11
    • 2010-10-16
    • 2012-02-10
    • 1970-01-01
    • 2015-03-09
    • 1970-01-01
    相关资源
    最近更新 更多