Java8中的默认方法(面试者必看)

背景

在Java8之前,定义在接口中的所有方法都需要在接口实现类中提供一个实现,如果接口的提供者需要升级接口,添加新的方法,那么所有的实现类都需要把这个新增的方法实现一遍,如果说所有的实现类能够自己控制的话,那么还能接受,但是现实情况是实现类可能不受自己控制。比如说Java中的集合框架中的List接口添加一个方法,那么Apache Commons这种框架就会很难受,必须修改所有实现了List的实现类

现在的接口有哪些不便

向已经发布的接口中添加新的方法是问题的根源,一旦接口发生变化,接口的实现者都需要更新代码,实现新增的接口
接口中有些方法是可选的,不是所有的实现者都需要实现,这个时候实现类不得不实现一个空的方法,或者是提供一个Adapter对接口中所有的方法做空实现,在Spring中我们可看到很多这种例子,比如WebMvcConfigurerAdapter

@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {

 @Override
 public void configurePathMatch(PathMatchConfigurer configurer) {
 }

 @Override
 public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
 }

 @Override
 public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
 }

 省略其他代码...
}

在Java8以后这些类都被标注成了过期@Deprecated

默认方法的简介

为了解决上述问题,在Java8中允许指定接口做默认实现,未指定的接口由实现类去实现。如何标识出接口是默认实现呢?方法前面加上default关键字。比如Spring中的WebMvcConfigurer

public interface WebMvcConfigurer {

 default void configurePathMatch(PathMatchConfigurer configurer) {
 }

 default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
 }

 default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
 }

 省略其他代码...
}

从现在看来,可能大家都会有个疑问,默认方法和抽象类有什么区别呢?

  • 默认方法不能有实例变量,抽象类可以有
  • 一个类只能继承一个抽象类,当时可以实现多个接口

默认方法的使用场景

可选方法

为接口提供可选的方法,给出默认实现,这样实现类就不用显示的去提供一个空的方法;这种场景刚才我们在上面已经说到了,spring中有大量的例子

实现多继承

继承是面向对象的特性之一,在Java中一直以来都是单继承的原则,Java8中默认方法为实现多继承提供了可能(由于接口中不能有实例对象,所以能够抽象的到接口中的行为一般都是比较小的模块);从个人的经历来看,做游戏是训练自己面向对象思维的最好方式(以后有机会分享一下小游戏的制作),因为现在大部分学Java的同学学完Java基础后就直接进入JavaWeb的学习,整合各种框架,只能在通用的三层架构(Controller、Service、Dao)中写自己的逻辑。

相信很多人在都做个坦克大战的游戏,如果用Java8中的默认方法如何设计好多继承呢?

这里我们举个简单的例子,定义了三个接口:

  1. Moveable:允许移动的物体,把移动的逻辑放入到这个接口中的默认方法
  2. Attackable: 允许攻击的物体,把攻击的通用逻辑放入到默认方法,不通用的逻辑通过模板方法给实现类处理
  3. Location: 获取物体的坐标

通过这些接口的组合方式,我们就可以为游戏创建不同的实现类,比如说坦克、草地、墙壁...

解决默认方法冲突规则(面试者必看)

通过上面的例子,我们体验的默认方法给我们带来了多继承的便利,但是让我们思考下,如果出现了不同的类出现的相同签名的默认方法,实际在运行的时候应该如何选择呢?客官不慌,有办法的

  • 类中的方法优先级最高。如果类或者父类(抽象类也OK)中声明了相同签名的方法,那么优先级最高
  • 如果第一条无法确定,那么最具体的的实现的默认方法;很绕,举例子:B接口继承了A,B就更加具体,那么B中的方法优先级最高
  • 如果上面两个都无法判断,那么编译会报错,需要在实现接口,然后手动显式调用
public class C implements A, B {
 void pint() {
  B.supper.print(); // 显式调用
 }
}

菱形继承问题

为了说明上面的三个原则,我们直接来看看最复杂的菱形继承问题

public interface A {
 default void print(){
  System.out.println("Class A");
 }
}

public interface B extend A {}

public interface C extend A {}

public class D implement B, C {
 public static void main(String[] args) {
  new D().print()
 }
}

这种情况下B,C都没有自己的实现,实际上就只有A有实现,那么会打印Class A

如果说这个时候把接口B接口改一下

public interface B extends A {
 default void print(){
  System.out.println("Class B");
 }
}

根据原则(2),B继承于A,更加具体,所以打印结果应该是B
如果说把接口C修改一下

public interface C extends A {
 default void print(){
  System.out.println("Class C");
 }
}

这时候我们发现编译报错,需要我们自己手动指定,修改D中的代码

public class D implements B, C {

 @Override
 public void print() {
  C.super.print();
 }

