【问题标题】:How do I extend Java interface containing generic methods in Scala?如何在 Scala 中扩展包含泛型方法的 Java 接口?
【发布时间】:2010-12-01 03:13:14
【问题描述】:

假设我们有以下 Java 接口:

// Java
public interface Foo {
    <T> T bar(Class<T> c);
}

我应该如何在 Scala 中扩展它?写作

// Scala
class FooString extends Foo {
  override def bar(c: Class[String]): String = "hello, world";
}

将导致编译器抛出“类 FooString 需要是抽象的,因为类型为 [T](Class[T])T 的特征 Foo 中的方法 bar 未定义。”

提前致谢!

更新: 丑陋的事实是:我误解了 Java 中的泛型。

无论如何,尼古拉斯和沃尔特的回答都显示了我的困境的解决方案,尽管我更喜欢沃尔特的回答,因为它不那么冗长。

【问题讨论】:

  • 你终于明白了!很高兴你已经理解了你在泛型上的错误。不客气。

标签: java scala generics interface type-parameter


【解决方案1】:

你可以这样改变:

public interface Foo<T> {
    T bar(Class<T> c);
}

class FooString extends Foo[String] {
    override def bar(c: Class[String]): String = "hello, world";
}

【讨论】:

  • 其实Java接口是第三方API,所以我只好照原样使用。
  • 据我所知,没有办法用特殊类型的方法覆盖泛型方法。
【解决方案2】:

这行得通:

class FooString extends Foo {
  def bar[String](c: Class[String]): String = "hello world".asInstanceOf[String]
}

val fs = new FooString
println(fs.bar(classOf[String]))

已编辑:

@Eastsun 的 cmets 是正确的。由于 bar 是带有类型参数 T 的泛型方法,因此在 Scala 中 bar 的实现也必须是泛型方法。我认为在 Scala 中实现 Foo 的正确方法如下:

class FooString extends Foo {
  def bar[T](c: Class[T]): T = c.newInstance.asInstanceOf[T] // c gotta have a default constructor
}

val fs = new FooString
println(fs.bar(classOf[String]).getClass) // prints "class java.lang.String"
println(fs.bar(classOf[java.util.Date]).getClass) // prints "class java.util.Date"

【讨论】:

  • 实际上,它并没有像您预期的那样工作。 FooString#bar 方法中的“String”不是 java.lang.String 类型,而是 Foo 中的“T”类型参数。因此,您可以编写 fs.bar(classOf[Int]) 之类的内容并编译 OK,但运行时出现异常。
【解决方案3】:

它不起作用,因为您没有正确实现接口。您的方法 n scala 的签名必须是:

def bar[T](c:Class[T]):T

只有当你想要 ton 实现 Foo 时,你才能修复 String 的行为。

第三次尝试,根据我们的讨论:

def bar[T](c:Class[T]):T = {
  // Some stuff
  val o:Any = myUntypedFunction(env)
  c.cast(o)
}

myUntypedFunction 将根据上下文创建一个对象,然后您使用类参数转换您的结果并获得一个 T 对象。 再说一遍:这种行为在 java 和 scala 中是一样的。

【讨论】:

  • 这是我的问题:如何使签名匹配?
  • 你不能。您尝试更改界面,这不是scala问题,而是编程问题。接口说:“接受任何类并返回这个类的结果”,你的实现说“接受任何字符串类并返回一个字符串”。 bar 的实现必须使用 cast()、newInstance 或构造函数从对象 c 构建一个 T。
  • 这只是一个人为的例子;我面临的实际问题需要我实现一个 Java 接口,该接口在方法中包含参数化类型,类似于我给出的示例。如果没有办法实现这一点,即使这可能是一个边缘情况,那么这是一个 scala 问题,因为它与 Java 不完全兼容。
  • 我不认为这是一个 scala 问题。在 Java 中你无法做到这一点。
  • @shaolang:如果您认为这是一个 scala 问题,您能否给我们您的 FooString 类的有效 java 等效代码?我仍然相信您错过了 bar 函数中泛型声明的要点。
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 2018-07-13
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-07
  • 1970-01-01
相关资源
最近更新 更多