致力于最高效的Java学习
什么是默认方法
Java8 中的默认方法是针对接口添加的新特性,它是指接口可以直接对方法进行实现,实现方式很简单,直接在方法定义处添加 default 关键字即可,如下所示。
public interface MyInterface {
default void test(){
System.out.println("这是一个默认方法...");
}
}
虽然接口中可以直接定义方法,但是调用该方法还是需要实例化对象,所以仍然需要创建接口的实现类,区别在于实现类不必对默认方法进行具体实现,如下所示。
public class MyImplements implements MyInterface {
}
根据实现类创建接口的实例化对象,调用默认方法,如下所示。
public class Test {
public static void main(String[] args) {
MyInterface myInterface = new MyImplements();
myInterface.test();
}
}
运行结果如下图所示。
同时我们也可以在实现类中对方法进行实现,从而覆盖接口中的默认方法,如下所示。
public class MyImplements implements MyInterface {
@Override
public void test() {
System.out.println("这是实现类的方法...");
}
}
再次运行测试方法,结果如下图所示。
当然也可以通过匿名类的方式对默认方法进行覆盖,如下所示。
public class Test {
public static void main(String[] args) {
MyInterface myInterface = new MyInterface() {
@Override
public void test() {
System.out.println("这是匿名类方法...");
}
};
myInterface.test();
}
}
运行结果如下图所示。
了解完默认方法的概念和使用,接下来我们说一说为什么要使用默认方法。
面向接口编程可以实现代码的解耦合,从而提高程序的扩展性,但是这种方式也存在明显的不足,当对接口进行修改时,所有的实现类都要同步修改,这样就非常麻烦,使用默认方法可以解决这一问题,只需要修改接口的默认方法即可,实现类不需要进行处理。
默认方法在 Java8 中的实际应用
Java8 针对集合操作提供了一个新的方法 forEach,并将其定义在 Iterable 接口中,如果没有默认方法机制,那么 Java8 中所有的 Iterable 实现类都需要修改,接口和实现类高度耦合,默认方法可以完美地解决这一问题,只需要将 forEach 定义成默认方法即可,源码如下图所示。
默认方法的继承
默认方法支持继承,即子接口可以继承父接口中的默认方法,如下所示。
/**
* 父接口
*/
public interface MyInterface {
default void test(){
System.out.println("这是一个默认方法...");
}
}
/**
* 子接口
*/
public interface MyInterfaceB extends MyInterface {
}
/**
* 实现类
*/
public class MyImplements implements MyInterfaceB {
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
MyInterfaceB myInterfaceB = new MyImplements();
myInterfaceB.test();
}
}
运行结果如下图所示。
同时子接口也可以完成对父接口默认方法的重写,如下所示。
/**
* 父接口
*/
public interface MyInterface {
default void test(){
System.out.println("这是一个默认方法...");
}
}
/**
* 子接口
*/
public interface MyInterfaceB extends MyInterface {
@Override
default void test() {
System.out.println("这是子接口的默认方法...");
}
}
/**
* 实现类
*/
public class MyImplements implements MyInterfaceB {
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
MyInterfaceB myInterfaceB = new MyImplements();
myInterfaceB.test();
}
}
运行结果如下图所示。
接口多实现场景下默认方法冲突的解决方案
如果两个不同的接口中定义同名的默认方法,创建一个实现类来同时实现这两个接口,就会出现问题,代码如下所示。
/**
* 接口1
*/
public interface Run {
default void test(){
System.out.println("跑起来了...");
}
}
/**
* 接口2
*/
public interface Fly {
default void test(){
System.out.println("飞起来了...");
}
}
public class MyImplements implements Run,Fly {
}
异常信息如下图所示。
MyImplements 无法区分两个默认方法,此时需要在实现类中通过 super 关键字来指定调用哪个接口的默认方法,如下所示。
public class MyImplements implements Run,Fly {
public void test(){
Fly.super.test();
}
}
同时也可以在实现类中对方法进行重新定义,覆盖接口的默认方法,如下所示。
public class MyImplements implements Run,Fly {
public void test(){
System.out.println("MyImplements...");
}
}
静态默认方法
默认方法也可以定义为静态,直接通过接口调用,具体操作如下所示。
public interface MyInterface {
static void staticTest(){
System.out.println("这是一个静态默认方法...");
}
}
public class Test {
public static void main(String[] args) {
MyInterface.staticTest();
}
}
运行结果如下图所示。
往期文章一览