回答
从 Java 的角度来看,Trait.scala 被编译成 Trait 接口。因此,在 Java 中实现 Trait 被解释为实现了一个接口——这使您的错误消息显而易见。简短的回答:你不能利用 Java 中的 trait 实现,因为这会在 Java 中启用多重继承(!)
它是如何在 Scala 中实现的?
长答案:那么它在 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 接口
-
scalac 通过委托给Trait$class 自动实现Trait 方法。这实质上意味着调用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
翻译成:
特征1
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";
}
}
特质2
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";
}
}
FooOn类固醇
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);
}
}
所以整个堆栈调用如下:
- FooOnSteroids 实例上的'bar' 方法(入口点);
- Trait2$class 的 'bar' 静态方法将 this 作为参数传递并返回 'Trait2$$super$bar()' 方法调用和字符串 ", Trait2" 的串联;
- 'Trait2$$super$bar()' 在 FooOnSteroids 实例上调用 ...
- Trait1$class 的 'bar' 静态方法将 this 作为参数传递并返回 'Trait1$$super$bar()' 方法调用和字符串 ", Trait1" 的串联;
- 'Trait1$$super$bar' 在 FooOnSteroids 实例上调用 ...
- 原始 Foo 的 'bar' 方法
结果是“Foo, Trait1, Trait2”。
结论
如果您已设法阅读所有内容,则原始问题的答案在前四行...