第六章: Reusing Classes

第六章: Reusing Classes

use the classes without soiling the existing code—composition and inheritance(合成与继承—has a is a )

 

 

 

 

 

1、  Inheritance

 

 

 

 

 

class Cleanser {

 

public void scrub() {System.out.println(“Cleanser”); }

 

}

 

 

 

 

 

public class Detergent extends Cleanser {

 

  // Change a method:

 

  public void scrub() {System.out.println(“Detergent”);

 

    super.scrub(); // Call base-class version

 

  }

 

2、 Initializing the base class(基类的初始化)

 

 

 

 

 

When you create an object of the derived class, it contains within it a subobject of the base class. This subobject is the same as if you had created an object of the base class by itself. It’s just that from the outside, the subobject of the base class is wrapped within the derived-class object. Java automatically inserts calls to the base-class constructor in the derived-class constructor(默认的无参构造函数)if you want to call a base-class constructor that has an argument, you must explicitly write the calls to the base-class constructor using the super keyword and the appropriate argument list.

 

 

 

 

 

// Constructor calls during inheritance.

 

import com.bruceeckel.simpletest.*;

 

class Art {

 

 

 

 

 

  Art() {

 

 

 

 

 

    System.out.println("Art constructor");

 

 

 

 

 

  }

 

 

 

 

 

}

 

 

 

 

 

public class Cartoon extends Art {

 

 

 

 

 

  private static Test monitor = new Test();

 

 

 

 

 

  public Cartoon() {

 

 

 

 

 

    System.out.println("Cartoon constructor");

 

 

 

 

 

  }

 

 

 

 

 

  public static void main(String[] args) {

 

 

 

 

 

    Cartoon x = new Cartoon();

 

 

 

 

 

    monitor.expect(new String[] {

 

 

 

 

 

      "Art constructor",

 

 

 

 

 

      "Cartoon constructor"

 

 

 

 

 

    });

 

 

 

 

 

  }

 

 

 

 

 

} ///:~

 

 

 

 

 

// Inheritance, constructors and arguments.

 

 

 

 

 

import com.bruceeckel.simpletest.*;

 

class Game {

 

 

 

 

 

  Game(int i) {

 

 

 

 

 

    System.out.println("Game constructor");

 

 

 

 

 

  }

 

 

 

 

 

}

 

 

 

 

 

public class Chess extends Game {

 

 

 

 

 

  private static Test monitor = new Test();

 

 

 

 

 

  Chess() {

 

 

 

 

 

    super(11);        //必须调用,否则系统提示找不到祖先黙认的构造函数Game()

 

 

 

 

 

    System.out.println("Chess constructor");

 

 

 

 

 

  }

 

 

 

 

 

  public static void main(String[] args) {

 

 

 

 

 

    Chess x = new Chess();

 

 

 

 

 

    monitor.expect(new String[] {

 

 

 

 

 

      "Game constructor",

 

 

 

 

 

      "Chess constructor"

 

 

 

 

 

    });

 

 

 

 

 

  }

 

 

 

 

 

} ///:~

 

 

 

 

 

// the compiler forces you to place the base-class constructor call first in the body of the derived-class constructor.

 

 

 

 

 

3Guaranteeing proper cleanup(确保进行妥善的清理)

 

 

 

 

 

import com.bruceeckel.simpletest.*;

 

import java.util.*;
class Shape {

 

  Shape(int i) {

 

    System.out.println("Shape constructor");

 

  }

 

  void dispose() {

 

    System.out.println("Shape dispose");

 

  }

 

}
class Circle extends Shape {

 

  Circle(int i) {

 

    super(i);

 

    System.out.println("
Drawing Circle
"
);

 

  }

 

  void dispose() {

 

    System.out.println("Erasing Circle");

 

    super.dispose();

 

  }

 

}

 

public class CADSystem extends Shape {

 

  private static Test monitor = new Test();

 

  private Circle c;

 

  public CADSystem(int i) {

 

    super(i + 1);

 

    c = new Circle(1);

 

    System.out.println("Combined constructor");

 

  }

 

  public void dispose() {

 

    System.out.println("CADSystem.dispose()");

 

    // The order of cleanup is the reverse

 

    // of the order of initialization

 

    c.dispose();

 

    super.dispose();

 

  }

 

  public static void main(String[] args) {

 

    CADSystem x = new CADSystem(47);

 

    try {

 

      // Code and exception handling...

 

    } finally {

 

      x.dispose();

 

    }

 

   monitor.expect(new String[] {

 

      "Shape constructor",

 

      "Shape constructor",

 

      "
Drawing Circle
"
,

 

      "Combined constructor",

 

      "CADSystem.dispose()",

 

      "Erasing Circle",

 

      "Shape dispose",

 

      "Shape dispose"

 

    });

 

  }

 

} ///:~

 

4、 Upcasting(向上转型)-- The new class is a type of the existing class
One of the clearest ways to determine whether you should use composition or 
inheritance is to ask whether you’ll ever need to upcast from your new class to the base class.
5The final keyword -- it says “This cannot be changed.”

 

the three places where final can be used: for data, methods, and classes.

 

A constant is useful for two reasons:

 

 

 

 

 