 public static void main(String[] args) {
  new D().print();
 }
}

总结

  • Java8中的默认方法需要使用default来修饰
  • 默认方法的使用场景可选方法和多继承
  • 三个原则解决相同签名的默认方法冲突问题

到此这篇关于Java8中的默认方法(面试者必看)的文章就介绍到这了,更多相关Java8 默认方法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 谨慎使用Java8的默认方法

    默认方法给JVM的指令集增加了一个非常不错的新特性.使用了默认方法之后,如果库中的接口增加了新的方法,实现了这个接口的用户类能够自动获得这个方法的默认实现.一旦用户想更新他的实现类的话,只需覆盖一下这个默认方法就可以了,取而代之的是一个在特定场景下更有意义的实现.更棒的是,用户可以在重写的方法里面调用接口的默认实现来增加一些额外的功能. 目前为止一切都还不错.然而,给现有的Java接口增加默认方法可能会导致代码的不兼容.看个例子就很容易能明白了.假设有一个库,它需要用户实现它的一个接口作为输入:

  • 30分钟入门Java8之默认方法和静态接口方法学习

    前言 上一篇文章30分钟入门Java8之lambda表达式,我们学习了lambda表达式.现在继续Java8新语言特性的学习,今天,我们要学习的是默认方法和静态接口方法. 这一Java8的新语言特性,在Android N中也得到了支持.至于如何在Android开发中配置Java8的开发环境,请查看上一篇文章30分钟入门Java8之lambda表达式. 默认方法 默认方法让我们能给我们的软件库的接口增加新的方法,并且能保证对使用这个接口的老版本代码的兼容性. 下面通过一个简单的例子来深入理解下默认

  • java8新特性之接口默认方法示例详解

    前言 JAVA8 已经发布很久,而且毫无疑问,java8 是自 java5(2004年发布)之后的最重要的版本.其中包括语言.编译器.库.工具和 JVM 等诸多方面的新特性.Java8 新特性列表如下: 接口默认方法 函数式接口 Lambda 表达式 方法引用 Stream Optional 类 Date API Base64 重复注解与类型注解 接口默认方法 1.什么是接口默认方法 从 Java8 开始,程序允许在接口中包含带有具体实现的方法,使用 default 修饰,这类方法就是默认方法.

  • 一篇文章带你认识Java8接口的默认方法

    前言 Java8是Oracle于2014年3月发布的一个重要版本,其API在现存的接口上引入了非常多的新方法. 例如,Java8的List接口新增了sort方法.在Java8之前,则每个实现了List接口的类必须定义sort方法的实现,或者从父类中继承它的实现.想象一下,如果List接口的继承体系非常庞杂,那么整个集合框架的维护量有多么大! 为此,在Java8中引入了一种新的机制:接口支持申明带实现的方法. 默认方法 前文提到了Java8中List接口新增了sort方法,其源码如下: publi

  • Java8接口的默认方法

    Java8接口的默认方法 什么是默认方法,为什么要有默认方法? 简单说,就是接口可以有实现方法,而且不需要实现类去实现其方法.只需在方法名前面加个default关键字即可. 为什么要有这个特性?首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8之前的集合框架没有foreach方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现.然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有

  • Java8默认方法Default Methods原理及实例详解

    这篇文章主要介绍了Java8默认方法Default Methods原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Java 8 引入了新的语言特性--默认方法(Default Methods). Default methods enable new functionality to be added to the interfaces of libraries and ensure binary compatibility wit

  • Java8新特性之接口中的默认方法和静态方法

    写在前面 在Java8之前的版本中,接口中只能声明常量和抽象方法,接口的实现类中必须实现接口中所有的抽象方法.而在Java8中,接口中可以声明默认方法和静态方法,本文,我们就一起探讨下接口中的默认方法和静态方法. 接口中的默认方法 Java 8中允许接口中包含具有具体实现的方法,该方法称为"默认方法",默认方法使用 default 关键字修饰 . 例如,我们可以定义一个接口MyFunction,其中,包含有一个默认方法getName,如下所示. public interface MyF

  • Java8新特性之默认方法(default)浅析

    一.什么是默认方法,为什么要有默认方法 简单说,就是接口可以有实现方法,而且不需要实现类去实现其方法.只需在方法名前面加个default关键字即可. 为什么要有这个特性?首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的java 8之前的集合框架没有foreach方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现.然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现.所以引进的默认方法

  • Java8中新特性Optional、接口中默认方法和静态方法详解

    前言 毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库.工具和JVM等方面的十多个新特性. Java 8是Java的一个重大版本,有人认为,虽然这些新特性领Java开发人员十分期待,但同时也需要花不少精力去学习.下面本文就给大家详细介绍了Java8中新特性Optional.接口中默认方法和静态方法的相关内容,话不多说了,来一起看看详细的介绍吧. Optional Optional 类(java.util.Optional) 是一个

  • Java8中的默认方法(面试者必看)

    背景 在Java8之前,定义在接口中的所有方法都需要在接口实现类中提供一个实现,如果接口的提供者需要升级接口,添加新的方法,那么所有的实现类都需要把这个新增的方法实现一遍,如果说所有的实现类能够自己控制的话,那么还能接受,但是现实情况是实现类可能不受自己控制.比如说Java中的集合框架中的List接口添加一个方法,那么Apache Commons这种框架就会很难受,必须修改所有实现了List的实现类 现在的接口有哪些不便 向已经发布的接口中添加新的方法是问题的根源,一旦接口发生变化,接口的实现者

  • Java8新特性之接口中的默认方法和静态方法详解

    一.前言 Java 8 引入了默认方法以及可以在接口中定义的静态方法. 默认方法是一个普通的 java 方法,但以 default 关键字开头,静态方法像往常一样用 static 关键字声明. 二.为什么在 Java 接口中使用默认方法? 为什么java在接口中引入了默认方法. 假设一个拖拉机制造公司发布了操作拖拉机的标准接口,如如何挂挡或停车等. 开发者已经开发了不同类型的拖拉机来实现标准的拖拉机接口. 如果公司在其标准接口中增加了新的功能,如如何跳动拖拉机? 开发者需要对他们的类进行修改以定

  • 深入理解Java8新特性之接口中的默认方法和静态方法

    1.接口中的默认方法和静态方法 Java 8中允许接口中包含具有具体实现的方法,该方法称为 "默认方法" ,默认方法使用 default 关键字修饰. 接口默认方法的 " 类优先 " 原则.若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时 选择父类中的方法.如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略. 接口冲突.如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方

  • Java8中如何通过方法引用获取属性名详解

    前言 在我们开发过程中常常有一个需求,就是要知道实体类中Getter方法对应的属性名称(Field Name),例如实体类属性到数据库字段的映射,我们常常是硬编码指定 属性名,这种硬编码有两个缺点. 1.编码效率低:因为要硬编码写属性名,很可能写错,需要非常小心,时间浪费在了不必要的检查上. 2.容易让开发人员踩坑:例如有一天发现实体类中Field Name定义的不够明确,希望换一个Field Name,那么代码所有硬编码的Field Name都要跟着变更,对于未并更的地方,是无法在编译期发现的

  • Java8接口之默认方法与静态方法详解

    目录 前言 为什么选择默认方法? Java 8示例:接口中的默认方法 Java 8示例:接口中的静态方法 Java 8 - 抽象类与接口 总结 前言 在Java8之前,java中的接口只能有抽象方法.默认情况下,接口的所有方法都是公共和抽象的.Java8允许接口具有默认和静态方法.我们在接口中使用默认方法的原因是,允许开发人员向接口添加新方法,而不会影响实现这些接口的类. 为什么选择默认方法? 例如,如果A.B.C和D等几个类实现了一个接口XYZInterface,那么如果我们向XYZInter

  • 在Tomcat中部署Web项目的操作方法(必看篇)

    在这里介绍在Tomcat中部署web项目的三种方式: 1.部署解包的webapp目录 2.打包的war文件 3.Manager Web应用程序 一:部署解包的webapp目录 将Web项目部署到Tomcat中的方法之一,是部署没有封装到WAR文件中的Web项目.要使用这一方法部署未打包的webapp目录,只要把我们的项目(编译好的发布项目,非开发项目)放到Tomcat的webapps目录下就可以了.如下图所示: 这时,打开Tomcat服务器(确保服务器打开),就可以在浏览器访问我们的项目了,如下

  • PHP获取路径和目录的方法总结【必看篇】

    PHP获取目录和的方法通过魔术变量:通过超级全局变量:通过相关函数等等: <?php /** * PHP获取路径或目录实现 */ //魔术变量,获取当前文件的绝对路径 echo "__FILE__: ========> ".__FILE__; echo '<br/>'; //魔术变量,获取当前脚本的目录 echo "__DIR__: ========> ".__DIR__; echo '<br/>'; //dirname返回

  • 利用JS提交表单的几种方法和验证(必看篇)

    工作中发现表单提交方便的问题,很多时候IE下提交好好的,打了火狐下就出现了问题,利用提交按钮就不成功了,于是利用JS的方式就成功了,也不知道为什么.在导师的催促下就总结出以下的几种常用表单提交的方法. 第一种方式:表单提交,在form标签中增加onsubmit事件来判断表单提交是否成功 <script type="text/javascript"> function validate(obj) { if (confirm("提交表单?")) { aler

随机推荐