zoukankan      html  css  js  c++  java
  • Java集合为什么设计为:实现类继承了抽象类,同时实现抽象类实现的接口

     

    更好阅读体验:Java集合为什么设计为:实现类继承了抽象类,同时实现抽象类实现的接口

    问题

    Java集合源码为什么设计为:「实现类继承了抽象类,同时实现抽象类实现的接口?」

    看着List 集合的UML图来分析

    如图:接口+抽象类都是成对出现,Collection 和 AbstractCollection;List 和 AbstractList。ArrayList 继承了AbstractList,同时实现了List 接口。

    img

    再看下其他集合的UML 图,看看是不是也是这样设计的

    img

    img

    img

    这样设计的意义

    有的人说接口只能使用抽象方法,为了实现公共的方法抽出来用抽象类来实现,提高代码复用性,提高代码质量。

    其实不是,第一句就错了,接口同样是可以实现方法,用的关键字是 default。如果真的是为了公共的实现方法抽出来用抽象类来实现,那还不如直接在接口上实现不更好,而且具体的实现类(如:ArrayList)还不用继承抽象类,毕竟继承还是单一的。

    List 接口继承了Collection 接口绝大部分方法,并新定义了List 特有的抽象方法,而这些特有的抽象方法都交给了AbstractList 来实现。

    抽两个方法来看看

        // AbstractList
        public void add(int index, E element) {
            throw new UnsupportedOperationException();
        }
    ​
        public E remove(int index) {
            throw new UnsupportedOperationException();
        }

    在AbstractList中,这两个方法只是抛了个“不支持的操作异常”,并没有具体的内容。要明白抽象类是多种类的再一次抽象,也就是说具体的实现方法还是要针对不同的类来编写,所以还要看看ArrayList 和 LinkedList 对add(int index, E element)的具体实现

     // ArrayList 
     public void add(int index, E element) {
            rangeCheckForAdd(index);
    ​
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            System.arraycopy(elementData, index, elementData, index + 1, size - index);
            elementData[index] = element;
            size++;
        }
    ​
     // LinkedList 
     public void add(int index, E element) {
            checkPositionIndex(index);
    ​
            if (index == size)
                linkLast(element);
            else
                linkBefore(element, node(index));
        }

    可见,这两个方法的实现完全不同(底层数据结构不同),到此应该明白一点了:「List 接口定义个List 特有的规范,AbstractList 对这个规范做了通用实现,而具体实现还是要在具体类里面落实」。但并不是只是为了高复用性、减少代码重复度。

    比如:public int indexOf(Object o); 虽然抽象类实现了,但具体类还是重写了这方法,显然不是为了解决代码复用的问题,而是提供了通用实现,具体的还有看具体类使用了什么类型的数据结构,然后在具体类中重写方法定制化的实现。

        // AbstractList
       public int indexOf(Object o) {
            ListIterator<E> it = listIterator();
            if (o==null) {
                while (it.hasNext())
                    if (it.next()==null)
                        return it.previousIndex();
            } else {
                while (it.hasNext())
                    if (o.equals(it.next()))
                        return it.previousIndex();
            }
            return -1;
        }
        // ArrayList
        public int indexOf(Object o) {
            if (o == null) {
                for (int i = 0; i < size; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = 0; i < size; i++)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }
        // LinkedList
        public int indexOf(Object o) {
            int index = 0;
            if (o == null) {
                for (Node<E> x = first; x != null; x = x.next) {
                    if (x.item == null)
                        return index;
                    index++;
                }
            } else {
                for (Node<E> x = first; x != null; x = x.next) {
                    if (o.equals(x.item))
                        return index;
                    index++;
                }
            }
            return -1;
        }

    意义

    1.接口实现的解耦:接口新增或删除方法时,只需在抽象类中做个方法初始实现(对于删除方法可以不做处理),即可避免一个接口变动导致所有实现类都需要更新代码的问题。

    2.多态特性的运用,向上转型:ArrayList 、Vector、LinkedList 都可以实现对数据的存储,都可以用List 作为引用(面向接口编程)。

    「总结」

    • 提高接口的灵活性:接口只需要按需重写方法;

    • 提高接口的易扩展:接口变动不影响实现类,只需要更改相应的抽象类实现即可;

    • 抽象类和接口的互补:接口规定行为规范,抽象类补充属性和接口实现的解耦。

       

      个人理解,如有不对,还望纠正。

  • 相关阅读:
    git
    HTML5 新增语义化标签
    vue directive 常用指令
    JS 数组 数组迭代方法 map, forEach, filter, some, every,
    图片居中
    进度条
    移动页面 REM自适应
    轮播图基本样式
    webpack3.0
    关于码云中项目提交的问题
  • 原文地址:https://www.cnblogs.com/dennyLee2025/p/15779514.html
Copyright © 2011-2022 走看看