  1. It can be a compile-time constant that won’t ever change

     

  2. It can be a value initialized at run time that you don’t want changed.

     

With a primitive, final makes the value a constant, but with an object reference, final makes the reference a constant. Once the reference is initialized to an object, it can never be changed to point to another object. However, the object itself can be modified;

 

 

 

 

 

  // Can be compile-time constants:

 

  private final int VAL_ONE = 9;   //通常约定,primitive常量,词与词之间下划线分开 

 

 private static final int VAL_TWO = 99;  //,字母全部大写

 

  // Typical public constant:

 

  public static final int VAL_THREE = 39;

 

  // Cannot be compile-time constants:

 

  private final int i4 = rand.nextInt(20);

 

  static final int i5 = rand.nextInt(20);

 

  private final Value v2 = new Value(22);

 

  private static final Value v3 = new Value(33);

 

  // Arrays:

 

  private final int[] a = { 1, 2, 3, 4, 5, 6 };

 

 

1)Blank finals--blank finals provide much more flexibility in the use of the final keyword since, 
for example, a final field inside a class can now be different for each object
class Poppet {

 

  private int i;

 

  Poppet(int ii) { i = ii; }

 

}

 

public class BlankFinal {

 

  private final int i = 0; // Initialized final

 

  private final int j; // Blank final

 

  private final Poppet p; // Blank final reference

 

  // Blank finals MUST be initialized in the constructor:

 

  public BlankFinal() {

 

    j = 1; // Initialize blank final

 

    p = new Poppet(1); // Initialize blank final reference

 

  }

 

  public BlankFinal(int x) {

 

    j = x; // Initialize blank final

 

    p = new Poppet(x); // Initialize blank final reference

 

  }

 

  public static void main(String[] args) {

 

    new BlankFinal();

 

    new BlankFinal(47);

 

  }

 

} ///:~

 

 

2)Final arguments

 

class Gizmo {

 

  public void spin() {}

 

}

 

public class FinalArguments {

 

  void with(final Gizmo g) {

 

    //! g = new Gizmo(); // Illegal -- g is final

 

  }

 

  void without(Gizmo g) {

 

    g = new Gizmo(); // OK -- g not final

 

    g.spin();

 

  }

 

  // void f(final int i) { i++; } // Can't change

 

  // You can only read from a final primitive:

 

  int g(final int i) { return i + 1; }

 

  public static void main(String[] args) {

 

    FinalArguments bf = new FinalArguments();

 

    bf.without(null);

 

    bf.with(null);

 

  }

 

} ///:~

 

 

3)Final methods --There are two reasons for final methods. 
The first is to put a “lock” on the method to prevent any inheriting class from changing its meaning. 
The second reason for final methods is efficiency.
4)final and private--Any private methods in a class are implicitly final.
“Overriding” can only occur if something is part of the base-class interface. If a method is private, 
it isn’t part of the base-class interface. It is just some code that’s hidden away inside the class,
 and it just happens to have that name, but if you create a public, protected, or package-access 
method with the same name in the derived class, there’s no connection to the method that might 
happen to have that name in the base class. 
5)Final classes--state that you don’t want to inherit from this class or allow anyone else to do so. 
In other words, for some reason the design of your class is such that there is never a need to make 
any changes, or for safety or security reasons you don’t want subclassing. Note that the fields of a 
final class can be final or not, as you choose.
6Initialization with inheritance(继承情况下的初始化)

 

先装载基类的class,初始化基类的static变量,再装载派生类,初始化派生类的static变量,之后可以创建对象了,
首先对象里所有primitive变量初始化为缺省值,reference初始化为null,然后再调用基类的构造函数(自动),
再执行派生类构造函数的其余部分。
import com.bruceeckel.simpletest.*;

 

class Insect {

 

  protected static Test monitor = new Test();

 

  private int i = 9;

 

  protected int j;

 

  Insect() {

 

    System.out.println("i = " + i + ", j = " + j);

 

    j = 39;

 

  }

 

  private static int x1 =

 

    print("static Insect.x1 initialized");

 

  static int print(String s) {

 

    System.out.println(s);

 

    return 47;

 

  }

 

}

 

public class Beetle extends Insect {

 

  private int k = print("Beetle.k initialized");

 

  public Beetle() {

 

    System.out.println("k = " + k);

 

    System.out.println("j = " + j);

 

  }

 

  private static int x2 =

 

    print("static Beetle.x2 initialized");

 

  public static void main(String[] args) {

 

    System.out.println("Beetle constructor");

 

    Beetle b = new Beetle();

 

    monitor.expect(new String[] {

 

      "static Insect.x1 initialized",

 

      "static Beetle.x2 initialized",

 

      "Beetle constructor",

 

      "i = 9, j = 0",

 

      "Beetle.k initialized",

 

      "k = 47",

 

      "j = 39"

 

    });

 

  }

 

} ///:~

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值