Java/Scala 有界泛型和类型推断不匹配

5

作为一个有Java背景的人,我知道这段代码无法编译。

public static class SuperClass {}
public static class SubClass extends SuperClass {}

public static <T, U extends T> U returnSub(T sup, U sub) {
    return sub;
}

public static void main(String[] args) {
    SuperClass parent = new SuperClass();
    SubClass child = new SubClass();

    returnSub(parent, child);
    returnSub(child, parent); // Java doesn't like that
}

最后一行产生了编译错误(编辑:至少在jdk1.6.0_65上),它是这样的:
绑定不匹配:类型Test的通用方法returnSub(T,U)对参数(Test.SubClass,Test.SuperClass)不适用。 推断的类型Test.SuperClass不是受限制的参数的有效替代品。
所以我很惊讶,这似乎在Scala中起作用。 我编写了下面的示例代码(据我所知,表达相同的“逻辑”):
class SuperClass
class SubClass extends SuperClass

def returnSub[Type, SubType <: Type](supArg: Type, subArg: SubType): SubType = {
  subArg
}

override def main(args: Array[String]): Unit = {
  val parent = new SuperClass()
  val child = new SubClass()

  val iAmOkWithThat: SubClass = returnSub(parent, child)
  val iDontGetThat: SuperClass = returnSub(child, parent)
}

我猜Scala编译器非常聪明,它会说:“好的,child是SubClass的一个实例,但如果我这么说,我就不能调用returnSub了,所以让我尝试将child视为SuperClass实例,好吧,它起作用了,那就这么做吧。”

是这样的吗(如果是,您能指出有关此事的语言规范吗)?或者我的Scala“转换”与Java代码不等价吗?

谢谢!


它应该适用于Java和Scala,因为TU都可以是SuperClass。我尝试了你的Java程序,并且使用jdk1.8.0_25编译和运行都非常完美。你为什么认为Java不喜欢它呢? - Paul Boddington
我只有一个旧版的Java。可能是因为它是jdk 1.6.0_65版本。已经进行了编辑以反映这一点。 - GPI
2
类型推断自1.6版本以来已经大幅改进。您可以通过执行ThisClass.<SuperClass, SuperClass>returnSub(child, parent);在Java 1.5及以上版本上使其正常工作。 - Paul Boddington
在相同的JDK上运行,Scala编译器(2.11.7)不需要额外的推断信息。尽管如此,您的建议确实有效,并使1.6 javac“满意”。感谢您指出这一点。请随意将其编辑为答案。 - GPI
1个回答

2

你的代码应该适用于两种语言,因为TU都可以是SuperClass。使用Java 1.8,你的代码可以编译通过。自从引入泛型以来,类型推断已经得到了很大的改进,但是你可以通过编写以下内容使其适用于从1.5版本开始的所有Java版本。

ThisClass.<SuperClass, SuperClass>returnSub(child, parent);

现在你只需要很少频繁地提供显式类型参数。

至于为什么在Scala中不会出现相同的问题,我很抱歉无法回答,因为我完全不了解Scala。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接