Scala:重写通用 Java 方法 II
在 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
方法>超级调用。另外,我希望它首先引用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
调用。
仍然非常欢迎回复。
In Scala, I need to override the following, given, Java classes and methods:
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)
}
I'm getting the compilation error:
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)
I wouldn't expect the Scala compiler to refer to an abstract
method on a super
call. Also, I'd expect it to refer to the direct super class first.
How can I make the Scala class compile?
Thanks!
Edit:
When leaving off the super.test(clazz)
call, there'll be the error message:
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
Well, of course these are the same types (or variants) ...! - So there's something wrong with Scala/Java inheritance ...
Thanks to michid, there's a preliminary solution:
class ConcreteScala3 {
this: ConcreteJava =>
protected override def test(clazz: Class[_ <: AnyRef]): AnyRef = {
this.foo() // method of ConcreteJava
null
}
}
although we can't make super
calls from here.
Responses are still most welcome.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用原始类型覆盖 Java 方法时存在一些限制。请参阅相应的 Scala 票证。具体来说,Martin Odersky 的 comment: "[...] 在这些情况下唯一能做的就是实现一个子类实现该方法的 Java [...]”
但是,我在 博客文章 之前提到,对于某些情况似乎有解决方案。技巧是使用 Java 端原始类型的存在类型显式声明重写 Scala 类的 self 类型。
通过这种技术,我得到了以下工作:
There are some limitations when overriding Java methods with raw types. See the corresponding Scala ticket. Specifically Martin Odersky's comment: "[...] The only thing one can do in these situations is implement a subclass in Java that implements the method. [...]"
However, I pointed out in a blog post earlier that there seems to be a solution for certain cases. The trick is to explicitly declare the self type of the overriding Scala class using an existential type for the raw type on the Java side.
With this technique I got the following working:
关于同一问题的问题在2017年再次提出。
我认为这肯定是一个错误,我创建了一个问题< a href="https://issues.scala-lang.org/browse/SI-10155" rel="nofollow noreferrer">SI-10155。
您可以应用以下解决方法。
创建额外的 Java 类,通过重写
test()
将其“重命名”为renameTest()
,并且还提供调用超级ConcreteJava.test()
的能力> 通过concreteTest()
方法。现在,在
ConcreteScala
类中,您可以重写renameTest()
并且仍然可以使用调用超级
ConcreteJava.test()
方法具体测试()方法。The question about the same issue was raised again in 2017.
I think that this is certainly a bug and I created an issue SI-10155.
You can apply the following workaround.
Create additional Java class that by overriding
test()
"renames" it torenameTest()
and also provides ability to call superConcreteJava.test()
throughconcreteTest()
method.Now in
ConcreteScala
class you can overriderenameTest()
and you're still able to call superConcreteJava.test()
method usingconcreteTest()
method.