笔记来源:
在许多面向对象的语言中,常常在类构造器中接受参数,目的是将参数赋值给类成员。
执行下面的代码会是什么结果呢?
trait A { val audience: String println("Hello " + audience)}class BMember(a: String = "World") extends A { val audience = a println("I repeat: Hello " + audience)}class BConstructor(val audience: String = "World") extends A { println("I repeat: Hello " + audience)}new BMember("Readers")new BConstructor("Readers")
答案是:
Hello nullI repeat:Hello ReadersHello ReadersI repeat:Hello Readers
通常,BConstructor
中的模式是首选的,因为它的行为更少可能会引起意外。这时,超类中声明的 val
绝不会存在于非初始化的状态。
其实,超类和超特质初始化代码的执行是在参数评估和早期字段定义之后,实例化类和特质的初始化语句之前。直接超类和混进特质是当它们出现在 class
、trait
、object
定义中时按从左到右的顺序初始化。
因此,考虑以下初始化方式:
class BMember2(a: String = "World") extends { val audience = a} with A { println("I repeat: Hello " + audience)}new BMember2("Readers")
它的输出结果则为:
Hello ReadersI repeat:Hello Readers
实际生产中,最好考虑在类或对象体的括号后(这是主构造器)按照从左到右的声明顺序插入超类构造器和超特质初始化程序。