Scala:重写通用Java方法II

时间:2011-06-22 12:52:56

标签: scala scala-java-interop

在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方法。另外,我希望它首先引用 direct 超类。

如何编译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来电。

回应仍然是最受欢迎的。

2 个答案:

答案 0 :(得分:5)

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

但是,我在blog post早些时候曾指出,某些案件似乎有解决办法。诀窍是使用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)
    }
}

答案 1 :(得分:0)

2017年再次提出了关于同一问题的{p> The question

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

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

通过覆盖test()&#34;重命名&#34>创建其他Java类。它可以renameTest(),还可以通过ConcreteJava.test()方法调用超级concreteTest()

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)
  }
}