gpt4 book ai didi

class - 为什么在混合特征时会创建一个匿名类?

转载 作者:行者123 更新时间:2023-12-04 13:11:57 26 4
gpt4 key购买 nike

scala> class A
defined class A

scala> trait B
defined trait B

创建类 A 的对象给我们:
scala> new A
res4: A = A@11ea3fc

但是创建一个 A 类的对象有特质 B混合给我们:
scala> new A with B
res3: A with B = $anon$1@172aa3f

这里我们有一个匿名类(由 anon 提示)。为什么 ?

这是因为类型 A with B被视为一种新类型(之前没有用标识符定义)?

最佳答案

这不仅是因为 A with B必须被视为一种新的类型。对于 Scala 类型系统,是否存在对应于 A with B 的类没有直接关系。 .生成了一个匿名类,因为它必须包含已混入的特征中所有方法的桥接方法。

创建匿名类的原因是该对象必须具有 A 中所有方法的实现。以及来自 B 的所有方法.在 JVM 字节码级别,这将保证继承多个类,并且 JVM 不支持多继承模型。

为了模拟多重继承(或 mixin 组合,但你想调用它),Scala 在你创建一个 trait 时会做以下事情:

  • 如果性状 T没有方法实现,它创建一个接口(interface)来定义特征中的所有方法。
  • 如果性状 T有方法实现,它另外创建一个类T$class它对T 中的每个具体方法都有一个静态方法.此静态方法与 T 中的相应方法具有相同的主体。 ,但其签名已更改为包含 this范围。如果 T有:
    def foo(x: Int) = x

  • 然后 T$class将有:
    <static> def foo($this: T, x: Int) = x

    某类的mixin组合得到的类 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。直接从调用站点调用静态方法,而不是通过桥接方法。不这样做的原因是因为它不再支持子类型多态性。

    关于class - 为什么在混合特征时会创建一个匿名类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11253813/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com