打字猴:1.70045475e+09
1700454750
1700454751 sanMao.setRifle(new AUG());
1700454752
1700454753 sanMao.killEnemy();
1700454754
1700454755 }
1700454756
1700454757 }
1700454758
1700454759 狙击手使用G3杀死敌人,运行结果如下所示:
1700454760
1700454761 通过望远镜察看敌人……
1700454762
1700454763 AUG射击……
1700454764
1700454765 在这里,系统直接调用了子类,狙击手是很依赖枪支的,别说换一个型号的枪了,就是换一个同型号的枪也会影响射击,所以这里就直接把子类传递了进来。这个时候,我们能不能直接使用父类传递进来呢?修改一下Client类,如代码清单2-10所示。
1700454766
1700454767 代码清单2-10 使用父类作为参数
1700454768
1700454769 public class Client{
1700454770
1700454771 public static void main(String[]args){
1700454772
1700454773 //产生三毛这个狙击手
1700454774
1700454775 Snipper sanMao=new Snipper();
1700454776
1700454777 sanMao.setRifle((AUG)(new Rifle()));
1700454778
1700454779 sanMao.killEnemy();
1700454780
1700454781 }
1700454782
1700454783 }
1700454784
1700454785 显示是不行的,会在运行期抛出java.lang.ClassCastException异常,这也是大家经常说的向下转型(downcast)是不安全的,从里氏替换原则来看,就是有子类出现的地方父类未必就可以出现。
1700454786
1700454787 3.覆盖或实现父类的方法时输入参数可以被放大
1700454788
1700454789 方法中的输入参数称为前置条件,这是什么意思呢?大家做过Web Service开发就应该知道有一个“契约优先”的原则,也就是先定义出WSDL接口,制定好双方的开发协议,然后再各自实现。里氏替换原则也要求制定一个契约,就是父类或接口,这种设计方法也叫做Design by Contract(契约设计),与里氏替换原则有着异曲同工之妙。契约制定了,也就同时制定了前置条件和后置条件,前置条件就是你要让我执行,就必须满足我的条件;后置条件就是我执行完了需要反馈,标准是什么。这个比较难理解,我们来看一个例子,我们先定义一个Father类,如代码清单2-11所示。
1700454790
1700454791 代码清单2-11  Father类源代码
1700454792
1700454793 public class Father{
1700454794
1700454795 public Collection doSomething(HashMap map){
1700454796
1700454797 System.out.println(“父类被执行……”);
1700454798
1700454799 return map.values();
[ 上一页 ]  [ :1.70045475e+09 ]  [ 下一页 ]