《Java8实战》笔记(09):默认方法

Java 8引入了默认方法,允许接口提供方法实现,以兼容的方式更新API。当接口升级添加默认方法时,已有实现类无需修改即可继承新方法。默认方法可能导致冲突,但可通过选择最具体实现的接口或显式覆盖来解决。本文通过示例解释了默认方法的使用、冲突规则和菱形继承问题。
摘要由CSDN通过智能技术生成

默认方法

本文的源码

实现接口的类必须为接口中定义的每个方法提供一个实现,或者从父类中继承它的实现。但是,一旦类库的设计者需要更新接口,向其中加入新的方法,这种方式就会出现问题。现实情况是,现存的实体类往往不在接口设计者的控制范围之内,这些实体类为了适配新的接口约定也需要进行修改。由于Java 8的API在现存的接口上引入了非常多的新方法,这种变化带来的问题也愈加严重,一个例子就是像Guava和Apache Commons这样的框架现在都需要修改实现了List接口的所有类,为其添加sort方法的实现。

Java 8为了解决这一问题引入了一种新的机制。Java 8中的接口现在支持在声明方法的同时提供实现!通过两种方式可以完成这种操作。

  1. Java 8允许在接口内声明静态方法。
  2. Java 8引入了一个新功能,叫默认方法,通过默认方法你可以指定接口方法的默认实现。

换句话说,接口能提供方法的具体实现。因此,实现接口的类如果不显式地提供该方法的具体实现,就会自动继承默认的实现。这种机制可以使你平滑地进行接口的优化和演进。实际上,到目前为止你已经使用了多个默认方法。


两个例子

List接口中的sort方法是Java 8中全新的方法,它的定义如下:

default void sort(Comparator<? super E> c){
   
    Collections.sort(this, c);
}

Collection中的stream方法的定义如下

default Stream<E> stream() {
   
    return StreamSupport.stream(spliterator(), false);
}

默认方法的引入就是为了以兼容的方式解决像Java API这样的类库的演进问题的

不断演进的API

为了理解为什么一旦API发布之后,它的演进就变得非常困难,

假设你是一个流行Java绘图库的设计者

你的库中包含了一个Resizable接口,它定义了一个简单的可缩放形状必须支持的很多方法, 比如:setHeight、setWidth、getHeight、getWidth以及setAbsoluteSize。此外,你还提供了几个额外的实现(out-of-box implementation),如正方形、长方形。由于你的库非常流行,你的一些用户使用Resizable接口创建了他们自己感兴趣的实现,比如椭圆。

发布API几个月之后,你突然意识到Resizable接口遗漏了一些功能。比如,如果接口提供一个setRelativeSize方法,可以接受参数实现对形状的大小进行调整,那么接口的易用性会更好。

你会说这看起来很容易啊:为Resizable接口添加setRelativeSize方法,再更新Square和Rectangle的实现就好了。不过,事情并非如此简单!你要考虑已经使用了你接口的用户,他们已经按照自身的需求实现了Resizable接口,他们该如何应对这样的变更呢

非常不幸,你无法访问,也无法改动他们实现了Resizable接口的类。这也是Java库的设计者需要改进Java API时面对的问题。

初始版本的API

public interface Resizable extends Drawable{
   
    int getWidth();
    int getHeight();
    void setWidth(int width);
    void setHeight(int height);
    void setAbsoluteSize(int width, int height);
}

用户实现

用户根据自身的需求实现了Resizable接口,创建了Ellipse类:

	public class Ellipse implements Resizable {
   }

他实现了一个处理各种Resizable形状(包括Ellipse)的游戏:

public class Game{
   
    public static void main(String...args){
   
        List<Resizable> resizableShapes =
        Arrays.asList(new Square(), new Rectangle(), new Ellipse());
        Utils.paint(resizableShapes);
    }
}
public class Utils{
   
    public static void paint(List<Resizable> l){
   
        l.forEach(r -> {
   
            r.setAbsoluteSize(42, 42);
            r.draw();
        });
    }
}

第二版API

库上线使用几个月之后,你收到很多请求,要求你更新Resizable的实现,让Square、Rectangle以及其他的形状都能支持setRelativeSize方法。为了满足这些新的需求,你发布了第二版API

public interface Resizable {
   
    //...
    void setRelativeSize
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值