Java8新特性:默认方法详解

Java大联盟

致力于最高效的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();
    }
}

运行结果如下图所示。

往期文章一览

1、Java8新特性:方法引用详解

2、Java8新特性:Lambda表达式详解

3、仿照源码,手写一个自定义 Spring MVC 框架

原文发布于微信公众号 - Java大联盟(javaunion)

原文发表时间:2019-07-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券