先来看个最正宗的定义 如果对每一个类型为S的对象o1,都有类型为T的对 象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变 化,那么类型S是类型T的子类型。 我们再来看一个通俗易懂的定义: 所有引用基类的地方必须能透明地使用其子类的 对象。 下面来看一下uml图
public abstract class AbstractGun {
//枪用来干什么的?杀敌!
public abstract void shoot();
}
//手枪、步枪、机枪的实现类如代码清单2-2所示。 代码清单2-2 手枪、步枪、机枪的实现类
public class Handgun extends AbstractGun {
//手枪的特点是携带方便,射程短
@Override
public void shoot() {
System.out.println("手枪射击...");
}
}
public class Rifle extends AbstractGun{
//步枪的特点是射程远,威力大
public void shoot(){
System.out.println("步枪射击...");
}
}
public class MachineGun extends AbstractGun{
public void shoot(){
System.out.println("机枪扫射...");
}
}
//有了枪支,还要有能够使用这些枪支的士兵,其源程序如士兵的实现类
public class Soldier {
//定义士兵的枪支
private AbstractGun gun;
//给士兵一支枪
public void setGun(AbstractGun _gun){
this.gun = _gun;
}
public void killEnemy(){
System.out.println("士兵开始杀敌人...");
gun.shoot();
}
}
//定义士兵使用枪来杀敌,但是这把枪是抽象的,具体是手枪还是步枪需 要在上战场前(也就是场景中)前通过setGun方法确定
public class Client {
public static void main(String[] args) {
//产生三毛这个士兵
Soldier sanMao = new Soldier();
//给三毛一支枪
sanMao.setGun(new Rifle());
sanMao.killEnemy();
}
}
在项目中难免会遇到一些比较特殊的子类,此时建议采用聚合或者组合来进行
比如如下
public class ToyGun extends AbstractGun {
//玩具枪是不能射击的,但是编译器又要求实现这个方法,怎么办?虚构一个呗!
@Override
public void shoot() {
//玩具枪不能射击,这个方法就不实现了
}
}
public class Client {
public static void main(String[] args) {
//产生三毛这个士兵
Soldier sanMao = new Soldier();
sanMao.setGun(new ToyGun());
sanMao.killEnemy();
}
}
此种情况建议采用如下的方式进行实现 同样我们来看一下uml图
public class AUG extends Rifle {
//狙击枪都携带一个精准的望远镜
public void zoomOut(){
System.out.println("通过望远镜察看敌人...");
public void shoot(){
System.out.println("AUG射击...");
}
}
public class Snipper {
public void killEnemy(AUG aug){
//首先看看敌人的情况,别杀死敌人,自己也被人干掉
aug.zoomOut();
//开始射击
aug.shoot();
}
}
public class Client {
public static void main(String[] args) {
//产生三毛这个狙击手
Snipper sanMao = new Snipper();
sanMao.setRifle(new AUG());
sanMao.killEnemy();
}
}
为了满足设计满足“里氏替换”原则,子类不能太有个性,子类重载父类的方法时,入参要更加宽泛,大于等于父类,返回值要收缩,要小于等于父类。 下面来看一下具体的代码描述
public class Father {
public Collection doSomething(HashMap map){
System.out.println("父类被执行...");
return map.values();
}
}
public class Son extends Father {
//放大输入参数类型
public Collection doSomething(Map map){
System.out.println("子类被执行...");
return map.values();
}
}
public class Client {
public static void invoker(){
//父类存在的地方,子类就应该能够存在
Father f = new Father();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void main(String[] args) {
invoker();
}
}