Java8接口变化-静态方法&默认方法

来源:互联网 发布:港澳游怎么样知乎 编辑:程序博客网 时间:2024/06/08 04:00

Java8 接口改变-静态方法&&默认方法

java8接口改变包括接口中的静态方法和默认方法。早于jdk1.8的java版本,在接口中我们只能声明方法。 但是,在java第8个版本,在接口中,我们可以有默认方法静态方法


java8接口


设计接口一直是一个艰难的工作,因为如果我们想要改变接口中的一个方法,这将改变所有实现了该方法的类。随着接口存在的时间越来越长,实现了这个接口的类越来越多,以至于无法再拓展这个接口。这是为什么当我们设计一个应用,大多数的框架都提供一个基本实现类,然后我们拓展这个类,覆盖基类的方法以适用于我们的应用。


让我们一起看一下默认几接口方法和静态接口方法,和他们引进java8的原因。


java接口默认方法

为了在java中创造一个默认方法,我们需要使用“default”关键字作为方法特性。例如:

public interface Interface1 {void method1(String str);default void log(String str){System.out.println("I1 logging::"+str);}}

注意在接口Interface1中log(String str)是一个默认方法。现在,当一个类实现接口Interface1,它将不被强制为默认方法log(String str)提供一个实现体。这个特性(使用默认方法)将帮助我们拓展接口。所有我们需要做的就是提供一个默认实现。


让我们看一下另一个具有下列方法的接口。

public interface Interface2 {void method2();default void log(String str){System.out.println("I2 logging::"+str);}}

我们知道java不允许我们继续多个类,因为它将导致“钻石问题”。钻石问题将导致编译器不能确定使用哪个超类的方法。使用默认方法,钻石问题也会出现在接口中。因为一个类正在实现接口1Interface1和接口2Interface2 ,而且没有实现共同的默认方法。编译器不能决定选择使用哪一个。


继承多个接口是java中的一个完整部分。你将在java核心类和大多数的企业应用和框架中发现它。因而为了保证这个问题不会出现在接口中,它将强制性地为公共默认方法提供实现。因而,一个正在实现上述两个接口的类,它不得不为log()方法提供实现,否则编译器将抛出编译时错误。


一个简单的正在实现接口1Interface1和接口2Interface2的类将是:

public class MyClass implements Interface1, Interface2 {@Overridepublic void method2() {}@Overridepublic void method1(String str) {}@Overridepublic void log(String str){System.out.println("MyClass logging::"+str);Interface1.print("abc");}}

关于java接口默认方法的重要点:

1、java接口默认方法将帮助我们拓展接口,而不用担心破坏实现了的类。

2、帮助我们区分(原文用的bridge down)接口和抽象类。

3、帮助我们避免效用类。例如:所有的集合类方法能够被接口本身提供。

4、帮助我们移除基础实现接口的类,我们能够提供默认实现方法,而且实现类选择覆盖哪个方法。

5、在接口中引入默认方法的一个重要原因是为增强Java8中的应用程序接口API集合,进而支持lambda表达式。

6、在等级制度中,若任何类有一个相同特性的方法,默认方法就不相关了。一个默认方法不能够覆盖java.lang.Object.的方法。那个推理是很简单的,因为Object是所有类的基类。因而即使我们在接口有被定义为默认方法的Object的方法,它也将没有用,因为Object的方法总是被使用。那也是为什么为了避免混乱,我们不能有覆盖Object类成员方法的默认方法。

7、java接口默认方法也简称为Defender Methods或者Vtrtual extension method 虚拟拓展方法。


Java接口静态方法

java接口静态方法类似于默认方法,除了我们不能在实现(该接口的)类中覆盖他们。这个特性帮助我们避免在实现接口类是得到不期望的结果。让我们看一个简单的例子:

public interface MyData {default void print(String str) {if (!isNull(str))System.out.println("MyData Print::" + str);}static boolean isNull(String str) {System.out.println("Interface Null Check");return str == null ? true : "".equals(str) ? true : false;}}

现在让我们看一个执行不力的有isNULL()方法的实现类。

public class MyDataImpl implements MyData {public boolean isNull(String str) {System.out.println("Impl Null Check");return str == null ? true : false;}public static void main(String args[]){MyDataImpl obj = new MyDataImpl();obj.print("");obj.isNull("abc");}}
注意isNull(String str)是一个简单的类方法,它没有正在覆盖接口中的isNULL方法。例如,如果你向isNULL方法上添加@Override annotation,它将导致一个编译错误。


现在我们运行这个应用,我们将得到下面的输出。

Interface Null CheckImpl Null Check

如果我们将接口方法isNULL()的属性从静态改为默认,我们将得到下面的输出

Impl Null CheckMyData Print::Impl Null Check
接口静态方法仅仅对于接口本身可见,如果我们从类MyDataImp1中移除isNULL()方法,我们将不能在MydataImp1中使用它。然而,像其他静态方法一样,我么么可以通过接口名引用接口静态方法。例如,一个有效的写法是:

boolean result = MyData.isNull("abc");


关于接口静态方法的要点:

1、java接口静态方法是接口的一部分,我们不能使用它实现类对对象。

2、有利于提供实用方法,例如,空检查,集合排序等。

3、通过不允许实现类覆盖接口静态方法,可以在安全方面帮助我们。

4、我们不能定义为Object类定义接口静态方法,否则我们将得到编译错误“这个静态方法不能隐藏Object类的实例方法”。这是因为它在java中不被允许,因为Object类是所有类的基类,我们不能有一个类层次的静态方法,而且另一个具有相同特点的实例方法。

5、我们使用java接口静态方法溢出实用类,像集合Collections,移除所有它的静态方法到相应的接口中,这将是简单的查找和使用。

Java函数(功能)接口

在我得出结论帖子(post)之前,我想要提供一个简短的功能接口说明。一个只有一个抽象方法的接口作为函数接口。

一个新的注释@FunctionalInterface 已经被介绍用来创建一个功能接口。@FunctionalInterface注释是一个避免偶然向功能接口中添加抽象方法的注释。 它是可选的,但是使用它真的很方便。


功能接口是期待已久的,且很受人追捧的Java8特性,因为它使我们可以使用lambda表达式去实例他们。一个具有功能接口分支的新包java.util.function被加入了API,为提供方法引用和lambda表达式的目标类型。


wjsay第一次翻译外文,2017-8-25 10:48:19


原创粉丝点击