java 代码
- //: notes about thinking in java
- //c07:Sandwich.java
- // Order of constructor calls.
- // From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
- // www.BruceEckel.com. See copyright notice in CopyRight.txt.
- package c07;
- import com.bruceeckel.simpletest.*;
- 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()");}
- }
- public class Sandwich extends PortableLunch {
- private static Test monitor = new Test();
- private Bread b = new Bread();
- private Cheese c = new Cheese();
- private Lettuce l = new Lettuce();
- public Sandwich() {
- System.out.println("Sandwich()");
- }
- public static void main(String[] args) {
- new Sandwich();
- monitor.expect(new String[] {
- "Meal()",
- "Lunch()",
- "PortableLunch()",
- "Bread()",
- "Cheese()",
- "Lettuce()",
- "Sandwich()"
- });
- }
- } ///:~
- /*例子说明对象调用构造器要遵循以下顺序:
- 1)调用基类构造器。这个步骤会不断反复递归下去,首先是构造这种层次结构的根,
- 然后是下一层倒出类,等等,知道最底层的倒出类
- 2)按声明顺序调用成员的初始化方法
- 3)调用导出类构造器的主体*/
java 代码
- //:notes about thinking in java
- //c07:PolyConstructors.java
- // Constructors and polymorphism
- // don't produce what you might expect.
- // From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
- // www.BruceEckel.com. See copyright notice in CopyRight.txt.
- import com.bruceeckel.simpletest.*;
- abstract class Glyph {
- abstract void draw();
- Glyph() {
- System.out.println("Glyph() before draw()");
- draw();
- System.out.println("Glyph() after draw()");
- }
- }
- class RoundGlyph extends Glyph {
- private 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 {
- private static Test monitor = new Test();
- public static void main(String[] args) {
- new RoundGlyph(5);
- monitor.expect(new String[] {
- "Glyph() before draw()",
- "RoundGlyph.draw(), radius = 0",
- "Glyph() after draw()",
- "RoundGlyph.RoundGlyph(), radius = 5"
- });
- }
- } ///:~
- /*在Glyph中,draw()方法是抽象的,这样设计是为了覆盖该方法。我们确实在RoundGlyph中强制覆盖
- draw()。但是Glyph构造器会调用这个方法,结果导致了对RoundGlyph.draw()的调用,这看起来
- 似乎是我们的目的。但是看到输出结果时我们会发现Glyph的构造起用draw()方法时,radius不是默认
- 初始值1,而是0。这可能是导致在屏幕上只画了一个点,或者根本什么东西都没有。
- 这一迷题的关键所在,初始化的实际过程是:
- 1)在其他任何事务发生之前,将分配给对象的存储空间初始化成二进制的零
- 2)如前所述那样调用构造器。此时,调用被覆盖后的draw()方法(要在调用RoundGlyph
- 构造器之前调用),由于步骤1的缘故,我们此时会发现radius的值为0
- 3)按照声明的顺序调用成员的初始化方法
- 4)调用导出类的构造器主题*/