Java 默认方法

2025 年 8 月 12 日 | 阅读 5 分钟

在 Java 中,默认方法是在 Java 8 中引入的。默认方法是在接口中定义并具有具体实现的。它允许我们在接口内部直接定义方法体。这些方法是非抽象方法。

在 Java 8 之前,接口只能包含抽象方法。这意味着实现类负责提供方法的实现。

默认方法使用 default 关键字定义在方法的返回类型之前。

为什么需要默认方法?

Java 8 之前

  • 接口只能包含抽象方法
  • 添加新方法意味着每个实现类都必须定义它——这会破坏向后兼容性。

有了默认方法

  • 我们可以为接口添加新功能。
  • 现有类不需要实现新方法,除非它们想要覆盖它。

示例:默认方法

示例

编译并运行

输出

Greetings!
Hello from default method!

多重继承冲突

如果一个类实现了两个具有相同默认方法的接口,它必须覆盖该方法以解决歧义。例如,考虑以下程序。

在上面的程序中,我们定义了两个接口 A 和 B。它们都具有 show() 默认方法。主类 C 同时实现了接口 A 和 B,这会导致方法歧义,因为 Java 不知道要继承哪个 show()。

为了解决这个歧义,C 覆盖了 show() 方法,并通过 A.super.show() 或 B.super.show() 显式调用其中一个超接口的版本。

如果调用 A.super.show(),我们会得到 A 的默认输出。如果调用 B.super.show(),我们会得到 B 的默认输出。

默认方法的特点

覆盖:实现类可以选择使用默认实现,也可以覆盖它以提供自己的特定行为。

行为的多重继承:默认方法允许一种形式的行为多重继承,因为一个类可以实现多个接口,每个接口都可能包含默认方法。这与传统的类继承不同,后者只允许单重继承。

冲突解决:如果一个类实现了多个定义了具有相同签名的默认方法的接口(“菱形问题”),则实现类必须显式覆盖有冲突的方法以解决歧义。它还可以使用 InterfaceName.super.methodName() 显式调用特定接口的默认方法。

向后兼容性:它们使得在不强制所有实现类立即提供实现的情况下向现有接口添加新方法成为可能,从而防止现有代码库被破坏。

例如,Java 8 中添加到 Iterable 接口的 forEach 方法是一个默认方法。

代码重用性:它们允许接口为方法提供默认行为,减少了实现类中可能出现的代码重复,否则这些类可能会提供相同的样板实现。

Java 8 接口中的静态方法

我们也可以在接口中定义静态方法。静态方法用于定义实用工具方法。

以下示例解释了如何在接口中实现静态方法。

示例

编译并运行

输出

Hello, this is default method.
This is abstract method.
This is static method.

抽象类与 Java 8 接口

在接口中拥有默认方法和静态方法之后,我们考虑 Java 中抽象类的必要性。接口和抽象类几乎是相似的,除了你可以在抽象类中创建构造函数,而在接口中不能。例如,考虑以下程序。

示例

编译并运行

输出

You can create constructor in abstract class
Addition: 30
Subtraction: 10
Multiplication: 200

Java 默认方法选择题

1. 关于接口中的默认方法,以下哪个陈述是正确的?

  1. 默认方法必须在所有实现类中被覆盖。
  2. 默认方法可以有一个方法体,并且可以在实现类中被覆盖,也可以不被覆盖。
  3. 默认方法不能存在于接口中。
  4. 默认方法必须是抽象的。
 

答案:B

解释:默认方法是在 Java 8 中引入的,可以有一个方法体(实现)。它们不是抽象的,除非在实现类中需要特定行为,否则不需要被覆盖。


2. 以下代码的输出是什么?

  1. 编译错误
  2. 运行时错误
  3. 无输出
  4. 默认方法
 

答案:D

解释:接口 Sayable 有一个默认方法 say(),它被类 Test 继承。因此,Test 可以调用 say(),它将打印 Default Method。


3. 在 Java 8 中,用于在接口中定义具有默认实现的方法的关键字是什么?

  1. static
  2. final
  3. abstract
  4. default
 

答案: D

解释:在 Java 8 中,default 关键字用于接口中定义具有方法体的方法,从而为接口更改提供向后兼容性。


4. 以下关于 Java 接口中静态方法的说法哪个是正确的?

  1. 它们可以使用对象引用调用。
  2. 它们可以被实现类继承。
  3. 它们必须使用接口名调用。
  4. 它们不能在接口中定义。
 

答案:C

解释:接口中的静态方法不会被继承,必须使用接口名调用,例如 InterfaceName.method()。


5. 在 Java 接口中,以下哪个是不可能的?

  1. 抽象方法
  2. 静态方法
  3. 构造函数
  4. 默认方法
 

答案:C

解释:Java 接口不能有构造函数,因为接口不能被直接实例化。它们可以包含抽象方法、静态方法和默认方法。