JDK8以前,接口只能有抽象方法,抽象方法是没有方法体的,具体的逻辑还得依靠接口实现类,但是这时候有一个场景,假设一个接口有多个实现类:
- 这些实现类对接口中一个抽象方法的逻辑甚至代码都是一致的,这时候是不是得每个实现类都重写一遍该方法,使用一摸一样的逻辑代码(即使具体逻辑代码抽取出来公用了,是不是也避免不了重写操作),这操作是不是很冗余
- 接口类的某些抽象接口,实现类根本就不需要,但是因为接口类有,实现类就必须得实现,哪怕是一个空实现,是不是很无奈
- 更可怕的是,一旦接口新增了一个抽象方法,所有的实现类都会受到影响,关键是这个接口很可能只需要一个实现类去实现它就能够解决本次需求了,接口实现类越多,影响范围就越大,那这样耦合度是不是有点高了,是不是违反了开闭原则了
JDK8能解决,通过定义默认方法:
默认方法的定义和使用
方法修饰成default即是默认方法,如下:
public interface TestService {
/**
* 接口抽象方法
*/
void abstractTest();
/**
* 接口默认方法
*/
default void defaultTest() {
System.out.println("do defaultTest");
}
}
public class TestServiceImpl implements TestService {
@Override
public void abstractTest() {
System.out.println("do test");
}
}
默认方法使用时,还是得靠接口实现类实例化来做调用,如下:
public class Test {
public static void main(String[] args) {
//接口默认方法的操作方式
TestServiceImpl testService = new TestServiceImpl();
testService.defaultTest();
}
}
可以发现,默认方法可以完美解决以上提出的3个问题
- 如果接口方法的实现逻辑是统一的,不需要实现类各自重写,那么就可以使用默认方法来维护
- 使用了默认方法,一些实现类就可以在不需要使用该方法时,避免重写空实现的情况
- 如果接口新增了一个抽象方法,可以先用默认方法,把对实现类的影响降到最低,如果有实现类需要时,可以再重写,间接做到了开闭原则
这时候在以上情景中再进一步,默认方法很好用,但是实现类是可以重写默认方法的,如下:
public class TestServiceImpl implements TestService {
@Override
public void abstractTest() {
System.out.println("do test");
}
@Override
public void defaultTest() {
System.out.println("rewrite do defaultTest");
}
}
但是有时候我们封装抽象出一些公共类,甚至是开发简单中间件时,对外提供使用的接口类,有些固定的方法逻辑,我们不希望被使用修改,那么这时候使用默认方法就不安全了
那么通过定义静态方法能够解决该问题。
静态方法的定义和使用
方法修饰成static即是静态方法,如下:
public interface TestService {
/**
* 接口抽象方法
*/
void abstractTest();
/**
* 接口静态方法
*/
static void staticTest() {
System.out.println("do staticTest");
}
}
public class TestServiceImpl implements TestService {
@Override
public void abstractTest() {
System.out.println("do test");
}
//无法重写接口静态方法
}
静态方法直接通过接口类调用,和以前调用静态方法的方式没差,如下:
public class Test {
public static void main(String[] args) {
//接口静态方法的操作方式
TestService.staticTest();
}
}
接口使用静态方法,可以在默认方法的基础上,进一步保证接口方法的安全性,不希望被扩展的接口就用静态方法定义吧。