これはA with B
、新しいタイプと見なされなければならないという理由だけではありません。Scala型システムの場合、に対応するクラスが存在するかどうかは直接関係ありませんA with B
。匿名クラスが生成されるのは、混合されたトレイトのすべてのメソッドのブリッジメソッドが含まれている必要があるためです。
匿名クラスが作成される理由は、オブジェクトにからのすべてのメソッドとからのすべてのメソッドの実装が必要であるためA
ですB
。JVMバイトコードレベルでは、これは複数のクラスを継承することを保証し、多重継承モデルはJVMではサポートされていません。
多重継承(またはミックスイン構成、ただしそれを呼び出したい場合)をシミュレートするために、Scalaはトレイトを作成するときに次のことを行います。
- トレイト
T
にメソッドの実装がない場合は、トレイト内のすべてのメソッドを定義するインターフェイスが作成されます。
トレイトT
にメソッド実装がある場合T$class
は、の具体的なメソッドごとに静的メソッドを持つクラスを追加で作成しT
ます。この静的メソッドの本体は、の対応するメソッドと同じですT
が、そのシグネチャが変更されてthis
パラメータが含まれています。持っていた場合T
:
def foo(x: Int) = x
その後、次のT$class
ようになります。
<static> def foo($this: T, x: Int) = x
いくつかのクラスA
といくつかのトレイトのミックスイン構成によって取得されたクラスT
には、本体を含む静的メソッドに呼び出しを転送する特別なブリッジメソッドが生成されます。このように、メソッドの本体は、が混在するすべてのクラスで複製されるわけではありませんT
。これが、匿名クラスを作成する必要がある理由です。で、メソッドごとにブリッジメソッドを定義する必要がありT
ます。
これが例です。ミックスインコンポジションを実行して新しいクラスを作成する場合、たとえば次のように呼び出しますnew A with T
。
class A {
def bar = println("!")
}
trait T {
def foo(x: Int) = x
}
new A with T
コンパイラはそれを大まかに次のように書き直します。
class A {
def bar = println("!")
}
<interface> T {
def foo(x: Int): Int
}
class T$class {
<static> def foo($this: T, x: Int) = x
}
class $anon extends A <implements> T {
// notice that `bar` is inherited, but `foo` is not
<bridge> def foo(x: Int) = T$class.foo(this, x)
}
new $anon
コンパイラは実際にコールサイトを書き直しfoo
て、ブリッジメソッドではなく、コールサイトから直接静的メソッドを呼び出すことができることに注意してください。そのように行われない理由は、サブタイピングポリモーフィズムをサポートしなくなるためです。