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

来源:互联网 发布:网络诈骗被骗几万 编辑:程序博客网 时间:2024/06/10 12:17

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的,可重新赋值;

在语法上,一个类的抽象类只能有一个,但是可以拥有多个接口。

原创粉丝点击