为什么Java中的Collection类都继承了抽象类还要实现抽象类的接口?

文章首发于个人博客,欢迎访问关注: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]

再来看看二者的依赖图

AaImplV1AaImplV2
201905192015354692019051920155055

可以看出跟测试程序输出的结果有点像,显式声明的接口才会被打印出来。不过好在这种机制不会影响 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();
         }
     }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值