Java1.8 的特性之---Default 方法

转载 2015年05月23日 14:54:28

为什么Java接口可以实例化方法,纠结了我好久,今天终于找到大神的详解笔记了。在这里记录一下。

原文:http://blog.csdn.net/wwwsssaaaddd/article/details/24213525


为什么要有Default方法

在Java8发布之际,有件事情就显得非常重要,即在不破坏java现有实现架构的情况下能往接口里增加新方法。引入Default方法到Java8,正是为了这个目的:优化接口的同时,避免跟现有实现架构的兼容问题。看下面例子:

List<?> list = ...
list.forEach(...);// Lambda code goes here

上面的foreach方法既没有在java.util.List中声明,也没有在java.util.Collection中声明。(如果要使上面代码生效)容易想到的方案是在现有的接口中新增foreach方法,并在JDK中必要的地方实现foreach。然而,一经发布,要想在某个接口中增加方法,而不修改现该接口现有的实现类,这是不可能做到的。

这样,即使我们把Lambda表达式引入到java8中,但是因为不能牺牲向后兼容,而不可以把Lambda表达式和标准集合类库结合使用的话,会真的让人很泄气。

为了解决上述问题,引入了一个新的概念,即虚拟扩展方法(Virtual extension methods),通常也称之为 defender 方法,它目前可以添加到接口中,为声明的方法提供默认的实现。

简单地说,Java接口现在可以有非抽象方法了。Default 方法带来的好处是,往接口新增一个Default 方法,而不破坏现有的实现架构。

尽管如此,Default 方法不适合过多使用,但是对于Java集合API的优化升级,并达到无缝地结合Lambda表达式来说,Default 方法是至关重要的特性。

Default方法入门

让我们从最简单可行的例子开始:下面代码定义了接口A,以及实现了接口A的Clazz类:

public  interface  A {
    default  void  foo(){
        System.out.println("Calling A.foo()");
    }
} 
public  class  Clazz  implements A {}

即使Clazz中没有实现foo(),代码也能编译通过。foo()的默认实现在A接口中给出。

上例的客户端代码如下:

Clazz  clazz= new  Clazz();
clazz.foo();// Calling A.foo()

当大家第一次听说default方法,通常会问:“如果一个类实现了两个接口,而这两个接口中各自定义了一个同名的default方法,会怎么样?”

让我们用上一个例子来解释上述情况,代码如下所示:

public  interface A {
    default  void  foo(){
        System.out.println("Calling A.foo()");
    }
} 
public  interface B {
    default  void  foo(){
        System.out.println("Calling B.foo()");
    }
} 
publicclassClazzimplements A, B {}

上面代码编译失败,报错如下:

java: class Clazz inherits unrelated defaults for foo() from types A and B

为了修复错误,在Clazz中,我们手工地覆写掉冲突的方法来处理这个问题,如下所示:

public  class  Clazz  implements A, B {
    public  void foo(){}
}

可是,如果我们就想调用接口A中默认实现的方法foo(),而不用自己实现的,该怎么办?那就要像下面这样使用A#foo()才行。

public  class  Clazz  implements A, B {
    public  void foo(){
        A.super.foo();
    }
}

Default方法的实例可以在JDK8中找到。回到之前集合API的forEach 的例子,我们可以在接口java.lang.Iterable中找到forEach 的默认实现:

@FunctionalInterface  public  interface  Iterable{
    Iterator iterator(); 
 
    default  void  forEach(Consumer<?super T> action){
         Objects.requireNonNull(action);
        for(T t: this){
             action.accept(t);
        }
    }
}

上面的forEach方法使用函数接口java.util.function.Consumer作为参数,该参数使我们能传递一个Lambda表达式或者方法引用到forEach中,如下所示:

List<?> list = ...
list.forEach(System.out::println);

方法调用

我们来看看实际上是如何调用default方法的。

从客户端代码角度来看,default方法只不过都是初始化的抽象方法。因此default方法也叫-虚拟扩展方法。如果出现上例中的那个类,该类实现了带default方法的接口,那么调用default方法的客户端代码会在调用端生成invokeinterface 。如下所示

A  clazz= new  Clazz();
clazz.foo();// invokeinterface foo()
 
Clazz  clazz= new  Clazz();
clazz.foo();// invokevirtual foo()

以防出现上述的default方法冲突问题,所以我们重写那个default方法,并代理两个接口之中某一个的default方法的调用,具体代码请见下面。invokespecial意思是指 我们将调用专门的实现逻辑。

public  class  Clazz  implements A, B {
    public  void foo(){
        A.super.foo();// invokespecial foo()
    }
}

下面是javap的输出。

public void foo();
 Code:
  0: aload_0
  1: invokespecial #2    // InterfaceMethodA.foo:()V
  4: return

如上面所示的,invokespecial 指令用来调用接口中定义的方法foo()。这从字节码的角度看也是新东西,因为先前你进行方法调用,仅是通过指向父类的super而不是指向父接口的。

总结

Default方法加入到java中,这是引人关注的事情。Default方法可以认为是Lambda表达式和JDK类库之间的桥梁。引入Default方法的主要目的是为了升级标准JDK接口,另外也是为了我们最终能在Java8中顺畅使用Lambda表达式。

Java 8新特性——default方法(defender方法)介绍

Java 8新特性——default方法(defender方法)介绍 2013/11/27 | 分类: 基础技术 | 1 条评论 | 标签: DEFAULT方法, DEFENDER方...

JAVA 1.8 新特性学习(1) 接口的默认方法

java 1.8中,现在接口也可以定义实现了的方法了。用default定义方法就可以了。具体的例子可以看下面的代码: public class Test { public static voi...

精通Java8新特性Lambdas、Streams、Interface default methods

Java SE 8 是有史以来对 Java 语言和库改变最大的一次,其新特性增加了函数式编程风格的Lambda表达式。虽然一开始 lambda 表达式似乎只是“另一个语言特性”而已,但实际上,它们会改...

利用jdk1.8的新特性实现模板方法模式

jdk1.8的新特性中有一个是接口可以编写默认方法。这样写模板方法模式就很好的被利用到(不仅限模板方法使用)。 1、模板类 package com.zc.jdk8; /** * Created...

JDK1.8新特性之方法引用(Method References)

方法引用的唯一用途是支持Lambda表达式的简写,不用Lambda表达式,就用不着方法引用 方法引用分为4类,常用的是前三种。方法引用也受到访问控制权限的限制,可以通过在引用位置是否...
  • mn960mn
  • mn960mn
  • 2015年10月15日 18:12
  • 1826

Java 1.8 新特性之(Lambda表达式)

针对官网对Lambda的解释做个翻译。

java1.8重要新特性

1.接口中可以有默认方法实现 interface A { public void sayString(String str); default public void SayInt(int i)...
  • Senssic
  • Senssic
  • 2014年04月02日 12:53
  • 4690

Java1.8特性

Java1.8新特性

Stream:java1.8新特性

Stream:java1.8新特性what?(它是什么)stream流,Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过...

Java JDK1.8新特性

一、lambda含义     lambda表示数学符号“λ”,计算机领域中λ代表“λ演算”,表达了计算机中最基本的概念:“调用”和“置换”。在很多动态语言和C#中都有相应的lambda语法,这类...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java1.8 的特性之---Default 方法
举报原因:
原因补充:

(最多只允许输入30个字)