java8新特性之接口默认方法(扩展方法)

本文介绍了Java8引入的接口默认方法特性,旨在解决接口与实现类的耦合问题。详细讲解了默认方法的语法、简单用法、在Java8中的应用,并对比了与抽象类的区别。此外,重点探讨了多接口实现时默认方法冲突的解决方案,包括类方法优先级、子接口优先级以及显式选择默认方法。最后提到了默认方法的一些注意事项和Java8中接口的静态方法与静态变量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景:

java8新增加了特性,允许接口增加非抽象的方法实现,方法必须使用default声明,此方法可以在子类中直接使用,也可以在子类中重写,为什么要增加这一特性原因其实很简单,因为接口和实现类耦合度过高,使用java的同学肯定有感触,当要为接口增加一个方法时,所有实现类接口都要跟着改动,默认方法就是为解决这个问题而生,给接口增加方法而不破坏原有的接口实现。java8的大版本升级带来了很多功能上接口上的更新,为了向下兼容,所以增加的这一特性(bibi两句:这么解释其实有点打脸,piapia的,依然记得java8之前看过很多的书中解释为什么抽象类可以有实现方法,而接口不能有实现方法,解释为类可以实现多个接口,为了避免多个接口有同一方法等原因导致继承混乱发生所以没有方法实现)

二、语法:

背景讲完了,说一下语法吧,语法其实更简单,方法前增加default关键字即可

    /*
    java 8 新特性1 接口允许添加非抽象的方法实现(扩展方法)
     */
    interface ICar{
        default String getCarPowerTech() {
            return "Turbo";
        }
    }

三、简单的用法:

以下分别使用内部类,匿名内部类和java8函数式分别介绍一下默认方法的简单用法

public class Java8NewFeature1 {
    public Java8NewFeature1 (){
    }
    public Java8NewFeature1 (ICar iCar){
        System.out.println(iCar.getCarName());
        System.out.println(iCar.getCarPowerTech());
    }

    /*
    java 8 新特性1 接口允许添加非抽象的方法实现(扩展方法)
     */
    interface ICar{
        public static Integer carAge = 1;
        public String getCarName();
        default String getCarPowerTech() {
            return "Turbo";
        }
    }

    class Lamborghini implements ICar{
        @Override
        public String getCarName() {
            return "兰博基尼";
        }
    }


    public static void main (String[] args) {
        //内部类方式实现
        Lamborghini lamborghini = new Java8NewFeature1().new Lamborghini();
        System.out.println(lamborghini.getCarName());
        System.out.println(lamborghini.getCarPowerTech());

        //匿名内部类方式实现
        ICar icar = new ICar(){
            @Override
            public String getCarName() {
                return "兰博基尼";
            }
        };
        System.out.println(icar.getCarName());
        System.out.println(icar.getCarPowerTech());


        //java 8 简化匿名内部类实现写法
        new Java8NewFeature1(() -> "兰博基尼");
    }
}

四、java8中的使用

比如LIst接口

 default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }

Map接口

default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
}

五、与抽象类的区别

接口中有了非抽象方法的实现,其实很大的缩小了和抽象类之间的区别,但其实比较抽象类和接口的定位和定义,二者在语法上的主要区别1:接口可以被多实现,抽象类只能被单继承。2:抽象类有实例变量,接口java8以后只有类静态变量。

六、多接口实现,默认方法冲突

这一块背景中简单的提到了一下,这块也是这个知识点我花的时间相对比较多的一块,当类实现多个接口时,有默认方法冲突怎么办,别急,java8提供了解决办法

1:类方法优先级最高,类中声明的方法优先级高于所有接口中默认方法的优先级。

2:子接口优先级高于所有父接口优先级,默认方法相同时选择继承结构中最下层的子接口作为默认接口实现,即A接口继承了B接口,C接口,当ABC三个接口都有同一默认方法时,选择A接口的默认方法实现

3:1和2无法判断时,显示选择使用哪个默认方法

上例子:

当出现同一实现类实现的多个接口中有同一默认方法时,class编译失败,代码如下:

 interface A{
        default int get1(){
            return 1;
        }
    }

    interface B{
        default int get1(){
            return 1;
        }
    }

    class Test implements A,B{

    }

第一种解决办法,对默认方法进行实现,可验证第一条规则,编译通过,代码如下:

class Test implements A, B {
        public int get1() {
            return 1;
        }

第二种解决办法,改写接口的继承结构,让实现的更全面的接口继承其余接口,验证第三条规则,此时编译通过代码如下:

 interface A {
        default int get1() {
            return 1;
        }
    }

    interface B extends A{
        default int get1() {
            return 1;
        }
    }

    class Test implements A, B {
    }

第三种解决办法,显示调用想实现的接口的默认实现,验证第三条规则(也要实现默认方法,不过此时可以选择使用哪个接口中的默认方法)

class Test implements A, B {
        public int get1() {
           return A.super.get1();
        }
    }

七、其他的一些东西

1:默认方法不可以重写Object中的方法;

2:关于冲突部分的实例和说明并没有涵盖所有的情况,还有一些比较复杂的场景没有解释说明,原因是不建议和不提倡去这么只用默认方法,接口可以多继承接口,如果使用的过于复杂,会把结构弄得混乱,也容易引起莫名其妙的问题;

3:default关键字只适用于接口中的默认方法;

4:java8中也新增了静态方法和可调用静态变量

 

 

本人愿意去分享一些学过的和正在学习中的知识,但难免有一些疏漏和不足之处,还请留言说明好让我去改正。

另外学习中会参考很多公众号,文章去学习,借鉴,思考,感谢前辈们的分享,给了我更方便的学习途径。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值