“设计构建器时一个特别有效的规则是:用尽可能简单的方法使对象进入就绪状态;如果可能,避免调用任何方法。在构建器内唯一能够安全调用的是在基础类中具有final属性的那些方法(也适用于private方法,它们自动具有final属性)。这些方法不能被覆盖,所以不会出现上述潜在的问题。”
输出结果:
这不禁引出了一个初始化顺序的问题,对于继承的情况,显然是先初始化父类,然后子类。再加上先静态属性->静态块->非静态属性->构造方法,的顺序。
执行结果:
摘录来自: (美)埃克尔 著 陈昊鹏 译. “java编程思想”。
那么潜在的问题是什么呢?再来看看代码:
abstract class Glypy {
static int radius = 2;
abstract void draw();
Glypy() {
System.out.println("Glyph() before draw()");
draw();
System.out.println("Glypy() after draw()");
}
}
class RoundGlyph extends Glypy {
int radius = 1;
RoundGlyph(int r) {
radius = r;
System.out.println("RoundGlyph.RoundGlyph,radius= " + radius);
}
void draw() {
System.out.println("RoundGlyph.draw(),radius=" + radius);
}
}
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
}
输出结果:
Glyph() before draw()
RoundGlyph.draw(),radius=0
Glypy() after draw()
RoundGlyph.RoundGlyph,radius= 5
这不禁引出了一个初始化顺序的问题,对于继承的情况,显然是先初始化父类,然后子类。再加上先静态属性->静态块->非静态属性->构造方法,的顺序。
总结一下:先有类而后有对象,静态方法和静态块都属于类,所以先初始化静态属性和静态块。先有父类才有子类,所以先初始化父类。
有了类就可以初始化对象了,先初始化属性然后是构造方法,再加上先父类后子类。
整个初始化可以分成两步,第一步:类初始化,父类的静态属性->父类静态块->子类静态属性->子类静态块
第二步:对象初始化,父类属性->父类构造方法->子类属性->子类构造方法
来个例子:
class Meal{
Meal(){
System.out.println("Meal");
}
}
class Bread{
Bread(){
System.out.println("Bread");
}
}
class Cheese{
Cheese(){
System.out.println("Cheese");
}
}
class Lettuce{
Lettuce(){
System.out.println("Lettuce");
}
}
class Lunch extends Meal{
static Cheese c = new Cheese();
Lunch(){
System.out.println("Lunch");
}
}
class PortableLunch extends Lunch{
Bread b = new Bread();
PortableLunch(){
System.out.println("PortableLunch");
}
}
public class Sandwich extends PortableLunch{
Lettuce l = new Lettuce();
Sandwich(){
System.out.println("Sandwich()");
}
public static void main(String[] args) {
new Sandwich();
}
}
执行结果:
Cheese
Meal
Lunch
Bread
PortableLunch
Lettuce
Sandwich()