15

在 Scala 中,我需要覆盖以下给定的 Java 类和方法:

public abstract class AbstractJava<T> {
    protected abstract T test(Class<? extends T> clazz);
}

public class ConcreteJava extends AbstractJava<Object> {
    @Override
    protected Object test(Class<?> clazz) {
        return null;
    }
}

// Scala
class ConcreteScala extends ConcreteJava {
    protected override def test(clazz: Class[_ <: AnyRef]): AnyRef =
        super.test(clazz)
}

我收到编译错误:

error: ambiguous reference to overloaded definition,

both method test in class ConcreteJava of type 
(clazz: java.lang.Class[_])java.lang.Object

and method test in class AbstractJava of type 
(clazz: java.lang.Class[_ <: java.lang.Object])java.lang.Object

match argument types (Class[_$1]) and expected result type AnyRef

super.test(clazz)

我不希望 Scala 编译器在调用时引用abstract方法。super另外,我希望它首先引用直接超类。

如何使 Scala 类编译?

谢谢!

编辑:

挂断super.test(clazz)电话时,会出现以下错误消息:

error: name clash between defined and inherited member:

method test:(clazz: Class[_ <: AnyRef])AnyRef and
method test:(clazz: java.lang.Class[_])java.lang.Object in class ConcreteJava

have same type after erasure: (clazz: java.lang.Class)java.lang.Object

protected override def test(clazz: Class[_ <: AnyRef]): AnyRef = null

好吧,当然这些是相同的类型(或变体)......!- 所以Scala / Java继承有问题......

感谢michid,有一个初步的解决方案:

class ConcreteScala3 {
  this: ConcreteJava =>
  protected override def test(clazz: Class[_ <: AnyRef]): AnyRef = {
    this.foo() // method of ConcreteJava
    null
  }
}

虽然我们不能super从这里打电话。

仍然是最受欢迎的。

4

2 回答 2

5

使用原始类型覆盖 Java 方法时存在一些限制。请参阅相应的Scala 票证。特别是 Martin Odersky 的评论:“[...] 在这些情况下唯一可以做的就是在 Java 中实现一个子类来实现该方法。[...]”

但是,我在之前的一篇博文中指出,似乎有针对某些情况的解决方案。诀窍是使用 Java 端原始类型的存在类型显式声明覆盖 Scala 类的 self 类型。

使用这种技术,我得到了以下工作:

public abstract class AbstractJava<T> {
    protected abstract T test(Class<T> clazz);
}

public class ConcreteJava extends AbstractJava<Object> {
    @Override
    protected Object test(Class<Object> clazz) {
        return null;
    }
}

class ConcreteScala extends ConcreteJava {
    this: AbstractJava[AnyRef] =>

    protected override def test(clazz: Class[AnyRef]): AnyRef = {
        super.test(clazz)
    }
}
于 2011-06-22T20:27:02.560 回答
0

2017年再次提出同样的问题

我认为这肯定是一个错误,我创建了一个问题SI-10155

您可以应用以下解决方法。

创建额外的 Java 类,通过重写test()“重命名”它,renameTest()并提供ConcreteJava.test()通过concreteTest()方法调用 super 的能力。

public abstract class RenameJava extends ConcreteJava {
    public Object concreteTest(Class<?> c) {
        return super.test(c);
    }

    abstract protected Object renameTest(Class<?> c);

    @Override
    protected Object test(Class<?> c) {
        return renameTest(c);
    }
}

现在在ConcreteScala课堂上你可以覆盖renameTest()并且你仍然可以ConcreteJava.test()使用方法调用超级concreteTest()方法。

class ConcreteScala extends RenameJava {
  override protected def renameTest(c: Class[_]) = {
    // custom logic
    concreteTest(c)
  }
}
于 2017-01-19T22:55:42.833 回答