ScalaトレイトでJavaから実装されたメソッドを呼び出すことは不可能だと思いますか、または方法はありますか?
私がScalaにいるとします:
_trait Trait {
def bar = {}
}
_
そしてJava私がそれを次のように使用する場合
_class Foo implements Trait {
}
_
JavaはTrait is not abstract and does not override abstract method bar() in Trait
からJavaパースペクティブ_Trait.scala
_はTrait
interfaceにコンパイルされます。したがって、JavaでTrait
を実装すると、インターフェースを実装すると解釈されます-これにより、エラーメッセージがわかりやすくなります。短い回答:Javaの特性実装を利用することはできません。これは、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
_と混同しないでください)クラスは透過的に作成され、技術的にはnotTrait
インターフェースを実装します。ただし、Trait
インスタンスを引数として取るstatic bar()
メソッドがあります(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
を拡張するインターフェースになります。ここで、Foo
を定義するときに_Trait2
_が最後に来る場合:
_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"
}
_
ここにステロイドの新しい「フー」があります:
_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」です。
すべてを読み終えた場合、元の質問に対する答えは最初の4行にあります...
bar
が空のUnit
(NOPの一種)を返しているため、実際には抽象的ではありません。試してください:
trait Trait {
def bar: Unit
}
その場合、bar
は、Java void
を返す抽象メソッドになります。