如何理解 Java 中的接口(interface)()

【如何理解 Java 中的接口(interface)()】Java 中的接口(interface)如何理解?
interface 的实现(implement)不同于类(class)的继承(extend),因为 interface 中不包含方法(method)的实现(implement)。
于是很多人就会疑惑,既然 interface 中的 method 没有 implement,那么 extend(implement)它做什么呢?
这些人实际上把 interface 的 implement 和 class 的 extend 混淆了——class 的 extend 中,子类可以从父类中取得一些实现(implement),从而实现(realize)代码复用。
但是 interface 恰恰不是用来 realize 代码复用的。
为了表现 interface 的作用,我们来看一个例子。
这是一个 class (修饰符已略去)

class Tiger { void run() { // method body } void eat() { // method body } }

可以看到有 2 个方法。
Java 是一门静态类型语言,我们可以用 class 名作为参数类型,这是众所周知的。
void feed(Tiger tiger) { tiger.eat() }

但是,如果我们有了新的需求呢?
例如,我们又有了一个新的 class
class Fish { void swim() { // method body } void eat() { // method body } }

这个Fishclass 和Tigerclass 一样有一个eat()method,我们希望feedmethod 也能对Fish对象起作用。
当然,我们可以使用 method 的重载(overload)。
void feed(Tiger tiger) { tiger.eat() } void feed(Fish fish) { fish.eat() }

不过可以遇见,要是这样的 class 越来越多,我们的工作量就很大了。更何况,这里的代码基本上完全重复了嘛。
这说明什么?说明 overload 的方案的扩展性并不强,我们需要一个一劳永逸的方案。
理论上,我们可以采用这么一个方案
维护一个集合(set) FeedableAnimals,用来记录那些我们希望feedmethod 能起作用的 class。然后我们的feedmethod 就这么写。(Java 不支持这种语法,因此你只能在脑中这么做)
void feed(FeedableAnimials animal) { animal.eat() }

然后把TigerFish 等等放进 FeedableAnimals里。
现在,我就明确告诉你,这个FeedableAnimals就是 interface 概念的雏形。
现在,我们离真正的 interface 只差几步了。
考虑我们现在这个方案,看起来比原来好多了。
但是仔细想想,还有一些不足
第一,FeedableAnimals作为一个 set,是需要维护的:如果我们添加新的一种 class,比如Bear,那么我们必须修改其定义,将这个 classBear添加进去。
显然,这不符合开闭原则——对修改封闭。
第二,假设我们把Bear添加进来,但是由于疏忽,我们没有确认Bear是否有一个eat()method。不妨假设,Bear实际上长这样
class Bear { void run() { // method body } void eat(Fish fish) { // method body } }

这时Bear有一个methodeat(Fish),于是我们的工作人员产生了疏忽,误以为Bear有一个eat()method(这两者的方法签名(Method Signature)并不相同!)就把它加了进来。
固然,我们可以人工一个个浏览FeedableAnimals中的 class,检查其是否具有正确的 method signature。但是如果能让编译器来做这件事显然更合理,因为保证语法没有错误是编译器的工作。
于是,在 Java 中,真正的 interface 是这样设计的:
  1. interface 并不记录 class,相反,是 class 记录 interface。
  2. interface 可以定义抽象 method,抽象 method 仅仅包含 method signature。如果 class implement 了 interface,那么编译器会检查 class 中是否有对应的 method signature。
可以看到,这样的设计克服了上述两点困难。我们可以回到上面那个例子看一看。
定义一个 interface FeedableAnimals
interface FeedableAnimals { void eat(); }

然后feedmethod 应该这么写:
void feed(FeedableAnimals animal) { animal.eat() }

这时,由于 interfaceFeedableAnimals中确实规定了 method signatureeat(),因此编译器能够保证对于任何一个 implement 了 FeedableAnimals 的对象 animal 来说,animal.eat() 的调用不会出现语法错误(例如animal 找不到 eat() 方法这样的报错)。这样,从编译器层面就排除了feedmethod 跑不通的可能性。
Bear class 应该这么写
class Bear implements FeedableAnimals { void eat() { // method implement } }

这样一旦出现诸如 method signature 不符、或者是 method 忘了实现这样的错误,由于我们已经声明了Bear是 implement 了 interface FeedableAnimals 的,因此编译器就能帮我们检查和发现这些错误,从而在编译阶段就杜绝这些错误的可能性。
并且以后再出现新的 class,我们也只需要像Bear那样写,就能保证feedmethod 能自动被应用在这些新 class 的对象上。

    推荐阅读