在Java中,接口里只能写方法的声明,而不能写方法的具体实现,方法的实现要在实现接口的类中编写。但在JDK1.8中,接口可以对方法的声明写具体实现,个人觉得这有点违背接口的设计初衷。
下面我们来具体看一下:
1、JDK8之前的写法:
1)首先定义两个接口:IEat,IWalk
public interfaceIEat {voideat();
}public interfaceIWalk {voidwalk();
}
2)再定义一个Dog类,实现IEat和IWalk接口,此时则必须要实现walk(),eat()方法。
public class Dog implementsIWalk,IEat {
@Overridepublic voidwalk() {
System.out.println("dog walk!");
}
@Overridepublic voideat() {
System.out.println("dog eat!");
}
}
3)定义一个Test类,运行一下,看看结果
public classTest {public static voidmain(String[] args) {
Dog dog= newDog();
dog.walk();
dog.eat();
}
}
此时的运行结果为:
dog walk!
dog eat!
以上是JDK8之前的版本的写法。
2、接下来可以将1)中的IWalk接口定义修改一下:
public interfaceIWalk {default voidwalk(){
System.out.println("IWalk walk");
}
}
在JDK8中,可以在接口的方法声明前加上default关键字,这样就可以给walk()方法添加具体的实现,此种写法称之为默认方法实现。
接下来我们将Dog类中的walk()方法实现删除,只保留eat()方法的实现:
public class Dog implementsIWalk,IEat {
@Overridepublic voideat() {
System.out.println("dog eat!");
}
}
再次运行Test类,运行结果为:
IWalk walk
dog eat!
我们可以看到在调用dog.walk()方法时,打印出的是IWalk接口中的默认方法实现。
3、那么问题来了,如果Dog类继承自一个Animal的父类,Animal类也实现了IWalk方法,并且已经有了方法的实现,那此时会出现什么情况呢?
public class Animal implementsIWalk,IEat {
@Overridepublic voideat() {
System.out.println("Animal eat!");
}
@Overridepublic voidwalk() {
System.out.println("Animal walk!");
}
}
public class Dog extends Animal implementsIWalk,IEat {
@Overridepublic voideat() {
System.out.println("dog eat!");
}
}
此时,再次运行Test类,运行结果为:
Animal walk!
dog eat!
从结果我们可以看出,同时有父类和接口都有同一个方法的实现时,优先调用的是父类的实现,而不是接口中的默认实现。
4、另外,接口的默认方法除了可以声明为default之外,还可以声明为static,此时,调用默认方法时,则需要用类名.方法名来调用,和调用静态方法的方式是一样的。
5、总结
以上则是JDK8中对接口中方法的定义的变化,不知道JAVA的工程师们为什么要做这样一个变化,个人觉得这样违背了接口的设计初衷,把接口变成了抽象类了,甚至可以说是一个普通的父类了。在网上搜索到的一些答案,有的说是因为JDK中的某些接口需要新定义方法,但之前的项目中的某些类如果实现了这个接口,则需要重新在接口中添加方法的实现,如果给接口添加默认方法,则不需要再进行这些类的维护工作,这也可以说算是一个方案吧。但个人感觉这个方案还是不够好,因为它破坏了接口的性质和意义。