JAVA集合框架学习之:从Iterable到ArrayList 设计之美初体验

在阅读正文之前几点说明:
1.此篇博客献给那些初学JAVA的初级程序员,大牛可以忽略(能指点一番更好)
2.此篇博客灵感来自于 看Java核心卷之集合迭代器时,接口对象指向.Iterator()而产生的对Iterator()这个迭代器究竟返回什么对象以及迭代器实现的好奇
3.此篇博客从3条继承线完整讲述了如何设计出了ArrayList
4.此篇博客从源码分析,带你找一点接口程序设计,动态绑定(设计)运用的感觉

一.ArrayList 构成之三条继承线。
ArrayList的使用可以分为2个部分,1个是通过迭代器对数组进行操作,另1个是直接对数组进行操作(利用其中的方法);
于是自然而然分为2个部分(超级接口Iterable和迭代器接口Iterator来进行继承了
而完整构成迭代器 居然涉及了2条线!
①Iterable接口—>Collection接口—>AbstractCollection抽象类—>AbstractList抽象类——>ArrayList
这一条构成了ArraylList的直接操作集
②Collection接口->List接口->AbstractList抽象类(不是AbCollection)
③Itertor接口—>ListIerator接口 —>AbstactList抽象类的内部类(后面重点解释)

二.ArrayList操作集的形成
1.由超级接口Iterable开始,这个接口中只包含一个方法 Iterator iterator();
紧接着往下Colletion接口继承了这个接口,我们看看java.util.Collection可以了解到这里定义了一系列的抽象方法(没有提供default默认实现) 我们先记录其中重要的方法声明

 int size();
boolean isEmpty();
boolean contains(Object o);
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
 boolean remove(Object o);
 boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
 boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
boolean equals(Object o);
    int hashCode();

 Iterator<E> iterator();  [从上层继承过来,仍然未实现,可以不显式写出来,我估计写出来放这里 是为了当时设计和读者好阅读]

2.从Collection 往后,AbstractCollection抽象类继承了这个接口。并为其中的许多方法提供了实现,这将以最大限度地减少了实现此接口所需的工作!!
我们具体来看几个这个类所实现的Collection接口方法

public boolean isEmpty() {
        return size() == 0;
}
 public boolean contains(Object o) {
        Iterator<E> it = iterator();
        if (o==null) {
            while (it.hasNext())
                if (it.next()==null)
                    return true;
        } else {
            while (it.hasNext())
                if (o.equals(it.next()))
                    return true;
        }
        return false;
    }
  public boolean remove(Object o) {
        Iterator<E> it = iterator();
        if (o==null) {
            while (it.hasNext()) {
                if (it.next()==null) {
                    it.remove();
                    return true;
                }
            }
        } else {
            while (it.hasNext()) {
                if (o.equals(it.next())) {
                    it.remove();
                    return true;
                }
            }
        }
        return false;
    }
等等还有一些;需要注意到的事情是,这些方法实现的使用的是仍然没有具体实现的方法来实现的!!以public boolean isEmpty() {
        return size() == 0;   
}为例, 我们可以看到 方法内部就是 size()返回的int值如果是0的话,说明是空的,而此刻size()方法并未有具体实现。

那么为什么这样做呢
子类在之后实现了size(), 如果后面没有对isEmpty进行重写。那么子类A(假设有个A的实例 引用为a)使用a.isEmpty()将调用这里的实现,然后会调用this.size方法,而这里的方法未实现(这里的上一层可能实现了),没关系,虚拟机会找到他应该调用的size()方法的[动态绑定] 所以这么做的话,继承该类的子类,不需要再去实现isEmpty了,只需要将size()实现就好了。 降低了实现所需的工作量,同时代码可以重用 。[设计之美]
以上函数剩下2个的实现运用到了迭代器中的方法稍后讲。
这里列出了该抽象类对Collection实现 的方法:

boolean isEmpty();
boolean contains(Object o);
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
 boolean remove(Object o);
 boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
 boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);

仍未实现的方法有

 int size();
boolean equals(Object o);
    int hashCode();
 Iterator<E> iterator();
这4个方法

做出修改的方法:

   public boolean add(E e) {
        throw new UnsupportedOperationException();
} 

空实现,抛出了一个异常,在之后肯定要被覆盖重写。 为什么这么做呢? 我的理解是
对之后的实现进行指示。 

3.从AbstractCollection到 AbstrctList抽象类。
相比上一层的变化:
进一步重写了 add方法:

public boolean add(E e) {
        add(size(), e);
        return true;
}

实现了:

    public Iterator<E> iterator() {
            return new Itr();    //此后会对该方法重点讲
    }

public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;
}
        ListIterator<E> e1 = listIterator();    //另一条线的方法
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }
   public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }

到这里来自上层的仍然未有实现的方法还剩1个 int size();
这个类中还新增了抽象方法:

set(int index, E element) 
get(int index)
remove(int index)  (重载了Object obj的那一个)

