Java中 什么是默认方法?
默认方法使我们能够向接口添加新功能并确保实现该接口的现有类的向后兼容性。
顾名思义,接口中的默认方法是如果在实现类中未被覆盖,则默认调用的方法。
让我们通过一个例子来理解。
Moveable
接口是一些现有的接口,希望添加一个新方法 moveFast()
。
如果它使用旧技术添加 moveFast()
方法,那么所有实现 Moveable
的类也将被更改。
所以,让我们添加 moveFast()
方法作为默认方法。
public interface Moveable { default void moveFast() { System.out.println("I am moving fast, buddy !!"); } }
如果所有实现 Moveable
接口的类都不需要改变自己(直到某些类特别想要覆盖 moveFast()
方法以添加自定义逻辑)。
所有类都可以直接调用instance.moveFast()
方法。
public class Animal implements Moveable { public static void main(String[] args) { Animal tiger = new Animal(); //Call default method using instance reference tiger.moveFast(); } }
Java 多继承时可能发生的冲突
在上面的例子中,我们有两个不同的接口和两种不同的方法,所以没有冲突。
如果两个接口都决定定义一个同名的新方法会怎样。
那么他们可以毫无问题地定义。
但是当Animal
实例调用它的名字时会调用哪个方法。
这是矛盾的情况。
package com.onitroad.examples; interface Moveable { default void run(){ System.out.println("I am running, kid !!"); } } interface Crawlable { default void run(){ System.out.println("I am running, daddy !!"); } } public class Animal implements Moveable, Crawlable { public static void main(String[] args) { Animal self = new Animal(); //如果下面的语句执行会发生声明情况? // self.run(); } }
所以解决上面的冲突,调用者类必须决定它想要调用哪个 run()
方法,然后使用接口的引用调用,如下所示。
Moveable.super.run(); //调用 Moveable的 run() 方法 //or Crawlable.super.run(); //调用 Crawlable的 run() 方法
Java 如何通过默认方法实现多重继承?
多重继承是一些面向对象的计算机编程语言的一个特性,其中一个对象或者类可以从多个父对象或者父类继承特性和行为。
我们知道在 java 中(直到 jdk 7),java 中的继承是由 extends
关键字支持的,该关键字用于从父类创建子类。
我们不能从两个类进行扩展。
在 java 7 之前,接口仅用于声明实现类必须实现的契约(除了不是 abstract
本身的实现类)。
因此,类可以继承的接口没有添加特定的行为。
因此,即使在一个类能够实现任意数量的接口之后,将其称为多重继承也是不合适的。
但是由于 java 8 的默认方法,接口也有行为。
所以现在如果一个类实现了两个接口并且都定义了默认方法,那么它本质上是从两个父级继承行为,即多重继承。
例如,在下面的代码中,Animal
类没有定义它自己的任何行为;而是从父接口继承行为。
那就是多重继承。
package com.onitroad.examples; interface Moveable { default void moveFast(){ System.out.println("I am moving fast, buddy !!"); } } interface Crawlable { default void crawl(){ System.out.println("I am crawling !!"); } } public class Animal implements Moveable, Crawlable { public static void main(String[] args) { Animal self = new Animal(); self.moveFast(); self.crawl(); } }