MIT软件构造 -- ADT Patterns: Interfaces, Generics, and Enums

接口(Interfaces)

基本概念不再赘述,值得注意(记住)的有几点:

  1. 接口不应该有构造函数
  2. 只有静态方法才能拥有方法体
  3. 接口实现不能破坏表示不变性
  4. 接口实现可以添加接口没有的方法,但是不能缺少接口声明的方法
  5. 接口实现不应该违背接口规约(比如接口规约声明为不可变类型,但在实现类里加入了mutator)

子类型(subtype)

a是b的子类型,则a要么implement b,要么extend b。
a是b的子类(subclass),则a extend b。

(随着接口的提出,java似乎是第一个跳出来说出子类型与子类是有区别的语言,并在某种意义上不鼓励继承,而推崇接口与实现。)

Q: ArrayList是可变的,List.of()是不可变的,它们都是List的合法子类型,那么List到底是可变还是不可变的呢?
A: 答案是模糊的,事实上List、Map、Set等接口的规约中对此接口ADT到底是可变还是不可变的并没有明确的声明。同时要注意的是,子类型的规约强度应高于产生子类型的类型的规约强度(precondition变弱或postcondition变强)

泛型(Generic Types)

泛型的提出让java设计的重用性变得更上一层楼,它与接口相互结合,让java拥有了自己的特色。

接口的好处

  1. 接口可以让编译器帮忙检查ADT(实现类)的明显错误
  2. 提供多种功能,不同实现方法在不同操作上可能效率不同

子类(Subclass)与继承

继承父类与实现接口的区别在于rep也会从父类传到子类,但是非严格继承是容易产生错误的(此部分原文没有)

final对继承的影响:

final修饰父类方法,子类无法重写
final修饰父类,不能继承

非严格继承

子类中重写了父类的方法(难保证语义没有改变)
辨析下面的例子

 class Animal(){
 	public void eat(){}
 }
 
 class Duck extends Animal(){
  	public void eat(String food){}
  }

运行下面的代码,结果分别是什么?

Animal test = new Animal()
test.eat()		//正确使用

Duck duck = new Animal()
duck.eat()		//正确使用  Duck中有父类的eat方法

Animal test1 = new Duck()
test1.eat()		//正确使用

Duck duck1 = new Duck()
test.eat("food")		//正确使用

Animal test2 = new Animal()
test2.eat("food")		//错误使用

Animal test3 = new Duck()
test3.eat("duck")		//错误!test3虽然是指向Duck的引用,但本身是Animal类,并没有eat(String s)方法

初学者很容易出现第第六块的错误,解决方法如下:

1、直接用Horse类声明,就像第四块
2、向下转型,原则上第六块的错误是向上转型导致的
3、在Animal类中声明eat(String s)方法

你可能感兴趣的:(MIT软件构造 -- ADT Patterns: Interfaces, Generics, and Enums)