我们通过一个例子来体会scala对象的构造过程
首先创建一个车站类:
class Station {
val size = 100
val spots = new Array[String](size)
}
通过size来模拟停车位数,通过字符串数组模拟具体的停车位。
在创建一个停车场类,它是车站的子类
class Park extends Station {
override val size = 20
}
停车场没有车站那么多车位,只拥有20个,因此在Park中重写了Station的size成员变量。在Park中也自然继承了station中的spots成员
现在我们执行以下代码:
object Client extends App{
val park = new Park
println(park.spots.size)
}
输出结果为0
这是为什么呢?
这要从构建对象的过程说起。当创建一个Park对象的时候,会首先创建Park的父类Station对象,在Station对象初始化的时候调用了子类的getSize方法,而子类此时还没有初始化,于是得到了0.
具体步骤如下:
1、调用子类Park构造方法。在调用子类构造方法时首先调用了父类Station的构造方法。
2、Station的构造方法中初始化了size = 100。
3、Station构造方法初始化spots并调用getSize方法获取size。
4、getSize方法被子类Park重写,因此调用Park的getSize方法。
5、Park的getSize方法获取子类size。
6、此时Park对象还没有初始化,因此size = 0。
7、spots被设置为长度为0的数组。
上述两个类用java等效编写的话如下:
public class Station {
int size;
String[] spots;
public Station(){
size = 100;
spots = new String[getSize()];
}
int getSize(){
return size;
}
}
public class Park extends Station {
int size;
public Park(){
size = 20;
}
@Override
int getSize() {
return size;
}
}
在scala中想要解决上述问题的方法有以下两种:
1、在父类的成员变量前加上lazy修饰符。这样的话这些变量就会等子类初始化之后再初始化。代码如下:
class Station {
val size = 100
lazy val spots = new Array[String](size)
}
2、在子类的构造方法中加入参数size并设置默认值,这样在构造父类的时候size的值就已经初始化了。代码如下:
class Park(override val size:Int = 20) extends Station {
}
3、在子类中使用提前初始化预发,代码如下:
class Park extends {override val size = 20} with Station {
}
上述方式虽然能够解决问题,但是代码并不是非常美观,因此在实际编码时还是要尽量注意在构造方法中不要依赖val成员变量的值。
浅谈Scala对象构造过程
原文:http://blog.csdn.net/u010256841/article/details/46008201