Java8笔记(4)
默认方法
传统上,Java程序的接口是将相关方法按照约定组合到一起的方式。实现接口的类必须为接
口中定义的每个方法提供一个实现,或者从父类中继承它的实现。但是,一旦类库的设计者需要更新接口,向其中加入新的方法,这种方式就会出现问题。现实情况是,现存的实体类往往不在接口设计者的控制范围之内,这些实体类为了适配新的接口约定也需要进行修改
Java 8为了解决这一问题引入了一种新的机制,通过两种方式可以完成这种操作。
-
其一,Java 8允许在接口内声明静态方法。
-
其二,Java 8引入了一个新功能,叫默认方法,通过默认方法你可以指定接口方法的默认实现。换句话说,接口能提供方法的具体实现。因此,实现接口的类如果不显式地提供该方法的具体实现,就会自动继承默认的实现。这种机制可以使你平滑地进行接口的优化和演进
默认方法的引入就是为了以兼容的方式解决像Java API这样的类库的演进问题的:
简而言之,向接口添加方法是诸多问题的罪恶之源;一旦接口发生变化,实现这些接口的类
往往也需要更新,提供新添方法的实现才能适配接口的变化。如果你对接口以及它所有相关的实现有完全的控制,这可能不是个大问题。但是这种情况是极少的。这就是引入默认方法的目的:它让类可以自动地继承接口的一个默认实现
不断演进的 API
假设你是一个流行Java绘图库的设计者(为了说明本节的内容,我们做了这样的假想)。你的库中包含了一个 Resizable接口,它定义了一个简单的可缩放形状必须支持的很多方法, 比如: setHeight 、 setWidth 、getHeight 、 getWidth 以及 setAbsoluteSize 。此外,你还提供了几个额外的实现(out-of-boximplementation),如正方形、长方形。由于你的库非常流行,你的一些用户使用 Resizable 接口创建了他们自己感兴趣的实现,比如椭圆
发布API几个月之后,你突然意识到 Resizable 接口遗漏了一些功能。比如,如果接口提供
一个 setRelativeSize 方法,可以接受参数实现对形状的大小进行调整,那么接口的易用性会更好。你会说这看起来很容易啊:为 Resizable 接口添加 setRelativeSize 方法,再更新 Square和 Rectangle 的实现就好了。
不过,事情并非如此简单!你要考虑已经使用了你接口的用户,他们已经按照自身的需求实现了 Resizable 接口,他们该如何应对这样的变更呢?非常不幸,你无法访问,也无法改动他们实现了 Resizable 接口的类
初始版本的 API
Resizable 接口的最初版本提供了下面这些方法:
public interface Resizable {
int getWidth();
int getHeight();
void setWidth(int width);
void setHeight(int height);
void setAbsoluteSize(int width, int height);
}
用户实现:
public class Ellipse implements Resizable{
@Override
public int getWidth() {
return 0;
}
@Override
public int getHeight() {
return 0;
}
@Override
public void setWidth(int width) {
}
@Override
public void setHeight(int height) {
}
@Override
public void setAbsoluteSize(int width, int height) {
}
}
他实现了一个处理各种 Resizable 形状(包括 Ellipse )的游戏
public class Game {
public static void main(String[] args) {
// 可以调整大小//的形状列表
List<Resizable> resizableShapes =
Arrays.asList(new Ellipse());
Utils.paint(resizableShapes);
}
}
public class Utils {
public static void pa