代码复用是面向对象编程最具魅力的原因之一
- 组合(Composition)
- 继承(Inheritance)
组合
仅需要把对象的引用(object references)放置在一个新的类里,就完成了组合。
而编译器不会为每个引用创建一个默认对象,初始化引用有四种方法:
- 对象被定义时
private int i = 1
- 该类的构造函数中
Bath(){s1 = 'joy'}
- 实际使用对象之前(延迟初始化)
if (s3==null) s3 = 'hello'
- 使用实例初始化
Bath b = new bath
继承
初始化基类
子类包含基类中的接口信息,需要调用基类构造函数在构造函数中执行初始化。
初始化顺序由祖先—>子孙
带参数的构造函数:
若基类为带参构造函数,则必须使用 super 关键字和参数列表显式调用。
class Game {
Game(int i) {
System.out.println("Game constructor");
}
}
class BoardGame extends Game {
BoardGame(int i) {
super(i);
System.out.println("BoardGame constructor");
}
}
委托
委托是一种重要的编程方式。与继承相对,是可复用编程的重要方法。
委托指的是在A类中以各种方式利用B类,完成类的功能。
委托的类型:
A use B
B类对象在A类中出现,但是是以局部变量或是方法参数的形式出现的。A类中并没有B类的对象作为域。
一般称这种delegation为临时性的delegation。A has B
B类对象在A类中出现,B类的对象是A类的域之一。B类对象通过A类对象的constructor方法或其它方法从外部输入A类对象。
A has B有两种情况。1)Association。A类对象和B类对象之间并没有从属关系。
2)Aggregation。A类对象由B类聚合而成,但是B类可以脱离A类单独存在。
一般称这种delegation为永久性的delegation。A is part of B
B类对象在A类中出现,B类的对象是A类的域之一。B类对象在A类对象内创建。
B类对象不能脱离A类对象独立存在。
一般称这种delegation为永久性的delegation
保证适当的清理:
由于java垃圾自收集机制,无法主动知道垃圾何时被清理。如果要清理,则需编写一个显示的方法调用。
//[1]使用try finally 在finally中显示调用
public static void main(String[] args) {
CADSystem x = new CADSystem(47);
try {
// Code and exception handling...
} finally {
x.dispose();
}
}
//[2]Override子类的dispose函数,并super显示调用父类dispose;最好按照创建的相反顺序进行
class Circle extends Shape {
Circle(int i) {
super(i);
System.out.println("Drawing Circle");
}
@Override
void dispose() {
System.out.println("Erasing Circle");
super.dispose();
}
}
名称隐藏: 即使Java基类中的function被多次重载,但在派生类中重新定义该func仍不会隐藏任何基类版本
因此,使用 @Override 可以防止意外重载
**
组合与继承的选择
当想在新类中包含一个已有类的功能时,使用composition
当想使用一个现有类,并开发出它的新版本时,使用inheritation
考虑使用继承时,首先想”是否需要向上转型”
向上转型
派生类转型为基类都是向上的。派生类是基类的一个超集。它可能比基类包含更多的方法,但它必须至少具有与基类一样的方法。在向上转型期间,类接口只可能失去方法,不会增加方法。
否需要向上转型”
final理解:
final 只说明是一个常量, static 强调只有一个,而 final static 即表示编译时常量(命名全部大写)
并非被 final 修饰就认为可在编译时知道其值。
final 修饰 参数 时,意味着在该func不能改变所修饰的对象或常量。
void with(final Gizmo g) {
//-g = new Gizmo(); // Illegal -- g is final
}
final 修饰 方法 时,防止子类通过覆写改变方法的行为。
类中 private 方法都被隐式地指定为 final ,不能被覆写。我们可以理解为:覆写必须能将一个对象upcasting为基类并调用相同的方法,如果有一个方法为private,它表示基类接口的一部分,它只是隐藏在类内部的代码,恰好有相同命名。因此即使在子类中有和父类同名func,其并非是被覆写。
class WithFinals {
// Identical to "private" alone:
private final void f() {
System.out.println("WithFinals.f()");
}
// Also automatically "final":
private void g() {
System.out.println("WithFinals.g()");
}
}
class OverridingPrivate extends WithFinals {
private final void f() {
System.out.println("OverridingPrivate.f()");
}
private void g() {
System.out.println("OverridingPrivate.g()");
}
}
public class FinalOverridingIllusion {
public static void main(String[] args) {
OverridingPrivate op = new OverridingPrivate();
//[1]此时可利用op调用f()和g(),调用的是OverridingPrivate.f()
WithFinals wf = op;
//[2]若此时想调用,则调用失败,因为无法覆写,所以无法upcasting
final 修饰类时,表示该类不能被继承。