在 Java 中使用带有已实现方法的 Scala 特征 [英] Using Scala traits with implemented methods in Java

查看:34
本文介绍了在 Java 中使用带有已实现方法的 Scala 特征的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

假设我在 Scala 中有:

Suppose I have in Scala:

trait Trait {
  def bar = {}
}

在Java中,如果我将它用作

and in Java if I use it as

class Foo implements Trait {
}

Java 抱怨 Trait 不是抽象的并且没有覆盖 Trait 中的抽象方法 bar()

推荐答案

答案

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

Answer

From Java perspective Trait.scala is compiled into Trait interface. Hence implementing Trait in 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 (!)

长答案:那么它在 Scala 中是如何工作的?查看生成的字节码/类可以找到以下代码:

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

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 是一个接口
  • abstract Trait$class(不要与Trait.class混淆)类是透明创建的,技术上实现Trait 界面.然而,它确实有一个 static bar() 方法,将 Trait 实例作为参数(类似于 this)
  • Foo 实现了 Trait 接口
  • scalac 通过委托给 Trait$class 自动实现 Trait 方法.这实质上意味着调用 Trait$class.bar(this).
    • Trait is an interface
    • abstract Trait$class (do not confuse with Trait.class) class is created transparently, which technically does not implement Trait interface. However it does have a static bar() method taking Trait instance as argument (sort of this)
    • Foo implements Trait interface
    • scalac automatically implements Trait methods by delegating to Trait$class. This essentially means calling Trait$class.bar(this).
    • 注意 Trait$class 既不是 Foo 的成员,也不是 Foo 扩展它.它只是通过传递 this 来委托给它.

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

      继续讨论 Scala 的工作原理...话虽如此,很容易想象混合多个特征在下面是如何工作的:

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

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

      多个特征覆盖相同的方法

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

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

      再次Trait1Trait2 将成为扩展Trait 的接口.现在,如果在定义 FooTrait2 最后出现:

      Again Trait1 and Trait2 will become interfaces extending Trait. Now if Trait2 comes last when defining Foo:

      class Foo extends Trait1 with Trait2
      

      你会得到:

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

      然而,切换 Trait1Trait2(使 Trait1 排在最后)将导致:

      However switching Trait1 and Trait2 (making Trait1 to be last) will result in:

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

      可堆叠修改

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

      Stackable modifications

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

      class Foo {
        def bar = "Foo"
      }
      

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

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

      这是新的 'Foo' 类固醇:

      Here is the new 'Foo' on steroids:

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

      特质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

      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"静态方法将此作为参数传递并返回Trait2$$super$bar()"方法调用和字符串,Trait2"的串联;
      • FooOnSteroids 实例上的'Trait2$$super$bar()' 调用...
      • Trait1$class 的bar"静态方法将此作为参数传递并返回Trait1$$super$bar()"方法调用和字符串,Trait1"的串联;
      • FooOnSteroids 实例上的'Trait1$$super$bar' 调用...
      • 原始 Foo 的 'bar' 方法

      结果是Foo, Trait1, Trait2".

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

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

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

      这篇关于在 Java 中使用带有已实现方法的 Scala 特征的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