Java集合3:List,AbstractList和ArrayList

List

List是一个有序集合的接口,自然就相比Collection来说就添加了一些和索引有关的方法:

void add(int index, E element);
boolean addAll(int index, Collection<? extends E> c);
default void sort(Comparator<? super E> c);
E get(int index);
E set(int index, E element);
E remove(int index);
int indexOf(Object o);      //若未找到则返回-1
int lastIndexOf(Object o);  //若未找到则返回-1

以及一些其他独有的方法:

ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
default void replaceAll(UnaryOperator<E> operator)
List<E> subList(int fromIndex, int toIndex);

值得一提的是,在Java 9之后还出了一堆静态方法,它们是用来创建不可修改的List的(也就是生成对象以后就不能新增和修改其中的元素了)

static <E> List<E> of()
static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
...
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> List<E> of(E... elements)

AbstractList

AbstractColletion类似,它也是系统提供的一个List接口的骨干实现,为了减轻程序员的工作量。如果要实现不可修改元素的列表,继承它并实现get(int)size()方法即可。若要实现可修改元素的列表,还需要实现set(int, E)add(int, E)remove(int)方法 (如果是长度不可变的列表的话后两个方法也可以不实现)。

它继承自AbstractColletion,也就是说它将AbstractColletion里的iterator方法给实现了,不过这个方法在本系列第一讲中就已经介绍过了hhhh

然后它也实现了List接口,将大部分方法给实现了。
这些方法都比较简单,值得一提的是subList方法:

public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size());
    return (this instanceof RandomAccess ?
            new RandomAccessSubList<>(this, fromIndex, toIndex) :
            new SubList<>(this, fromIndex, toIndex));
}

根据名字就知道这是用来生产子列表的。
这里先进行防越界检查,然后就是判断是不是RandomAccess接口的实例(这个接口,根据文档解释,就是用来表示某个列表是否支持随机访问,而不是只支持顺序访问),然后再生成SubList的对象。
SubList是个内部类,继承自AbstractList
构造函数有两个:

    /**
     * Constructs a sublist of an arbitrary AbstractList, which is
     * not a SubList itself.
     */
    public SubList(AbstractList<E> root, int fromIndex, int toIndex) {
        this.root = root;
        this.parent = null;
        this.offset = fromIndex;
        this.size = toIndex - fromIndex;
        this.modCount = root.modCount;
    }

    /**
     * Constructs a sublist of another SubList.
     */
    protected SubList(SubList<E> parent, int fromIndex, int toIndex) {
        this.root = parent.root;
        this.parent = parent;
        this.offset = parent.offset + fromIndex;
        this.size = toIndex - fromIndex;
        this.modCount = root.modCount;
    }

分别是用List来生成SubList,以及用SubList来生成SubList,支持多层嵌套,也就是说SubList的SubList的SubList...这种都可以。还可以看出root是指最最上层的根List,而parent则是比自己高一级的SubList。

仔细看一下其他方法:

public E set(int index, E element) {
    Objects.checkIndex(index, size);
    checkForComodification();
    return root.set(offset + index, element);
}

public E get(int index) {
    Objects.checkIndex(index, size);
    checkForComodification();
    return root.get(offset + index);
}

public void add(int index, E element) {
    rangeCheckForAdd(index);
    checkForComodification();
    root.add(offset + index, element);
    updateSizeAndModCount(1);
}

public E remove(int index) {
    Objects.checkIndex(index, size);
    checkForComodification();
    E result = root.remove(offset + index);
    updateSizeAndModCount(-1);
    return result;
}

可以看出这里的各种增删查改都是通过调用根列表的增删查改实现的。除此之外,在所有操作之前都有调用checkForComodification方法,这是不是和Iterator里的很相似hhh
不过这里是判断自己的modCount和根列表的modCount是否相等:

private void checkForComodification() {
    if (root.modCount != this.modCount)
    throw new ConcurrentModificationException();
}

它的作用也和iterator里的一样,为了避免外部类偷偷修改了数组元素的个数,从而导致内部类中size属性无法得到更新从而出错。
既然如此,那在内部类中修改了数组个数之后就需要对modCount进行更新了,这在updateSizeAndModCount方法中有具体实现:

private void updateSizeAndModCount(int sizeChange) {
    SubList<E> slist = this;
    do {
        slist.size += sizeChange;
        slist.modCount = root.modCount;
        slist = slist.parent;
    } while (slist != null);
}

大致上来说就是一直往上寻找自己的上一级SubList,把他们的modCount和size都给更新了,这样下次调用checkForComodification就不会抛出错误了。


ArrayList

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容