4.从Abstract到ArrayList
看源码可以知道在ArrayList中定义了域 private int size;
并实现了方法public int size() {
return size;
}
同时对上层新增的以索引为参数的set,get,remove方法进行了实现
至此,如果我们实现了迭代器的3个方法,之前所有设计的函数内部调用的函数均有的具体的实现—>所有的函数都有了具体的实现,一个ArrayList操作集完成了!

三.迭代器到底怎么实现的呢
看了前面那么多,还是不知道迭代器在哪里实现了查看帮助文档
public interface ListIterator extends Iterator
就是从 Iterator—>ListIterator;之后没有继承的类了。关键是ListIterator是一个接口啊!!!哪有什么实现!!。没办法,于是只好根据仅有的线索去看源码。
让我们看下面2条线
①Collection接口->List接口->AbstractList抽象类
从Colltion到List 增加了2个重要的抽象方法:

  ListIterator<E> listIterator();
 ListIterator<E> listIterator(int index);

看起来很像C++的构造方法,但是并不是。返回值类型为2个接口引用的方法,可以判断出是返回一个实现了 ListIterator 接口的实例对象(迭代器),这里的ListIterator 就是我们上述最后一条继承线的最下层了(还未实现)。 是不是觉得我们离揭示迭代器又近了一步呢?
让我们继续往下走,AbstractList 继承了这个List接口,于是看看AbstractList的源码
找到了这个2个实现

public ListIterator<E> listIterator() {
        return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
        rangeCheckForAdd(index);

        return new ListItr(index);
    }

第一个方法是调用第二个方法 令参数X=0实现了。在这里我们看到了newListItr(IndeX)
算上之前看到的 public Iterator iterator() {
return new Itr();
}
一共三个迭代器方法,终于看到了有new的2个部分!!!实例化啦!!不是接口 ,不是抽象类,而是真真正正可以用new实例化的类!!! 让我去看看这个ListItr 和Itr究竟是何方神圣?

打开声明:private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         */
        int cursor = 0;
    /**
     * Index of element returned by most recent call to next or
     * previous.  Reset to -1 if this element is deleted by a call
     * to remove.
     */
    int lastRet = -1;

    /**
     * The modCount value that the iterator believes that the backing
     * List should have.  If this expectation is violated, the iterator
     * has detected concurrent modification.
     */
    int expectedModCount = modCount;

    public boolean hasNext() {
        return cursor != size();
    }

    public E next() {
        checkForComodification();
        try {
            int i = cursor;
            E next = get(i);
            lastRet = i;
            cursor = i + 1;
            return next;
        } catch (IndexOutOfBoundsException e) {
            checkForComodification();
            throw new NoSuchElementException();
        }
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            AbstractList.this.remove(lastRet);
            if (lastRet < cursor)
                cursor--;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException e) {
            throw new ConcurrentModificationException();
        }
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

哇哇哇,终于看到了Iterator接口里面定义的3个方法的实现啦!!!终于找到了!
然后上述类的一些参数可能没看过的人不清楚是干嘛的,这里就不说明了,可能下篇博客会拿出来讲讲
另外一个ListTtr类节约版面这里就稍作解释就不列源码了 ListTtr类是继承了上面这个Itr的一个子类。所以其实AbtractList中有2种迭代器。不过他们的根源都是Itr.
Itr是存在于AbtractList中的一个内部类,实现了ListIterator接口。对这个用法我也不能叙述的太清楚: 实现了ListIterator接口的Itr相当于是一个厂家/服务商,他对外提供了 Iterable接口(不要和Iterator混为一谈,一个是厂家提供具体服务要做的,一个是客户申请服务用的)一个类只要实现了Iterable接口(给钱?) 他就为这个厂家提供迭代服务。可以类比(不知道这么比对不对哈) sort方法 和comparable接口,一个类实现了compareable接口(比较原则),sort方法就为该类的数组提供排序服务)
最后一条线通过上述分析就很清楚了
②Itertor接口—>ListIerator接口 —>AbstactList抽象类的内部类。
自此迭代器的方法也全部实现了。
那么Arraylist的操作集算是彻底构成了!

四.一点小补充
其实到这里位置,ArrayList的这些对外功能已经可以用了,但是看源码可以发现
对这些已经可以用了的方法许多方法仍然进行了覆盖重写。举个例子
public boolean isEmpty() {
return size == 0;
}
这是最终ArrayList版本中的 isEmpty方法,对比之前public boolean isEmpty() {
return size() == 0;
}
为什么要可以用了还要进一步的覆盖重写呢
个人觉得是为了优化, 调用一个size()函数肯定没有直接用域值比较来的快对吧~

最后BB几句。其实在看源码的时候,是先在AbstractList里面找到了 ListIterator 的迭代器方法,才跟踪到了List那边去看。然后找到了Colleciton->list->AbstractList这条线。
而且在AbstractList 里面还有一个内部类 继承了AbstractList(内部类)为什么可以继承自己?? 而且里面还用了匿名内部类实现了相关的方法(包括迭代器)[我的天,内部类的内部类excuse me???]

最后附一个继承关系图
在这里插入图片描述

作者 :相赫哥哥
引用转载附作者谢谢啦~~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值