接口中的默认方法和静态方法

基于尚硅谷java8教程

1. 接口中的方法

从接触java编程的第一天起,老师就告诉我们接口中的变量必须是public static final的,方法也必须是public的,所以下面的定义是等价的

public interface MyService {
    public static final String KEY = "hello world";
    String key = "hello world";
    
    public abstract void sayHello();
    void sayHi();
}

但是从jdk1.8开始,这种现象有了改变,jdk添加了接口的默认方法和静态方法,使用如下方式定义:

public interface MyService {

    /* 静态方法 */
    static void method1(){
        System.out.println("这个是静态方法,调用方式为:MyService.method1()");
    }
    /* 默认方法 */
    default void method2(){
        System.out.println("这个是默认方法,调用方式为MyService实例.method2()");
    }
}

注意:
由于Java支持一个实现类可以实现多个接口,如果多个接口中存在同样的static和default方法会怎么样呢?如果有两个接口中的静态方法一模一样,并且一个实现类同时实现了这两个接口,此时并不会产生错误,因为jdk8只能通过接口类调用接口中的静态方法,所以对编译器来说是可以区分的。但是如果两个接口中定义了一模一样的默认方法,并且一个实现类同时实现了这两个接口,那么必须在实现类中重写默认方法,否则编译失败。

2. 与时俱进的接口优化(添加默认方法和静态方法的优势)

  • 默认方法
    假如由于业务的需要,需要在接口UserService中添加方法addUser,在jdk1.8之前,不管UserService的实现类有多少,都必须添加实现方法addUser(),这就增加了接口开发人员的负担,而且也增加了api的复杂度。从1.8开始,可以直接在UserService接口中使用default关键字实现默认方法只要在接口中写默认实现就可以在各个子类中使用,当然也可以根据实际情况决定是否在子类中重写。
  • 静态方法
    使用静态方法可以使用户强制使用面向接口编程。在jdk1.8之前,如果不期望用户直接使用接口实现类编程,可以将实现类接口访问范围修改为protected,那么就需要在写一个instance的工厂方法。现在可以直接在接口中使用静态方法,就不需要在写工厂类方法了。

3. 静态方法和默认方法的使用范例

// 接口1
package com.seven.jdk8.service;

public interface MyService {
    public static final String KEY = "hello world";
    String key = "hello world";

    public abstract void sayHello();
    void sayHi();

    /* 静态方法 */
    static void method1(){
        System.out.println("这个是静态方法,调用方式为:MyService.method1()");
    }
    /* 默认方法 */
    default void method2(){
        System.out.println("这个是默认方法,调用方式为MyService实例.method2()");
    }

    /*同名的默认方法*/
    default  void method(){
        System.out.println("这个默认方法在MyService中");
    }
}

// 接口2
package com.seven.jdk8.service;

/**
 * 接口.
 */
public interface MyService1 {
    /*同名的默认方法*/
    default  void method(){
        System.out.println("这个默认方法在MyService1中");
    }
}

//接口实现类

package com.seven.jdk8.service;

/**
 * MyService实现类.
 */
public class MyServiceImpl implements MyService,MyService1 {
    @Override
    public void sayHello() {
        System.out.println("sayHello");
    }

    @Override
    public void sayHi() {
        System.out.println("sayHi");
    }

    @Override
    public void method() {
        MyService.super.method();/*指定使用MyService中的method方法*/
        System.out.println("对于实现不同的接口中存在同名的default方法,实现类必须重写或者指定使用哪个父类的方法");
    }
}

package com.seven.jdk8;

import com.seven.jdk8.service.MyService;
import com.seven.jdk8.service.MyServiceImpl;
import org.junit.Test;

/**
 * 静态方法和默认方法测试.
 */
public class InterfaceTest {
    /*静态方法和默认方法的使用*/
    @Test
    public void test1(){
        /*静态方法必须使用接口调用*/
        MyService.method1();
        /*默认方法必须使用实例调用*/
        new MyServiceImpl().method2();
    }
}