构建器的调用顺序

用于基础类的构建器肯定在一个衍生类的构建器中调用,而且逐渐向上链接,使每个基础类使用的构建器都能得到调用。之所以要这样做,是由于构建器负有一项特殊任务:检查对象是否得到了正确的构建。

下面让我们看看一个例子,它展示了按构建顺序进行合成、继承以及多形性的效果:

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
 {
  Lunch() { System.out.println("Lunch()");}
}
class PortableLunch extends Lunch 
{
  PortableLunch() {
  System.out.println("PortableLunch()");
  }
}
class Sandwich extends PortableLunch 
{
  Bread b = new Bread();
  Cheese c = new Cheese();
  Lettuce l = new Lettuce();
  Sandwich() {
    System.out.println("Sandwich()");
  }
  public static void main(String[] args) {
    new Sandwich();
  }
}

输出结果如下:

Meal()

Lunch()

PortableLunch()

Bread()

Cheese()

Lettuce()

Sandwich()

这意味着对于一个复杂的对象,构建器的调用遵照下面的顺序:

(1) 调用基础类构建器。这个步骤会不断重复下去,首先得到构建的是分级结构的根部,然

后是下一个衍生类,等等。直到抵达最深一层的衍生类。

(2) 按声明顺序调用成员初始化模块。

(3) 调用衍生构建器的主体。

构建器内部的多形性方法的行为

构建器应该构建当前类还是衍生类,这是一个问题,

如下例子:

abstract class Glyph
 {
  abstract void draw();
  Glyph() {
  System.out.println("Glyph() before draw()");
  draw();
  System.out.println("Glyph() after draw()");
  }
}
class RoundGlyph extends Glyph 
{
  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

Glyph() after draw()

RoundGlyph.RoundGlyph(), radius = 5

上文部分的初始化顺序并不十分完整,而那是解决问题的关键所在。初始化的实际过程是这样的:

(1) 在采取其他任何操作之前,为对象分配的存储空间初始化成二进制零。

(2) 就象前面叙述的那样,调用基础类构建器。此时,被覆盖的draw()方法会得到调用(的

确是在RoundGlyph构建器调用之前),此时会发现 radius的值为 0,这是由于步骤(1)

造成的。

(3) 按照原先声明的顺序调用成员初始化代码。

(4) 调用衍生类构建器的主体。

因此,设计构建器时一个特别有效的规则是:用尽可能简单的方法使对象进入就绪状态;如果可能,避免调用任何方法。在构建器内唯一能够安全调用的是在基础类中具有final 属性的那些方法(也适用于private方法,它们自动具有final 属性)。这些方法不能被覆盖,所以不会出现上述潜在的问题。

时间: 2024-12-31 03:41:13

构建器的调用顺序的相关文章

python 多个装饰器的调用顺序

python 多个装饰器的调用顺序 一般情况下,在函数中可以使用一个装饰器,但是有时也会有两个或两个以上的装饰器.多个装饰器装饰的顺序是从里到外(就近原则),而调用的顺序是从外到里(就远原则). 原代码 执行结果 装饰顺序 : 就近原则 被装饰的函数,组装装饰器时,是从下往上装饰 执行顺序 : 就远原则 装饰器调用时是从上往下调用 为了更好的理解,找到这段话: 被装饰的函数是一个妹子,装饰器是衣服."办事情"的时候得依次把外套.衬衣.内衣脱掉,事情办完了还要依次把内衣.衬衣.外套穿上.

装饰器,装饰器多参数的使用(*arg, **kwargs),装饰器的调用顺序

一.#1.执行outer函数,并且将其下面的函数名,当作参数 #2.将outer的返回值重新赋值给f1 = outer的返回值 #3.新f1 = inner #4.func = 原f1 1 #!/usr/bin/env python 2 def outer(func) : 3 def inner() : 4 print("hello") 5 print("hello") 6 print("hello") 7 r = func() 8 print(

python 中多个装饰器的执行顺序

python 中多个装饰器的执行顺序: def wrapper1(f1): print('in wrapper1') def inner1(*args,**kwargs): print('in inner1') ret = f1(*args,**kwargs) return ret return inner1 def wrapper2(f2): print('in wrapper2') def inner2(*args,**kwargs): print('in inner2') ret = f2

Item2: 遇到多个构造器形参时考虑使用构建器

Consider a builder when faced with many constructor parameters 引言 遇到多个构造器时要考虑用构建器(builder) 重叠构造器(telescoping constructor) // Telescoping constructor pattern - does not scale well! - Pages 11-12 /** * 营养成分表 */ public class NutritionFacts { private fin

Java设计模式:Builder(构建器)模式

基本概念 Builder模式是一步一步创建一个复杂对象的创建型模式.该模式将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来. 应用场景 对象创建过程比较复杂,或对创建顺序或组合有依赖(经典Builder模式,可参阅GOF<设计模式>). 创建对象时所需参数较多,且包含较多可选参数(变种Builder模式,可参阅<Effective Java>构建器小节). 示例代码 本节侧重变种Builder模式,示例代码如下: public class RobustPerso

构建器模式

*构建器模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.类图如下: *product产品类:表示被构建器构建的复杂对象,包含多个部件. 1 //产品接口 示意性产品,所以没有任何方法 2 public interface Product{ 3 } *builder构建器接口:定义创建一个product对象所需要的各个部件的操作. 1 //生成器接口 2 public interface Builder{ 3 public void builderPart1();

第二章:创建和销毁对象。ITEM2:遇到多个构造器参数时要考虑用构建器。

如果一个类中有大量的可选参数,有以下几种方式: 1.重叠构造器: package com.twoslow.cha2; /** * 重叠构造器可行,但是当由许多参数的时候,客户端代码很难编写. * @author sai * */ public class Item201 { private final int servingSize; private final int servings; private final int calories; private final int fat; pr

第二条 遇到多个构造器参数时,要考虑用构建器

静态工厂和构造器都有个共同的局限性,就是它们都不能够很好的扩展到大量的可选参数. 如: public class NutritionFacts{ private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; public Nu

C++C++中构造函数与析构函数的调用顺序

http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2: 构造函数.拷贝构造函数和析构函数的的调用时刻及调用顺序 参考3: C++构造函数与析构函数的调用顺序 2.构造函数.析构函数与拷贝构造函数介绍 2.1构造函数 构造函数不能有返回值 缺省构造函数时,系统将自动调用该缺省构造函数初始化对象,缺省构造函数会将所有数据成员都初始化为零或空 创建一个对象