带有generics返回类型的方法中的Java编译错误

我无法解释为什么这个简单的代码不能编译。

class Foo {  T method() { return this; } } 

错误是: Type mismatch: cannot convert from Foo to T
为什么不? T被定义为Foo或其子类。

在相关的说明中,等效的Scala示例会进行编译,因此Java错误不是由于JVM的限制。

 class Foo { def method[T <: Foo] = this } 

更新:我在Java Tutorials中找到了关于generics方法的简明建议。

通用方法允许使用类型参数来表示方法和/或其返回类型的一个或多个参数的类型之间的依赖关系。 如果没有这种依赖关系,则不应使用通用方法。

我的解释是,通用方法仅适用于两种情况。

  1. 两个(或更多)方法的参数类型之间存在依赖关系。
  2. 方法的返回类型与其参数类型中的一个(或多个)之间存在依赖关系。

显然,有问题的简单代码在其参数和返回类型之间没有依赖关系,因为没有参数。 因此,通用方法是不合适的。


更新2:现在我已经意识到这一点,我在开源项目中注意到这种反模式的例子。

  • co.cask.cdap.api.data.DatasetContext.getDataset()
  • org.kitesdk.data.Datasets.load()
  • com.fasterxml.jackson.databind.ObjectMapper.valueToTree()

更新3:我想我已经找到了一个不涉及多个参数或返回类型的generics方法的要求。 多重inheritance似乎是Java教程中上述规则的一个例外。

  void method(T foobar) { // Call Foo method. // Call Bar method. } 

值得注意的是, Collectors实用程序类包括不带参数的toList()等通用方法。 在这种情况下,generics类型仅参数化返回类型,这可能比实际返回类型的generics类型更安全。

我认为你误解了Javagenerics如何工作:

  T method() { 

这意味着该方法的调用者可以选择他们想要的任何Foo子类型并请求它。 例如,你可以写

 Foo foo = new Foo(); SubFoo subfoo = foo.method(); 

…并期望返回SubFoo ,但是您的method实现无法返回SubFoo ,而这必须失败。 (我不会说Scala,但我认为这意味着你的Scala实现实际上并不是“等效的”。)

如果你希望你的方法能够返回实现选择的Foo子类型,而不是调用者,那么只需写

 Foo method() { return this; }