Class 为什么在混合特征时会创建匿名类?
创建类Class 为什么在混合特征时会创建匿名类?,class,scala,anonymous,mixins,Class,Scala,Anonymous,Mixins,创建类A的对象将为我们提供: scala> class A defined class A scala> trait B defined trait B scala> new A res4: A = A@11ea3fc 但是,创建一个包含traitB的类A对象会给我们带来: scala> class A defined class A scala> trait B defined trait B scala> new A res4: A = A@11
A
的对象将为我们提供:
scala> class A
defined class A
scala> trait B
defined trait B
scala> new A
res4: A = A@11ea3fc
但是,创建一个包含traitB
的类A
对象会给我们带来:
scala> class A
defined class A
scala> trait B
defined trait B
scala> new A
res4: A = A@11ea3fc
这里我们有一个匿名类(由anon
暗示)。为什么?
这是因为带B的类型A被视为一个新类型(以前没有用标识符定义过)?是。虽然您的类型仍然是A和B
,但需要有一个实现这两个接口的底层Java类。这没有什么错,只是如果您以这种方式创建对象数百次,您可能会有数百个类文件。在这种情况下,您可能需要创建一个专用的类AB,用B
扩展a,然后实例化新AB
作为补充说明,您会发现您也无法直接实例化trait,例如,newb
将不起作用。您也需要在这里创建一个显式类,例如,newb{}
,再次生成一个合成(“匿名”)类。这不仅仅是因为带B的a必须被视为一个新类型。对于Scala类型的系统,是否存在对应于a和B的类并不直接重要。生成匿名类是因为它必须包含混合在traits中的所有方法的桥接方法
创建匿名类的原因是,该对象必须具有A
中所有方法和B
中所有方法的实现。在JVM字节码级别上,这将保证继承多个类,JVM上不支持多重继承模型
为了模拟多重继承(或mixin组合,不管您如何称呼它),Scala在创建特征时会执行以下操作:
如果traitT
没有方法实现,它将创建一个定义trait中所有方法的接口
如果traitT
有方法实现,它会另外创建一个类T$class
,该类对T
中的每个具体方法都有一个静态方法。此静态方法的主体与T
中对应的方法相同,但其签名已更改为包含This
参数。如果T
had:
scala> new A with B
res3: A with B = $anon$1@172aa3f
然后,T$class
将具有:
def foo(x: Int) = x
编译器将大致将其重写为以下内容:
class A {
def bar = println("!")
}
trait T {
def foo(x: Int) = x
}
new A with T
A类{
def bar=println(“!”)
}
T{
def foo(x:Int):Int
}
等级T$等级{
def foo($this:T,x:Int)=x
}
类$anon扩展了一个T{
//请注意,“bar”是继承的,但“foo”不是
def foo(x:Int)=T$class.foo(this,x)
}
新$anon
注意,编译器实际上可以将调用站点重写为foo
,直接从调用站点调用静态方法,而不是通过桥接方法。之所以不这样做,是因为这样它就不再支持子类型多态性了。谢谢。当专用类在性能方面更有意义时,匿名对象的数量是多少?10、100、1000或更多?它只会为代码中出现的每一个此类创建一个新类,而不是为该类的每个实例创建一个新类。所以,除非你在数百行代码中有新的A和B
,这是不可能的,否则应该不会有问题。@John-我不知道。我个人已经有了10个案例的课程;这是10个不同的点,A和B
被实例化(正如@drexin正确地说的)。我不经常遇到这种情况。请注意,使用-Xprint:mixin
参数调用scalac
,将显示Scala创建的确切结构-Xshow阶段
显示可与-Xprint:
一起使用的其他阶段。