技术开发 频道

Java 8新特性:关于默认方法的详细介绍

        【IT168 技术】之前我们关于Java 8的lambda 的文章看上去很受欢迎。这次我们继续介绍Java 8的新特性,这回要介绍的是默认方法。与lambdas类似,这些都是Java 8引入的主要特性。在这篇文章里,我们要介绍默认方法是什么,有什么作用,已经在日常开发中如何去运用默认方法。

  为何要引入默认方法?

  Java 8正在临近,即使是发布期被推迟了,我们仍能肯定lambda特性会被引入。因此,我们之前其实已多少经涉及到一些这些主题,不过,lambda并非Java 8唯一的改变。

  假设Java 8 已经发布并且包含了lambda。现在你打算用一下lambda,最明显的应用场景莫过于对collection的每一个元素应用lambda。

List<?> list =
list.forEach(…);
// 这就是lambda代码

  在java.util.List或者java.util.Collection接口里都找不到forEach的定义。通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。

  因此,如果在Java 8里使用lambda的时候,因为向前兼容的原因而不能用于collection库,那有多糟糕啊。

  由于上述原因,引入了一个新的概念。虚拟扩展方法,也即通常说的defender方法, 现在可以将其加入到接口,这样可以提供声明的行为的默认实现。

  简单的说,Java的接口现在可以实现方法了。默认方法带来的好处是可以为接口添加新的默认方法,而不会破坏接口的实现。在我看来,这并非那种每天都会用到的Java特性,但是它绝对能让Java的Collections API可以很自然的使用lambda。

  最简单的例子

  让我们看一个最简单的例子:一个接口A,Clazz类实现了接口A。

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

public class Clazz implements A {
}

  代码是可以编译的,即使Clazz类并没有实现foo()方法。在接口A中提供了foo()方法的默认实现。

  使用这个例子的客户端代码:

Clazz clazz = new Clazz();
clazz.foo();
// 调用A.foo()

  多重继承?

  有一个常见的问题:人们会问 当他们第一次听到关于默认方法的新的特性时 “如果一个类实现了两个接口,并且两个接口都用相同的签名定义了默认方法,这该怎么办?”让我们用先前的例子来展示这个解决方案:

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

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

public class Clazz implements A, B {
}

  这段代码不能编译 有以下原因:

  java:class Clazz 从types A到B给foo()继承了不相关的默认值

  为了修复这个,在Clazz里我们不得不手动解决通过重写冲突的方法:

public class Clazz implements A, B {
    
public void foo(){}
}
0
相关文章