Java 默认方法冲突,一个类实现了两个接口,每个接口包含的默认方法相同,但实现不同。在类中实现方法。借由关键字 super
,实现仍然可以使用接口提供的默认方法。Java 8 支持在接口中使用静态和默认方法。默认方法提供由类继承的实现,这使得接口可以在不破坏现有类实现的情况下添加新的方法。
Java 默认方法冲突 问题描述
一个类实现了两个接口,每个接口包含的默认方法相同,但实现不同。
Java 默认方法冲突 解决方案
在类中实现方法。借由关键字 super
,实现仍然可以使用接口提供的默认方法。
Java 默认方法冲突 具体实例
Java 8 支持在接口中使用静态和默认方法。默认方法提供由类继承的实现,这使得接口可以在不破坏现有类实现的情况下添加新的方法。
由于一个类可以实现多个接口,它既可能继承具有相同签名但实现不同的默认方法,也可能已包含自己的默认方法。
此时需要考虑以下三种情况。
- 如果类的方法和接口的默认方法发生冲突,则类的方法始终优先。
- 如果两个接口(其中一个接口是另一个的后代)发生冲突,则后代接口优先;如果两个类(其中一个类是另一个的后代)发生冲突,则后代类优先。
- 如果两个默认方法之间不存在继承关系,则类无法编译。
对于第三种情况,只需在类中实现方法即可,第三种情况将简化为第一种情况。
观察例 5-13 所示的 Company
接口和例 5-14 所示的 Employee
接口。
例 5-13 包含默认方法的
Company
接口
public interface Company {
default String getName() {
return "Initech";
}
// 其他方法
}
关键字 default
将 getName
方法指定为默认方法,它提供一个返回企业名称的实现。
例 5-14 包含默认方法的
Employee
接口
public interface Employee {
String getFirst();
String getLast();
void convertCaffeineToCodeForMoney();
default String getName() {
return String.format("%s %s", getFirst(), getLast());
}
}
Employee
接口同样定义了一个名为 getName
的默认方法,其签名与 Company
接口中的 getName
方法相同,但二者的实现不同。如例 5-15 所示,CompanyEmployee
类实现了 Company
和 Employee
两个接口,从而导致冲突。
例 5-15 最初的
CompanyEmployee
类(无法编译)
public class CompanyEmployee implements Company, Employee {
private String first;
private String last;
@Override
public void convertCaffeineToCodeForMoney() {
System.out.println("Coding...");
}
@Override
public String getFirst() {
return first;
}
@Override
Public String getLast() {
return last;
}
}
由于 CompanyEmployee
类继承了与 getName
无关的默认方法,它无法编译。为解决这个问题,需要在 CompanyEmployee
类中添加用户自定义的 getName
方法,它将重写两个默认方法。
不过,借由关键字 super
,仍然可以使用所提供的默认方法,如例 5-16 所示。
例 5-16 调整后的
CompanyEmployee
类
public class CompanyEmployee implements Company, Employee {
@Override
public String getName() { ➊
return String.format("%s working for %s",
Employee.super.getName(), Company.super.getName()); ➋
}
// 其余代码和之前一样
}
❶ 实现 getName
方法
❷ 通过 super
访问默认实现
可以看到,CompanyEmployee
类中的 getName
方法根据 Company
和 Employee
接口定义的两个默认方法 getName
构建了一个 String
。
最好的消息是,这与默认方法一样复杂。读者现在已经了解了如何处理默认方法冲突。
实际上,我们还要考虑一种极端情况。如果 Company
接口定义了 getName
方法但没有将其指定为 default
(也不存在相应的实现,即 getName
成为抽象方法),那么当 Employee
接口也定义了 getName
方法时,是否还会导致冲突呢?答案是肯定的。有趣的是,仍然需要在 CompanyEmployee
类中提供一个实现。
在 Java 8 之前,如果两个接口包含相同的方法且没有指定为默认方法,这并不会导致冲突,但类必须提供一个实现。