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 {
@Override
public void method2() {
}
@Override
public void method1(String str) {
}
@Override
public 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 Check
Impl Null Check
如果我们将接口方法isNULL()的属性从静态改为默认,我们将得到下面的输出
Impl Null Check
MyData 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
\