接口中的默认方法和静态方法
基于尚硅谷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();
}
}