在 Java 中使用带有已实现方法的 Scala 特征

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7637752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:31:58  来源:igfitidea点击:

Using Scala traits with implemented methods in Java

javascalascala-java-interop

提问by Jus12

I guess it is not possible to invoke methods implemented in Scala traits from Java, or is there a way?

我想不可能从 Java 调用在 Scala 特征中实现的方法,或者有什么方法?

Suppose I have in Scala:

假设我在 Scala 中有:

trait Trait {
  def bar = {}
}

and in Java if I use it as

在 Java 中,如果我将它用作

class Foo implements Trait {
}

Java complains that Trait is not abstract and does not override abstract method bar() in Trait

Java抱怨说 Trait is not abstract and does not override abstract method bar() in Trait

回答by Tomasz Nurkiewicz

Answer

回答

From Java perspective Trait.scalais compiled into Traitinterface. Hence implementing Traitin Java is interpreted as implementing an interface - which makes your error messages obvious. Short answer: you can't take advantage of trait implementations in Java, because this would enable multiple inheritance in Java (!)

从Java的角度来看Trait.scala是编译成Trait接口的。因此Trait在 Java 中实现被解释为实现一个接口 - 这使您的错误消息显而易见。简短回答:您不能利用 Java 中的 trait 实现,因为这将启用 Java 中的多重继承(!)

How is it implemented in Scala?

它是如何在 Scala 中实现的?

Long answer: so how does it work in Scala? Looking at the generated bytecode/classes one can find the following code:

长答案:那么它在 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
    }
}
  • Traitis an interface
  • abstract Trait$class(do not confuse with Trait.class) class is created transparently, which technically does notimplement Traitinterface. However it does have a static bar()method taking Traitinstance as argument (sort of this)
  • Fooimplements Traitinterface
  • scalacautomatically implements Traitmethods by delegating to Trait$class. This essentially means calling Trait$class.bar(this).
  • Trait是一个接口
  • 摘要Trait$class(不混淆Trait.class)类透明创建,这在技术上也无法实现Trait接口。但是它确实有一个static bar()Trait实例作为参数的方法(有点this
  • Foo实现Trait接口
  • scalacTrait通过委托给自动实现方法Trait$class。这实质上意味着调用Trait$class.bar(this).

Note that Trait$classis neither a member of Foo, nor does Fooextend it. It simply delegates to it by passing this.

请注意,Trait$class它既不是 的成员Foo,也不Foo扩展它。它只是通过传递委托给它this

Mixing in multiple traits

混合多个特征

To continue the digression on how Scala works... That being said it is easy to imagine how mixing in multiple traits works underneath:

继续关于 Scala 如何工作的题外话……话虽如此,很容易想象混合多个特征在下面是如何工作的:

trait Trait1 {def ping(){}};
trait Trait2 {def pong(){}};
class Foo extends Trait1 with Trait2

translates to:

翻译成:

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

Multiple traits overriding same method

多个特征覆盖相同的方法

Now it's easy to imagine how mixing in multiple traits overriding same method:

现在很容易想象如何混合多个特征覆盖相同的方法:

trait Trait {def bar(){}};
trait Trait1 extends Trait {override def bar(){}};
trait Trait2 extends Trait {override def bar(){}};

Again Trait1and Trait2will become interfaces extending Trait. Now if Trait2comes last when defining Foo:

再次Trait1Trait2将成为接口扩展Trait。现在,如果Trait2在定义时最后出现Foo

class Foo extends Trait1 with Trait2

you'll get:

你会得到:

class Foo implements Trait1, Trait2 {
    public void bar() {
        Trait2$class.bar(this); //works because `this` implements Trait2
    }
}

However switching Trait1and Trait2(making Trait1to be last) will result in:

然而,切换Trait1Trait2(成为Trait1最后一个)将导致:

class Foo implements Trait2, Trait1 {
    public void bar() {
        Trait1$class.bar(this); //works because `this` implements Trait1
    }
}

Stackable modifications

可堆叠修改

Now consider how traits as stackable modifications work. Imagine having a really useful class Foo:

现在考虑特征作为可堆叠修改的工作原理。想象一下有一个非常有用的类 Foo:

class Foo {
  def bar = "Foo"
}

which you want to enrich with some new functionality using traits:

您希望使用特征来丰富一些新功能:

trait Trait1 extends Foo {
  abstract override def bar = super.bar + ", Trait1"
}

trait Trait2 extends Foo {
  abstract override def bar = super.bar + ", Trait2"
}

Here is the new 'Foo' on steroids:

这是类固醇的新“Foo”:

class FooOnSteroids extends Foo with Trait1 with Trait2

It translates to:

它翻译成:

Trait1

特质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";
  }
}

Trait2

特质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";
  }
}

FooOnSteroids

FooOnSteroids

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

So the whole stack invocations are as follows:

所以整个栈调用如下:

  • 'bar' method on FooOnSteroids instance (entry point);
  • Trait2$class's 'bar' static method passing this as argument and returning a concatenation of 'Trait2$$super$bar()' method call and string ", Trait2";
  • 'Trait2$$super$bar()' on FooOnSteroids instance which calls ...
  • Trait1$class's 'bar' static method passing this as argument and returning a concatenation of 'Trait1$$super$bar()' method call and string ", Trait1";
  • 'Trait1$$super$bar' on FooOnSteroids instance which calls ...
  • original Foo's 'bar' method
  • FooOnSteroids 实例(入口点)上的“bar”方法;
  • Trait2$class 的“bar”静态方法将此作为参数传递并返回“Trait2$$super$bar()”方法调用和字符串“,Trait2”的串联;
  • FooOnSteroids 实例上的“Trait2$$super$bar()”调用...
  • Trait1$class 的“bar”静态方法将此作为参数传递并返回“Trait1$$super$bar()”方法调用和字符串“,Trait1”的串联;
  • FooOnSteroids 实例上的“Trait1$$super$bar”调用...
  • 原始 Foo 的 'bar' 方法

And the result is "Foo, Trait1, Trait2".

结果是“Foo, Trait1, Trait2”。

Conclusion

结论

If you've managed to read everything, an answer to the original question is in the first four lines...

如果您已经阅读了所有内容,那么原始问题的答案就在前四行中...

回答by paradigmatic

It's indeed not abstract since baris returning an empty Unit(a kind of NOP). Try:

它确实不是抽象的,因为bar它返回一个空的Unit(一种 NOP)。尝试:

trait Trait {
  def bar: Unit
}

Then barwill be a Java abstract method returning void.

然后bar将返回一个 Java 抽象方法void