Java 继承
继承: 按照现有类的类型来创建新类,无需改变现有类的形式,采用现有类的形式并在其中添加新代码,这种神奇的方式称为继承.
继承是所有OOP语言和Java语言不可缺少的组成部分,当创建一个类时总是在继承,因此除非已明确指出要从其它类中继承,否则就是在隐式地从Java的标准根类Object进行继承.
继承是一种特殊的语法,在继承过程中,需要先声明新类和旧类相似.这种声明是通过在类主体的左边花括号之前,书写后面紧随基类名称的关键字extends而实现的.当这么做时,会自动得到基类中所有的域和方法.
组合和继承都能从现有类型生成新类型,组合一般是将现有类型作为新类型底层实现的一部分来可以实现的,而继承复用的是接口
下面是示例
package object; class Cleanser{ private String s = "Cleanser";//为了继承一般的潜规则时将所有的数据成员都指定为private,所有的方法都指定为public public void append(String a){s += a;} // "+=" 将几个String对象连接成s 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) //可以在每个类中都创建一个main()方法,这种在 //每个类中都设置一个main()方法的技术可使每个类的单元测试变得简单易行 //而且在测试结束后也无需删除main(),可以将其留待下次测试 { Cleanser x = new Cleanser(); x.dilute();x.apply();x.scrub(); System.out.println(x); } } public class Detergent extends Cleanser{ //extends 继承关键字 //change a method public void scrub() //可以从新定义基类的scrub()方法 { append(" Detergent.scrub()"); super.scrub(); // Call base-class version 在scrub里调用scrub会产生递归, //加super关键词表示超类的意思,当前类是从超类继承来的 } // Add methods to the interface; public void foam() {append(" foam()");} //Test the new class public static void main(String args[]) //只有命令行调用的类的main()才会被使用,比如 java Cleanser test; { Detergent x = new Detergent(); x.dilute(); x.apply(); x.scrub(); x.foam(); System.out.println(x); System.out.println("testing base class"); Cleanser.main(args); } }/* output: Cleanser dilute() apply() Detergent.scrub() scrub() foam() testing base class Cleanser dilute() apply() scrub() *///~
同时使用继承和组合
package object; class Plate{ Plate(int i) { System.out.println("plae constructor"); } } class DinnerPlate extends Plate{ DinnerPlate(int i) { super(i); System.out.println("Dinnerplate constructor"); } } class Utensil{ //器械 Utensil(int i) { System.out.println("Utensil constructor"); } } class Spoon extends Utensil{ Spoon(int i) { super(i); System.out.println("Spoon constrcutor"); } } class Fork extends Utensil{ Fork(int i) { super(i); System.out.println("fork constructor"); } } class Knife extends Utensil{ Knife(int i) { super(i); System.out.println("knife constructor"); } } //A cultural way of doing someting 有教养的去做事 class Custom{ Custom(int i) { System.out.println("custom constructor" ); } } public class PlaceSetting extends Custom{ private Spoon sp; private Fork frk; private Knife kn; private DinnerPlate pl; public PlaceSetting(int i) { super(i); sp = new Spoon(i + 2); frk = new Fork(i + 3); kn = new Knife(i + 4); pl = new DinnerPlate(i = 5); System.out.println("PlaceSeting constructor"); } public static void main(String[] args ) { PlaceSetting x = new PlaceSetting(9); } }/* output: custom constructor Utensil constructor Spoon constrcutor Utensil constructor fork constructor Utensil constructor knife constructor plae constructor Dinnerplate constructor PlaceSeting constructor *///:~
二.向上转型:由导出类转型成基类,在继承图上是向上移动的,因此一般称为向上转型
"为新的类提供方法"并不是继承技术中最重要的方面,其最重要的方面是用来表现新类和基类之间的关系,这种关系可以用"新类是现有类的一种类型"这句话概括.
//: 这种将wind转化为instrument引用的动作,我们称之为向上转型. package object; class Instrument{ public void play() { } static void tune(Instrument i) { i.play(); } } public class Wind extends Instrument{ public static void main(String[] args) { Wind wind = new Wind(); Instrument.tune(wind); } }
三.用继承设计
1.在建立新类时如果首先使用继承,反而会加重我们的设计负担,使事情变得不必要复杂起来,
更好的方式是选择组合,尤其是在不确定使用哪种方式时,组合不会强制我们的程序设计进入继承的层次结构,而且更加灵活,因为它可以动态选择类型(因此也就选择了行为),相反,继承在编译时就需要知道确切的类型
一种通用的准则时"用继承表达行为的差异,并用字段表达状态的差异"
package object;
class Ship{
public void use(){}
}
class Attackship extends Ship{
public void use(){System.out.println("attack");} //通过继承得到两个不同的类,表达了use()方法的差异
}
class AlertStatus extends Ship{
public void use(){System.out.println("Alertstaus");}
}
public class Starship {
Ship ship = new Attackship();
public void change(){ship = new AlertStatus();} //通过组合使自己的状态发生变化,状态的变化也就产生了行为的变化
public void show(){ship.use();}
public static void main(String[] args)
{
Starship ss = new Starship();
ss.show();
ss.change();
ss.show();
}
}