文章首发于个人博客,欢迎访问关注:https://www.lin2j.tech
StackOverFlow的答案在这里 传送门
在Java的集合类中,有很多这种操作,一个集合类实现了抽象类后,又显式地实现抽象类实现的接口。我通过一段代码来解释为什么要这样,也可以直接跳过代码,看好处。
解释一下:
现在有四个接口 A,B,C,Aa(Aa,实际上是继承了A,B)
有一个抽象类,该抽象类实现了 Aa,就相当于 AbstractList 实现了 List
有两个版本的实现了,一个在类声明的时候显式地声明了自己实现了 A B,一个则没有
public interface A {}
public interface B {}
public interface C {}
public interface Aa extends A, B {}
public abstract class AbstractAa implements Aa{ }
public class AaImplV1 extends AbstractAa implements C{ }
public class AaImplV2 extends AbstractAa implements A, B, C { }
接下来通过代码来测试一下这两种声明方式的区别
import java.util.Arrays;
public class InterfaceTest {
@Test
public void interfaceTest(){
AaImplV1 v1 = new AaImplV1();
AaImplV2 v2 = new AaImplV2();
// 输出该类实现的接口
System.out.println("V1: " + Arrays.toString(v1.getClass().getInterfaces()));
System.out.println("V2: " + Arrays.toString(v2.getClass().getInterfaces()));
// 这种机制不影响 instanceof
System.out.println("V1 instanceof A: " + (v1 instanceof A));
// 使用 Apache Common Lang 包的类来获取该类实现的所有接口
System.out.println("V1: " + ClassUtils.getAllInterfaces(v1.getClass()));
System.out.println("V2: " + ClassUtils.getAllInterfaces(v2.getClass()));
}
}
输出
V1: [interface com.jia.interfaces.C]
V2: [interface com.jia.interfaces.A, interface com.jia.interfaces.B, interface com.jia.interfaces.C]
V1 instanceof A: true
V1: [interface com.jia.interfaces.C, interface com.jia.interfaces.Aa, interface com.jia.interfaces.A, interface com.jia.interfaces.B]
V2: [interface com.jia.interfaces.A, interface com.jia.interfaces.B, interface com.jia.interfaces.C, interface com.jia.interfaces.Aa]
再来看看二者的依赖图
AaImplV1 | AaImplV2 |
---|---|
![]() | ![]() |
可以看出跟测试程序输出的结果有点像,显式声明的接口才会被打印出来。不过好在这种机制不会影响 instanceof 关键字,可以看测试代码。
虽然这两种实现方式的效果是一样的,但是建议使用V2的方式,好处是
- 规范:相比较V1,我们在看V2的类声明时就知道该类实现的接口有哪一些,而不用追溯到整个类结构。
- 可读性:可以更方便地获取该类实现的所有接口。像V1这样隐式实现的,不能直接获取所有接口,而是通过递归迭代类层次结构,或者使用Apache Common Lang 包里的ClassUtils类(实质也是递归查询,看下面代码)
ClassUtils.getAllInterfaces(Class<?> cls) 的原理,递归查询每个类实现的接口,然后放在一个LinkHashSet中。有兴趣可以自己去看ClassUtils的源码。
private static void getAllInterfaces(Class<?> cls, final HashSet<Class<?>> interfacesFound) {
while (cls != null) {
final Class<?>[] interfaces = cls.getInterfaces();
for (final Class<?> i : interfaces) {
if (interfacesFound.add(i)) {
getAllInterfaces(i, interfacesFound);
}
}
cls = cls.getSuperclass();
}
}