使用静态方法泛型时不兼容的类型

Ash*_*oyi 0 java generics static-methods

当我尝试编译以下代码时,编译失败并出现以下错误.我不知道为什么它应该,因为我只返回一个实现合同的类

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

class ConcreteContract implements Contract {
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

有没有人知道为什么java表现这种方式(或)我错过了一些明显的东西

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

Era*_*ran 7

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

OtherConcreteContract variable = Contract.get();
Run Code Online (Sandbox Code Playgroud)

并且您不能将a赋值ConcreteContractOtherConcreteContract变量(假设ConcreteContract不是子类OtherConcreteContract).

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

static Contract get() {
    return new ConcreteContract();
}
Run Code Online (Sandbox Code Playgroud)

或具体类型:

static ConcreteContract get() {
    return new ConcreteContract();
}
Run Code Online (Sandbox Code Playgroud)

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

仿制药在这里没有帮助你.

  • @AshokKoyi当你让你的方法有一个泛型返回类型时,你允许方法的调用者决定那个类型是什么.因此,您的方法必须返回一个匹配调用者可能做出的任何选择的实例.如果调用者选择将此方法的结果分配给某个其他类型的变量(也实现接口),则返回`ConcreteContract`实例不起作用. (3认同)
  • `new ArrayList <>`对运行时没有影响,它只是让你不再重复已经用变量类型声明的东西,如果你使用`<>`而不是具体的话,隐式地认为你的意思是相同的泛型类型.在你的情况下,你正在调用一种方法.如果您没有为其提供在运行时告诉它的参数,则此方法无法猜测其调用者希望您执行的操作. (2认同)
  • @AshokKoyi更多的是泛型和推理,而不仅仅是或多或少聪明.Java的泛型是一种完全编译时类型的安全验证工具,而大多数语言将其泛型定义为运行时工具,具有其优点和不便之处.但无论如何,如果你更喜欢打字稿而不是Java,那么只需使用它就是一个非常好的选择. (2认同)
  • 泛型没有其他目的,只有编译器拒绝这样的程序.它们的存在纯粹是为了帮助确保类型安全,而且你坚持不关心类型安全,因此不尊重它.因此,仿制药只存在于您所做的事情被拒绝.编译器绝对不能知道它在运行时是有效的,因为如果调用者期望一个显然会失败的OtherConcreteClass,它在运行时很可能无效.该消息很有用:事实上,ConcreteClass无法转换为T,它就是这样说的. (2认同)