9.高效java8编程-默认方法

文章是个人阅读《Java8实战》过程中的重点摘抄,可能晦涩,没有示例代码,后续会补充总结完善。


本章内容

  • 什么是默认方法
  • 如何以一种兼容的方式改进API
  • 默认方法的使用模式
  • 解析规则

核心问题

1.引入默认方方法的原因是什么?
2.默认方法的编码中的使用场景是什么?
3.存在默认方法的情况下,如何解决多继承带来的冲突?

概述

传统上,接口的实现类必须必须为接口的中每个方法提供一个实现,或者从父类中继承他的实现。但是,一旦类库的设计者需要更新接口,或者为接口增加新方法,这种方式就会出现问题。由于java8在现存的接口中引入了非常多的新方法,这种变化带来的问题也愈加严重。

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

  • 其一,java8允许在接口内声明静态方法。??
  • 其二,java8引入了默认方法,通过默认方法可以指定接口的默认实现。这样接口可以提供方法的具体实现,如果实现接口的类不显式提供该方法的实现,就会继承默认实现。这种机制可以使你平滑的进行接口的优化和演进。

简而言之,向接口添加方法是诸多问题的罪恶之源;一旦接口发生变化,实现这些接口的类往往也需要更新,提供新添方法的实现才能适配接口的变化。如果你对接口以及它所有相关的实现有完全的控制,这可能不是个大问题。但是这种情况是极少的。这就是引入默认方法的目的:它让类可以自动地继承接口的一个默认实现。

因此,如果你是个类库的设计者,这一章的内容对你而言会十分重要,因为默认方法为接口的演进提供了一种平滑的方式,你的改动将不会导致已有代码的修改。此外,默认方法为方法的多继承提供了一种更灵活的机制,可以帮助你更好地规划你的代码结构:类可以从多个接口继承默认方法。因此,即使你并非类库的设计者,也能在其中发现感兴趣的东西。


9.1 不断演进的 API

》》》


9.2 概述默认方法

默认方法是Java 8中引入的一个新特性,希望能借此以兼容的方式改进API。默认方法由default修饰符修饰,并像类中声明的其他方法一样包含方法体。例如:

public interface Sized {
	int size();
	default boolean isEmpty() {
		return size() == 0;
	}
}

java8中抽象类和抽象接口

那么,抽象类和带有默认方法的接口有什么区别呢?他们都包含抽象方法和包含方法体的实现。

  • 一个类只能继承一个抽象类,但是能实现多个接口。
  • 一个抽象类可以通过实例变量保存一个通用状态,而接口不能拥有实例变量。

9.3 默认方法的使用模式

我们已经了解了默认方法怎样以兼容的方式演进库函数。本节我们介绍使用默认方法的两个示例:可选方法和行为的多继承。

9.3.1 可选方法

我们很可能碰到这种情况,类实现了接口,却刻意的将某个方法的实现留白。例如,现Interator接口的类通常会为remove方法放置一个空的实现,这些都是些毫无用处的模板代码。采用了默认方法之后,我们可以为这类方法提供一个默认的实现,这样实现类就不需要在自己的实现中留白这个方法了。通过这种方式,可以减少无用的模板方法。

9.3.2 行为的多继承

默认方式之前无法做到的事情,现在通过默认放的优雅的实现了,即行为的多继承。这是一种让类从多个源重用代码的能力。java中一个类只能从一个类继承,但是能实现多个接口,实现多个接口的方式是java多继承的唯一方式。由于java8接口默认方法的存在,类可以从多个接口中继承他们的行为。

保持接口的精致性和正交性能帮助你在现有的代码基上最大程度地实现代码复用和行为组合。


9.4 解决冲突的规则

Java的语法中一个类只能继承一个父类,但是一个类可以实现多个接口。随着默认方法在Java 8中引入,有可能出现一个类继承了多个方法而它们使用的却是同样的函数签名。这种情况下,类会选择使用哪一个函数?在实际情况中,像这样的冲突可能极少发生,但是一旦发生这样的状况,必须要有一套规则来确定按照什么样的约定处理这些冲突。

9.4.1 解决问题的三个原则

如果一个类使用相同的函数签名从多个地方(比如另一个类或接口)继承了方法,通过三条规则可以进行判断。

  • 类中的方法优先级更高。类或者父类中声明的方法高于任何声明为默认方法的优先级。
  • 如果无法依据第一条进行判断,那么子接口的优先级更高。函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。
  • 如果前两条都无法判断,继承了多个接口的类必须显式覆盖和调用期望的方法。

9.4.2 选择提供了最具体实现的默认方法的接口

通过两个示例说明,这个最具体的含义。

9.4.3 冲突及如何显式的消除歧义

当第一条和第二条规则都不能使用的时候,从编译器的角度来看,没有那个接口的实现更具体,编译器就会抛出一个异常。

解决这种类型的冲突的方式只能是显式的说明调用哪一个方法:即在实现类中覆盖该方法,并在方法中显式的说明你希望调用哪一个方法。为此,java8引入了一种新的语法:X.spuer.m(…),其中X是表示m方法所在的父接口。

9.4.4 菱形继承问题

》》》


9.5 小节

  • java8中的接口可以通过默认方法或静态方法提供方法的代码实现。
  • 默认方法的开头以关键字defualt修饰,方法体与常规方法一样。
  • 向发布的接口添加抽象方法不是源码Щ容的。
  • 默认方法的出现能帮助类库的设计者以向后兼容的方式演进API。
  • 默认方法可以用于创建可选方法和行为的多继承。
  • 解决由于一个类从多个接口中继承了઴有相同函数签名的方法而导致的冲突:类或者父类中声明的方法的优先级高于任何默认方法。如果前一条无法解决冲突,那就选择同函数签名的方法中实现得最具体的那个接口的方法。两个默认方法都同样具体时,你需要在类中覆盖该方法,显式地选择使用哪个接口中提供的默认方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值