接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。
抽象类和抽象方法
包含抽象方法的类叫做抽象类。
抽象方法的语法:abstract void f();
- 抽象方法仅有声明而没有方法体
- 对于抽象类我们会用关键字abstract限定抽象类
- 抽象类中可以有普通的方法
抽象是一个概念,关于抽象可以单独拿出来当哲学类的书讲了,我就粗略讲下与我们编程有关的知识。
我们说Instrument(乐器)是一种概念,就乐器来说我们不能明确的给出一个对象,因此抽象类是不能实例化的(编译器会报错),但我们对于乐器我们可以说吉他是一种乐器,即吉他是继承自乐器这个抽象类的,而吉他我们就可以创建它的对象,继承了抽象类的类与普通类没有什么区别。
abstract Class Instrument{
public abstract void play();
}
Class Guitar extends Instrument{
publci void play(){print(" play Guitar");}
}
- 抽象类与抽象方法主要是为了使类的抽象性明确起来,并告诉用户和编译器怎样来使用它们。
- 抽象类还是很有用的重构工具,它们使得我们可以很容易地将公共方法沿着继承层次结构向上移动
接口
接口可以说是抽象类在抽象概念上的更进一步,我们在接口中只能定义没有任何具体实现的方法,即接口中的方法只有声明没有方法体。
- 我们用interface关键字来代替Class关键字
- 我们不使用extends而是使用implements来继承接口
- 实现了接口的类变为一个普通的类,可以按常规方法扩展和继承它
- 接口中被定义的方法必须被定义为public的,即使你不写它们也自动都是public的
- 对于实现类我们必须给出接口类中所有方法的方法体(内容为空也行,但必须有方法体,例public void f(){})
Java的多重继承
有时候我们需要表示“一个x是一个a和一个b以及一个c”这意味着我们需要让x实现a、b、c。
- 如果我们需要实现多个接口,那么我们可以将所有的接口名都置于implements关键字后,然后用逗号将它们一个个隔开
- 如果我们需要实现接口和继承一个具体类,那么我们必须将继承具体类放在前面,后面才是接口,即extends要放在前面,后面才是implements。例:Class X extends A implements B,C
通过继承来扩展接口
我们可以通过extends来扩展接口:
interface A{}
interface B extends A{}
inteface C{}
inteface D extends B,C{}
- 一般来说将extends用于单一类,但是对于接口继承我们可以引用多个基类接口,只需用逗号将接口名一一分隔开即可。
- 组合不同的接口可以方便我们的设计,但组合的不同接口中最好不要使用相同的方法名(因为有可能方法名一样但返回类型不同),免得造成代码可读性的混乱
接口中的域
因为我们放进接口中的任何域都自动的是static和final的,所以接口就成为了一种很便捷的用来创建常量组的工具。
- 注意:Java中表示具有常量初始化值的static和final时,会使用大写字母的风格(一个标识符中用下划线来分隔多个单词)
总结
- 许多人只要有可能就去创建接口和工厂,这种逻辑看起来好像是因为需要使用不同的具体实现,因此总是应该添加这种抽象性。这实际上已经变成一种草率的设计优化。
- 任何抽象性都应该是应真正的需求而产生的。当必须时,你应该重构接口而不是到处添加额外级别的间接性,并由此带来额外的复杂性。
- 恰当的选择应该是优先选择类而不是接口。从类开始,如果接口的必须性变得非常明确,那么就进行重构。接口是一种重要的工具,但我们不能轻易地滥用。
以上总结自《Java编程思想(Thinking in Java)》——YayayaHong