我想不可能从Java调用Scala特征中实现的方法,或者有办法吗?
假设我有Scala:
trait Trait {
def bar = {}
}
并且在Java中如果我将其用作
class Foo implements Trait {
}
Java抱怨Trait is not abstract and does not override abstract method bar() in Trait
答案 0 :(得分:130)
从Java角度Trait.scala
编译为Trait
接口。因此,在Java中实现Trait
被解释为实现一个接口 - 这使得您的错误消息显而易见。简短的回答:你无法利用Java中的trait实现,因为这将在Java中实现多重继承(!)
答案很长:那么它如何在Scala中运行?查看生成的字节码/类,可以找到以下代码:
interface Trait {
void bar();
}
abstract class Trait$class {
public static void bar(Trait thiz) {/*trait implementation*/}
}
class Foo implements Trait {
public void bar() {
Trait$class.bar(this); //works because `this` implements Trait
}
}
Trait
是一个界面Trait$class
(不要与Trait.class
混淆)透明地创建类,从技术上讲,不实现Trait
接口。但是它确实有一个static bar()
方法将Trait
实例作为参数(this
的排序)Foo
实现Trait
interface scalac
通过委派Trait
自动实施Trait$class
方法。这实质上意味着调用Trait$class.bar(this)
。请注意,Trait$class
既不是Foo
的成员,也不是Foo
对其进行扩展。它只是通过传递this
来代表它。
继续关于Scala如何工作的题外话...据说很容易想象多种特征的混合是如何在下面起作用的:
trait Trait1 {def ping(){}};
trait Trait2 {def pong(){}};
class Foo extends Trait1 with Trait2
转换为:
class Foo implements Trait1, Trait2 {
public void ping() {
Trait1$class.ping(this); //works because `this` implements Trait1
}
public void pong() {
Trait2$class.pong(this); //works because `this` implements Trait2
}
}
现在很容易想象多种特征的混合如何覆盖相同的方法:
trait Trait {def bar(){}};
trait Trait1 extends Trait {override def bar(){}};
trait Trait2 extends Trait {override def bar(){}};
再次Trait1
和Trait2
将成为扩展Trait
的接口。现在,如果定义Trait2
时Foo
排在最后:
class Foo extends Trait1 with Trait2
你会得到:
class Foo implements Trait1, Trait2 {
public void bar() {
Trait2$class.bar(this); //works because `this` implements Trait2
}
}
然而,切换Trait1
和Trait2
(使Trait1
成为最后一位)将导致:
class Foo implements Trait2, Trait1 {
public void bar() {
Trait1$class.bar(this); //works because `this` implements Trait1
}
}
现在考虑可堆叠修改的特征如何工作。想象一下,有一个非常有用的类Foo:
class Foo {
def bar = "Foo"
}
您希望使用特征丰富一些新功能:
trait Trait1 extends Foo {
abstract override def bar = super.bar + ", Trait1"
}
trait Trait2 extends Foo {
abstract override def bar = super.bar + ", Trait2"
}
以下是关于类固醇的新'Foo':
class FooOnSteroids extends Foo with Trait1 with Trait2
它转换为:
interface Trait1 {
String Trait1$$super$bar();
String bar();
}
abstract class Trait1$class {
public static String bar(Trait1 thiz) {
// interface call Trait1$$super$bar() is possible
// since FooOnSteroids implements Trait1 (see below)
return thiz.Trait1$$super$bar() + ", Trait1";
}
}
public interface Trait2 {
String Trait2$$super$bar();
String bar();
}
public abstract class Trait2$class {
public static String bar(Trait2 thiz) {
// interface call Trait2$$super$bar() is possible
// since FooOnSteroids implements Trait2 (see below)
return thiz.Trait2$$super$bar() + ", Trait2";
}
}
class FooOnSteroids extends Foo implements Trait1, Trait2 {
public final String Trait1$$super$bar() {
// call superclass 'bar' method version
return Foo.bar();
}
public final String Trait2$$super$bar() {
return Trait1$class.bar(this);
}
public String bar() {
return Trait2$class.bar(this);
}
}
所以整个堆栈调用如下:
结果是“Foo,Trait1,Trait2”。
如果你已经设法阅读了所有内容,原始问题的答案就在前四行......
答案 1 :(得分:2)
它确实不是抽象的,因为bar
返回一个空的Unit
(一种NOP)。尝试:
trait Trait {
def bar: Unit
}
然后bar
将是一个返回void
的Java抽象方法。