传统接口的“痛点”¶
在Java 8之前,接口的作用更像是一个“契约”——接口中只能定义抽象方法,所有实现类必须“完完全全”地实现这些抽象方法。如果我们想在接口中新增一个方法,那所有实现该接口的类都必须手动添加这个新方法的实现,否则代码会编译报错。这在接口需要频繁扩展时非常不方便,比如一个框架接口突然需要增加新功能,所有依赖它的类都得跟着改,很容易出问题。
接口默认方法的“救场”¶
Java 8为了解决这个问题,引入了默认方法(Default Method)。简单来说,默认方法是接口中带具体实现的方法,使用 default 关键字修饰。有了默认方法后,接口不再只能定义抽象方法,还能提供一些“默认行为”,实现类可以直接使用这些默认方法,不需要强制重写。
如何定义和使用默认方法?¶
默认方法的语法很简单,只需在方法前加上 default 关键字,并给出具体实现即可。
示例代码:
// 定义一个接口,包含默认方法
interface Greeting {
// 抽象方法(必须由实现类重写)
void sayHello();
// 默认方法(接口自带实现,实现类可直接使用)
default void sayGoodbye() {
System.out.println("Goodbye!");
}
}
// 实现接口
class EnglishGreeting implements Greeting {
@Override
public void sayHello() {
System.out.println("Hello!");
}
// 这里可以选择是否重写默认方法(可选)
// @Override
// public void sayGoodbye() {
// System.out.println("Bye-bye!");
// }
}
public class Main {
public static void main(String[] args) {
Greeting greeter = new EnglishGreeting();
greeter.sayHello(); // 输出:Hello!
greeter.sayGoodbye(); // 输出:Goodbye!(直接使用默认实现)
}
}
在这个例子中:
- sayHello() 是抽象方法,实现类 EnglishGreeting 必须重写。
- sayGoodbye() 是默认方法,实现类无需手动实现,可直接调用。
实现类如何重写默认方法?¶
如果实现类觉得接口的默认方法不符合自身需求,可以像重写父类方法一样,重写默认方法。只需要在实现类中用 @Override 注解重新定义该方法即可。
示例代码:
class ChineseGreeting implements Greeting {
@Override
public void sayHello() {
System.out.println("你好!");
}
@Override
public void sayGoodbye() {
System.out.println("再见!"); // 重写默认方法
}
}
public class Main {
public static void main(String[] args) {
Greeting chineseGreeter = new ChineseGreeting();
chineseGreeter.sayGoodbye(); // 输出:再见!(使用重写后的默认方法)
}
}
注意:默认方法的冲突问题¶
如果一个类同时实现了多个接口,且这些接口中包含同名、同参数的默认方法,就会产生冲突。此时实现类必须显式重写该方法,否则编译报错。
示例代码:
interface A {
default void method() {
System.out.println("A's method");
}
}
interface B {
default void method() {
System.out.println("B's method");
}
}
// 类C同时实现A和B,会冲突!
class C implements A, B {
// 必须显式重写method()来解决冲突
@Override
public void method() {
System.out.println("C's method");
}
}
如果没有重写,编译器会报错:The type C must implement the inherited abstract method...(或类似冲突提示)。
总结:默认方法的意义¶
默认方法让接口变得更灵活:
1. 扩展接口不破坏现有实现:新增方法时,旧实现类无需修改,直接继承默认方法。
2. 接口更像“带默认行为的契约”:可以给接口提供基础功能,实现类按需重写或直接使用。
3. 避免了抽象类的缺点:抽象类需要继承,而接口可以多实现;默认方法让接口兼具“可扩展”和“契约性”。
小试牛刀¶
试着定义一个带默认方法的接口 Shape,包含抽象方法 getArea() 和默认方法 printInfo()(默认打印“这是一个图形”),然后实现一个 Circle 类继承该接口并测试。
提示:
- 接口 Shape:default void printInfo() { System.out.println("这是一个图形"); }
- 类 Circle:实现 getArea() 方法,例如计算半径为5的圆面积(πr²),并调用默认方法。
默认方法是Java 8的重要特性,它让接口从“纯抽象契约”升级为“可扩展的工具”,是面向对象设计中接口灵活性的一次重要提升。掌握它后,写代码时会更轻松!