复用代码(代码重用机制)
java问题解决是围绕着类展开的. 可以通过创建新类来复用代码(利用现有类形成新类). 有两种方法可以达到这一目的:
(1)在新类中产生现有类的对象. 由于新类是由现有类的对象所组成, 所以这种方法称为组合. 该方法只是复用了现有程序代码的功能, 而非它的形式.
(2)按照现有类的形式来创建新类. 采用现有类的形式并在其中添加新代码. 称为继承.
继承: 除非已明确指出要从哪个类继承, 否则就是在隐式地从Java的标准根类Object进行继承.

/** *//**
* Title: Inheritance syntax<br>
* Description: 此类纯粹为了表明继承的运用, 无任何功能<br>
* Copyright: (c) 2008 Thinking in Java<br>
* Company: Augmentum Inc<br>
* @author Forest He
* @version 1.0
*/

class Cleanser ...{
private String s = new String("Cleanser");

public void append(String a) ...{s += a;}

public void dilute() ...{ append(" dilute()"); }

public void apply() ...{ append(" apply()"); }

public void scrub() ...{ append(" scrub()"); }

public String toString() ...{ return s; }

public static void main(String[] args) ...{
Cleanser cleanser = new Cleanser();
cleanser.dilute(); cleanser.apply(); cleanser.scrub();
System.out.println(cleanser);
}
}


class Detergent extends Cleanser ...{
@Override

public void scrub() ...{
append(" Detergent.scrub");
super.scrub();
}

public void foam() ...{ append(" foam()"); }

public static void main(String[] args) ...{
Detergent detergent = new Detergent();
detergent.dilute(); detergent.apply(); detergent.scrub(); detergent.foam();
System.out.println(detergent);//先进行了向上转型, 然后继承基类的toString()方法.
}
}

/**//*
* 1.toString()方法不是覆盖的Object基类方法, 只是模仿StringBuffer类方法append()而写的. 这里我们用"+="操作符将几个String对象连接成s, 此操作符是被Java设计者重装用以处理String对象的操作符之一(另一个是"+").
* ps: "+="和"+"实际是数字类型数据的运算符. Java设计者将其重装以用于String类型.
* 2.两个类中都含有main()方法. 可以为每个类都创建一个main()方法. 一般建议以这种方法来编写程序代码, 以便测试代码被包含在类中. 这种在每个类中都设置一个main()方法的技术可使每个类的单元测试都变得简便易行.
* 3.为了继承, 一般的规则是将所有的数据成员都指定为private, 将所有的方法指定为public.
* 4.继承允许子类使用基类方法以及覆盖基类方法, 你也许想要在覆盖掉某个基类方法后再调用原来那个基类方法. eg: scrub()中, 你不能直接调用scrub(), 因为这样做将会产生递归. 为解决此问题Java提供了super关键字(表示超类的意思), 因此super.scrub()将调用基类的scrub()方法.
* ps: super和this使用方法是一样的, super表示"超类的...", this表示"当前类的...".
*/
初始化基类: 从外部来看, 导出类就像是一个与基类具有相同接口的新类, 或许还会有一些额外的方法和字段. 但继承并不只是复制基类的接口.
当创建了一个导出类的对象时, 该对象包含了一个基类的子对象. 这个子对象与你用基类直接创建的对象是一样的. 二者区别在于, 后者来自于外部, 而基类的子对象被包装在导出类对象内部(向上转型的理论依据).
当然, 对基类子对象的正确初始化也是至关重要的, 而且也仅有一种方法来保证这一点: 在导出类构造器中调用基类构造器来执行初始化.
Java会自动在导出类构造器中插入对基类构造器的调用, 当然你也可以对其进行覆盖.

/** *//**
* Title: Constructor calls during inheritance<br>
* Description: 不带参数的构造器: 此类纯粹为了表明继承中基类初始化问题, 无任何功能<br>
* Copyright: (c) 2008 Thinking in Java<br>
* Company: Augmentum Inc<br>
* @author Forest He
* @version 1.0
*/

class Art ...{

Art() ...{ System.out.println("Art Constructor"); }
}

class Drawing extends Art ...{

Drawing() ...{ System.out.println("Drawing Constructor"); }
}

class Cartoon extends Drawing ...{

public Cartoon() ...{ System.out.println("Cartoon Construtor"); }

public static void main(String[] args) ...{
new Cartoon();
}
}

/**//*通过上例发现: 构建过程是从基类"向外"扩散的, 所以基类在导出类构造器可以访问它之前就已经完成了初始化.*/


/** *//**
* Title: Inheritance, Constructors and arguments<br>
* Description: 带参数的构造器: 此类纯粹为了表明继承中基类初始化问题, 无任何功能<br>
* Copyright: (c) 2008 Thinking in Java<br>
* Company: Augmentum Inc<br>
* @author Forest He
* @version 1.0
*/

class Game ...{

public Game(int i) ...{ System.out.println("Game Constructor"); }
}

class BoardGame extends Game ...{

public BoardGame(int i) ...{
super(i);
System.out.println("BoardGame Constructor");
}
}

class Chess extends BoardGame ...{

public Chess() ...{
super(5);
System.out.println("Chess Constructor");
}

public static void main(String[] args) ...{
new Chess();
}
}

/**//* 如果类没有缺省的参数, 或者想调用一个带参数的基类构造器, 就必须用super关键字显式地编写调用基类构造器的语句
* 调用基类构造器必须是你在导出类构造器中要做的第一件事(如果你错了编译器会提醒你), 即super()必须放在第一句. 这意味着在此之前不会发生任何其他动作, 这种做法同样可以防止导出类构造器捕捉任何来自基类的异常.
* 同理, 调用重载构造器也是在构造器中要做的第一件事, 即this必须放在第一句.
* ps: 虽然编译器强制你去初始化基类, 并且要求你要在构造器起始处就要这么做, 但是它并不监督你必须将成员对象也初始化, 时刻注意这一点.
*/
名称屏蔽
如果Java的基类拥有某个已被多次重载的方法名称, 那么在导出类中重新定义该方法名称并不会屏蔽其在基类中的任何版本.