- 默认方法
默认方法允许您添加新的功能到现有库的接口中,并能确保与采用旧版本接口编写的代码的二进制兼容性。
JAVA8新增了接口的默认方法,简单的说就是在接口中可以有实现方法,而不仅仅是方法的声明,默认方法的实现也比较简单,只要在方法名字前面加个default关键字就可以了。 - 增加该特性的原因
在1.8之前接口的好处是让JAVA面向抽象而不是具体编程,缺陷就是如果接口里面的方法声明发生了变化,就需要修改所有实现当前接口的类。耦合性比较高。因此1.8引入默认方法的原因是为了解决接口的修改与现有的实现不兼容问题。换句话说,就是解决了,接口新增方法,但是不会影响已有的借口实现。提升了接口的兼容性。 - 示例代码
首先我们看下1.8之前的代码
public interface InterfaceA {
void print();
}
public class ClassA implements InterfaceA {
@Override
public void print() {
System.out.println(">>>>>>>> InterfaceA print");
}
}
public class MainTest {
public static void main(String[] args) {
ClassA classA = new ClassA();
classA.print();
}
}
在没有1.8之前,如果我们对于InterfaceA增加了新的方法fun();那么对于实现该接口的ClassA类也需要做修改。需要修改成为如下内容:
public interface InterfaceA {
void print();
void say();
}
public class ClassA implements InterfaceA {
@Override
public void print() {
System.out.println(">>>>>>>> InterfaceA print");
}
@Override
public void say() {
}
}
public class MainTest {
public static void main(String[] args) {
ClassA classA = new ClassA();
classA.print();
classA.say();
}
}
而引入默认方法后我们则不需要修改ClassA类,只需要修改调用的方法,如下:
public interface InterfaceA {
void print();
default void say(){
System.out.println(">>>>>>>InterfaceA say");
}
}
public class ClassA implements InterfaceA {
@Override
public void print() {
System.out.println(">>>>>>>> InterfaceA print");
}
}
public class MainTest {
public static void main(String[] args) {
ClassA classA = new ClassA();
classA.print();
classA.say();
}
}
接口默认方法的继承分三种情况:
不覆写默认方法,直接从父接口中获取方法的默认实现。
覆写默认方法,这跟类与类之间的覆写规则相类似。
覆写默认方法并将它重新声明为抽象方法,这样新接口的子类必须再次覆写并实现这个抽象方法。
JAVA8的另一个特性是提供了一个静态默认方法;示例代码如下:
public interface InterfaceA {
void print();
default void say(){
System.out.println(">>>>>>>InterfaceA say");
}
static void show(){
System.out.println(">>>>>>>> InterfaceA show");
}
}
public class ClassA implements InterfaceA {
@Override
public void print() {
System.out.println(">>>>>>>> ClassA print");
}
@Override
public void say() {
System.out.println("ClassA say");
}
}
public class MainTest {
public static void main(String[] args) {
InterfaceA.show();
}
}
因为这个是给接口的默认方法就存在接口的多继承,那么如果两个接口中有两个方法名相同的发方法我们怎么处理呢?示例代码如下:
public interface InterfaceB {
default void say(){
System.out.println(">>>>>>>InterfaceBBBBB say");
}
default void write(){
System.out.println(">>>>>>>InterfaceBBBBB write");
}
}
public interface InterfaceC {
default void write(){
System.out.println(">>>>>>>InterfaceC write");
}
}
public interface InterfaceD {
default void say(){
System.out.println(">>>>>>>InterfaceDDDDDD say");
}
}
public class ClassB implements InterfaceC,InterfaceD {
public void remember(){
say();
write();
}
@Override
public void say() {
System.out.println("<<<<<<<<<<<<<ClassBBBBBB say");
}
@Override
public void write() {
System.out.println("<<<<<<<<<<<<<ClassBBBBBB write");
}
}
public class ClassC implements InterfaceD,InterfaceB {
@Override
public void say() {
InterfaceD.super.say();
InterfaceB.super.say();
System.out.println("<<<<<<<<<<<<<< ClassCCCCCCCCCCCCC say");
}
}
测试主函数:
public class MainTest {
public static void main(String[] args) {
ClassB classB = new ClassB();
classB.write();
classB.say();
classB.remember();
ClassC classC = new ClassC();
classC.say();
classC.write();
}
}
输出结果:
<<<<<<<<<<<<<ClassBBBBBB write
<<<<<<<<<<<<<ClassBBBBBB say
<<<<<<<<<<<<<ClassBBBBBB say
<<<<<<<<<<<<<ClassBBBBBB write
>>>>>>>InterfaceDDDDDD say
>>>>>>>InterfaceBBBBB say
<<<<<<<<<<<<<< ClassCCCCCCCCCCCCC say
>>>>>>>InterfaceBBBBB write
从上面的代码可以看出
ClassB在实现C、D接口时,因为两个接口中不存在相同的方法,所以可以多重实现。
ClassC在实现B、D接口时,因为两个接口中都存在相同的方法say()
,因此存在歧义,这个时候我们就需要通过InterfaceB.super.say();
类似的方法来解决冲突。这种方法的一般格式是InterfaceName.super.MethodName()
.
在以上方法中还有一个特殊的情况:实例代码如下:
public interface InterfaceD {
default void say(){
System.out.println(">>>>>>>InterfaceDDDDDD say");
}
}
public interface InterfaceE extends InterfaceD {
@Override
default void say() {
System.out.println(">>>>>>>InterfaceE say");
}
}
public class ClassE implements InterfaceE,InterfaceD {
@Override
public void say() {
//InterfaceD.super.say(); 错误的
InterfaceE.super.say();
}
}
这里面通过InterfaceD.super.say()
是报错的。这个时候是无法通过以上方法来调用InterfaceD
中的say()
方法的。因为此时存在一个等价关系,InterfaceE
继承InterfaceD
,那么ClassE
在实现InterfaceE
和InterfaceD
其实就等价于ClassE
只实现InterfaceE
。因此InterfaceD.super.say()
会报错。那么如何解决,就需要重新定义一个接口去继承InterfaceD
,并且定义一个方法去调用InterfaceD
中的say()
方法即可。