是什么
Java8中新增了接口的默认方法,简单来说就是让接口可以自己有实现方法,不许要实现类去实现。
有什么用
想象一种情况,你定义了一个接口A,假如里面有几个抽象方法。然后什么B,C,D,E…一大堆类去实现了A接口里面的几个抽象方法。那么现在问题来了,如果要在A中新加一个抽象方法,那么所有的实现类都要去实现这个抽象方法,不是很麻烦吗?这个时候默认方法就派上用场了,只需要再A中自己实现这个新添加的方法就好了,所有的实现类也可以用了。最典型的例子,Iterable接口就增加了这么一个默认方法
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
我们就可以这么使用该默认方法迭代打印集合中的元素
List<Integer> integers = new ArrayList<Integer>();
integers.add(1);
integers.add(2);
integers.add(3);
integers.forEach(System.out::println);
怎么用
接口的默认方法
接口的默认方法定义很简单,就是在方法返回值前使用 default 关键字修饰,如下面这个接口
public interface MyFunction<T> {
void fun(T t);
//默认方法
default String getUpperCase(String str){
return str.toUpperCase();
}
//默认方法
default Integer getAge(){
return 23;
}
}
使用也是很简单,创建一个MyFunction的实例,然后像普通实例方法的调用方式调用即可
MyFunction<String> function = System.out::println;
String str = function.getUpperCase("abc");
Integer age = function.getAge();
function.fun("This is demo...");
System.out.println("str : "+str);
System.out.println("age : "+age);
输出结果
This is demo...
str : ABC
age : 23
接口的静态方法
Java8还允许接口中有静态方法,如
public interface MyFunction<T> {
void fun(T t);
static Integer toInteger(String num){
return Integer.parseInt(num);
}
}
接口静态方法调用比较简单,类名.方法 即可调用,如
Integer num = MyFunction.toInteger("3");
System.out.println(num);//3
一些规矩
如果一个接口继承了另外一个接口,而这两个接口有一个相同方法签名的默认方法,那么父接口的默认方法会被覆盖。如下面的例子
Father2接口
public interface Father2 {
default String getName(){
return "Father2";
}
}
Father1接口,继承了Father2接口,他们有一个方法签名一样的默认方法getName
public interface Father1 extends Father2{
default String getName(){
return "Father1";
}
}
Son类,实现Father1接口
public class Son implements Father1{
}
测试类
public class Main{
public static void main(String[] args) {
Son son = new Son();
String name = son.getName();
System.out.println(name);
}
}
最终输出结果为Father1,可见Father2的默认方法被Father1给覆盖了。
还有另外一个关于接口冲突规矩,现在把上面的接口和类改一下,Father2接口不变,Father1接口不再继承Father2,Son类同时实现Father1和Father2,你就会发现编译报错,其实就是相同的默认方法有两个,不知道用哪个,这个时候你就必须实现getName默认方法,如
public class Son implements Father1,Father2{
@Override
public String getName() {
return Father1.super.getName();
}
}
在这个实现中,可以发现可以用Father1.super.getName()去调用Father1接口的默认方法,当然也可以调用Father1接口的默认方法,只需Father2.super.getName(),可以发现子类调用某个父接口的默认方法可以通过 父接口.super.方法这种格式调用。