您的位置:首页 > 编程语言 > Java开发

java8接口默认方法和静态方法

2017-11-26 21:20 375 查看
java8中对接口进行了扩展,允许我们在接口中定义具体方法,一种是默认方法,即在方法返回值前加“default”关键字,另一种是加“static”的静态方法。

扩展带来的好处

1.java拥有了类似多继承的功能,虽然在对象关系中,继承关系和实现关系还是有有所区别,但是在作用上与C++的多继承类似;

2.接口可以帮我们实现一些比较固定的方法,不必每次实现一个接口就得实现所有方法;

3.向前兼容,如果要在接口中添加一个新的方法,在没有默认方法前,修改了接口,那实现接口的类都得多实现一个可能对他们来说没用的类,可扩展性不好,就好比java8添加的lambda表达式,默认方法就起到过渡作用。

@FunctionalInterface
public interface Iterable<T> {
Iterator<T> iterator();

default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
}


Iterable接口在java8之后添加了一个默认方法forEach,forEach 使用了一个java.util.function.Consumer功能接口(函数式接口)类型的参数,它使得我们可以传入一个lambda表达式或者一个方法引用,如下:

List<?> list = …

list.forEach(System.out::println);

冲突

现在来看看使用默认方法会遇到的一些冲突

1.一个类实现了接口A和B,A和B中都有一个方法签名一样的方法foo,这种情况下编译不通过,因为编译器无法判断我们想要使用的是哪个foo(),这时候实现类就必须对foo方法进行重写,在方法里决定要调用的是A的还是B的foo(),或者都不调用,下面的例子我使用A.super.foo();调用A的foo()。

public class Jdk8DefaultMethod implements A, C {
// 若此处重写foo(),那么调用的就是此类中的foo()了
}
interface A {
default void foo() {
System.out.println("default method of A");
}
}
interface C extends A {
// 重写方法优先
@Override
default void foo() {
System.out.println("default method of C");
}
}


2.修改一下上面的代码,一个类实现了接口A和C,而接口C继承了接口A并重写了A接口的foo方法,这种情况下实现类在不重写foo()的情况下会调用C接口中的foo(),重写过的方法被JVM认为更具体,更重要,所以这种情况下是重写方法优先。如果实现类也重写了foo()一样,那么调用的就是实现类中的foo()了。
public class Jdk8DefaultMethod implements A, C {
// 若此处重写foo(),那么调用的就是此类中的foo()了
}
interface A {
default void foo() {
System.out.println("default method of A");
}
}
interface C extends A {
// 重写方法优先
@Override
default void foo() {
System.out.println("default method of C");
}
}
3.继续修改,如果一个类实现了接口A和D,接口A中的foo()是默认方法,而接口D中的foo()是抽象方法,这种情况下,实现类必须重写接口D中的foo(),调用的也是接口D的foo()。
public class Jdk8DefaultMethod implements A, D {
// 重写接口D中的foo()
@Override
public void foo() {
System.out.println("Override foo of interface D");
}
}
interface A {
default void foo() {
System.out.println("default method of A");
}
}
interface D {
// 对接口定义的抽象方法的实现方法优先调用
void foo();
}

默认方法的简单使用

继续修改上面的类,利用接口的默认方法创造一个模板方法,其中getSession()和close()方法是接口帮我们实现好的,我们只需要重写逻辑不固定的service()。
/**
* writer: holien
* Time: 2017-11-26 14:46
* Intent: 默认方法以及多继承冲突
*/
public class Jdk8DefaultMethod implements MyTemplate {
@Override
public void service() {
System.out.println("用户自己实现的业务逻辑");
}

public static void main(String[] args) {
Jdk8DefaultMethod object = new Jdk8DefaultMethod();
object.doTemplate();
}
}
interface MyTemplate {
void service();  // 根据不同需求重写此方法
default void doTemplate() {
getSession();
service();
close();
}
// 逻辑不变的两个方法,使用默认方法封装实现
default void getSession() {
System.out.println("自动获取会话");
}
default void close() {
System.out.println("关闭连接");
}
}
以上是对默认方法的理解和使用,对于接口中的静态方法,暂时还不了解有什么具体用法和实践,以后会补上。
java8之后的接口和抽象类的区别

接口的变量默认是public static final 型,且必须给其初始值,抽象类的变量默认是default的,可重新赋值;

在语法上,一个类的抽象类只能有一个,但是可以拥有多个接口。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: