zoukankan      html  css  js  c++  java
  • Java集合框架之List接口浅析

    Java集合框架之List接口浅析

    一、List综述:

      毫无疑问List接口位于java.util包下,继承自 Collection接口

    • 存储元素的特点:

       有序可重复(有序:即存进去是什么顺序,取出来还是什么顺序,至于可重复相信大家都能理解)

       存储元素对象:只存储引用数据类型(其实可以存储任何对象,基本数据类型会自动转为包装类存储),包括null,有时候我们也常把List称为序列

    • 重要的实现类:ArrayList、LinkedList、Vector(我将在后续章节展开详细讨论,具体请关注我的博文)

    二、List方法摘要:

     boolean add(E e)   向列表的尾部添加指定的元素(可选操作)。
     void add(int index, E element)   在列表的指定位置插入指定元素(可选操作)。
     boolean

    addAll(Collection<? extends E> c)  添加指定 collection 中的所有元素到此列表的结尾,顺序是指定collection 的迭代器返回这些元素的顺序(可选操作)。

     boolean

    addAll(int index, Collection<? extends E> c)

      将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。

     void clear()   从列表中移除所有元素(可选操作)。
     boolean contains(Object o)   如果列表包含指定的元素,则返回 true
     boolean containsAll(Collection<?> c)   如果列表包含指定 collection 的所有元素,则返回 true
     boolean equals(Object o)   比较指定的对象与列表是否相等。
     E get(int index)   返回列表中指定位置的元素。
     int hashCode()   返回列表的哈希码值。
     int indexOf(Object o)   返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
     boolean isEmpty()   如果列表不包含元素,则返回 true
     Iterator<E> iterator()   返回按适当顺序在列表的元素上进行迭代的迭代器。
     int lastIndexOf(Object o)   返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
     ListIterator<E> listIterator()   返回此列表元素的列表迭代器(按适当顺序)。
     ListIterator<E> listIterator(int index)   返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
     E remove(int index)   移除列表中指定位置的元素(可选操作)。
     boolean remove(Object o)   从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。
     boolean removeAll(Collection<?> c)   从列表中移除指定 collection 中包含的其所有元素(可选操作)。
     boolean retainAll(Collection<?> c)   仅在列表中保留指定 collection 中所包含的元素(可选操作)。
     E set(int index, E element)  用指定元素替换列表中指定位置的元素(可选操作)。
     int size()   返回列表中的元素数。
     List<E>

    subList(int fromIndex, int toIndex)   

      返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。

     Object[] toArray()   返回按适当顺序包含列表中的所有元素的数组(从第一个元素到最后一个元素)。
    <T> T[]
    toArray(T[] a)   返回按适当顺序(从第一个元素到最后一个元素)包含列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。

    三、相关扩展:

    3.1List 与 Array 区别

    List 在很多方面跟 Array 数组感觉很相似,尤其是 ArrayList,那 List 和数组究竟哪个更好呢?

    • 相似之处:

      • 都可以表示一组同类型的对象

      • 都使用下标进行索引

    • 不同之处:

      • 数组可以存任何类型元素

      • List 不可以存基本数据类型,必须要包装

      • 数组容量固定不可改变;List 容量可动态增长

      • 数组效率高; List 由于要维护额外内容,效率相对低一些

    容量固定时优先使用数组,容纳类型更多,更高效。

    在容量不确定的情景下, List 更有优势,看下 ArrayList 和 LinkedList 如何实现容量动态增长:

    ArrayList 的扩容机制:

    public boolean add(E object) {

      Object[] a = array; int s = size;

      //当放满时,扩容

      if (s == a.length) {

        //MIN_CAPACITY_INCREMENT 为常量,12

        Object[] newArray = new Object[s + (s < (MIN_CAPACITY_INCREMENT / 2) ? MIN_CAPACITY_INCREMENT : s >> 1)];         System.arraycopy(a, 0, newArray, 0, s);

        array = a = newArray;

      }

      a[s] = object;

      size = s + 1;

      modCount++;

      return true;

    }

    可以看到:

    • 当 ArrayList 的元素个数小于 6 时,容量达到最大时,元素容量会扩增 12;

    • 反之,增加 当前元素个数的一半。

    LinkList的扩容机制:

    public boolean add(E object) {

      return addLastImpl(object);

    }

    private boolean addLastImpl(E object) {

      Link<E> oldLast = voidLink.previous;

      Link<E> newLink = new Link<E>(object, oldLast, voidLink);

      voidLink.previous = newLink;

      oldLast.next = newLink;

      size++;

      modCount++;

      return true;

    }

    可以看到,没!有!扩容机制!

    这是由于 LinedList 实际上是一个双向链表,不存在元素个数限制,使劲加就行了。

    transient Link<E> voidLink;

    private static final class Link<ET> {

      ET data;

      Link<ET> previous, next;

      Link(ET o, Link<ET> p, Link<ET> n) {

        data = o;

        previous = p;

        next = n;

      }

    }

    3.2List 与 Array 之间的转换

    在 List 中有两个转换成 数组 的方法:

    • Object[] toArray()

      • 返回一个包含 List 中所有元素的数组;

    • T[] toArray(T[] array)

      • 作用同上,不同的是当 参数 array 的长度比 List 的元素大时,会使用参数 array 保存 List 中的元素;否则会创建一个新的数组存放 List 中的所有元素;

    ArrayList 中的实现:

    public Object[] toArray() {

      int s = size;

      Object[] result = new Object[s];

      //这里的 array 就是 ArrayList 的底层实现,直接拷贝

      //System.arraycopy 是底层方法,效率很高

      System.arraycopy(array, 0, result, 0, s);

      return result;

    }

    public <T> T[] toArray(T[] contents) {

      int s = size;

      //先判断参数能不能放下这么多元素

      if (contents.length < s) {

        //放不下就创建个新数组

        @SuppressWarnings("unchecked")

        T[] newArray = (T[]) Array.newInstance(contents.getClass().getComponentType(), s);

        contents = newArray;

      }

      System.arraycopy(this.array, 0, contents, 0, s);

      if (contents.length > s) {

        contents[s] = null;

      }

      return contents;

    }

    LinkedList 的实现:

    public Object[] toArray() {

      int index = 0;

      Object[] contents = new Object[size];

      Link<E> link = voidLink.next;

      while (link != voidLink) {

        //挨个赋值,效率不如 ArrayList

        contents[index++] = link.data;

        link = link.next;

      }

      return contents;

    }

    @Override @SuppressWarnings("unchecked")

    public <T> T[] toArray(T[] contents) {

      int index = 0;

      if (size > contents.length) {

        Class<?> ct = contents.getClass().getComponentType();

        contents = (T[]) Array.newInstance(ct, size);

      }

      Link<E> link = voidLink.next;

      while (link != voidLink) {

        //还是比 ArrayList 慢

        contents[index++] = (T) link.data;

        link = link.next;

      }

      if (index < contents.length) {

        contents[index] = null;

      }

      return contents;

    }

    数组工具类 Arrays 提供了数组转成 List 的方法 asList :

    @SafeVarargs public static <T> List<T> asList(T... array) {

      return new ArrayList<T>(array);

    }

    使用的是 Arrays 内部创建的 ArrayList 的转换构造函数:

    private final E[] a;

    ArrayList(E[] storage) {

      if (storage == null) {

        throw new NullPointerException("storage == null");

      }

      //直接复制

      a = storage;

    }

    3.3迭代器 Iterator, ListIterator

    List 继承了 Collection 的 iterator() 方法,可以获取 Iterator,使用它可以进行向后遍历。

    在此基础上,List 还可以通过 listIterator(), listIterator(int location) 方法(后者指定了游标的位置)获取更强大的迭代器 ListIterator。

    使用 ListIterator 可以对 List 进行向前、向后双向遍历,同时还允许进行 add, set, remove 等操作。

    List 的实现类中许多方法都使用了 ListIterator,比如 List.indexOf() 方法的一种实现:

    public int indexOf(E e) {

      for (ListIterator<E> it = listIterator(); it.hasNext(); )

        if (e == null ? it.next() == null : e.equals(it.next()))

          return it.previousIndex();

      // Element not found

      return -1;

    }

      ListIterator 提供了 add, set, remove 操作,他们都是对迭代器刚通过 next(), previous()方法迭代的元素进行操作。下面这个栗子中,List 通过结合 ListIterator 使用,可以实现一个多态的方法,对所有 List 的实现类都适用:

    public static <E> void replace(List<E> list, E val, E newVal) {

      for (ListIterator<E> it = list.listIterator(); it.hasNext(); )

        if (val == null ? it.next() == null : val.equals(it.next()))

          it.set(newVal);

    }

    参考:http://blog.csdn.net/u011240877/article/details/52802849

  • 相关阅读:
    HDU 1505 City Game
    HDU 1506 Largest Rectangle in a Histogram
    HDU 1838 Chessboard
    HDU 2512 一卡通大冒险
    HDU 1081 To The Max
    HDU 2845 Beans
    HDU 1422 重温世界杯
    HDU 1231 最大连续子序列
    第6章 接口和实现
    java面向抽象编程样例
  • 原文地址:https://www.cnblogs.com/albertrui/p/8329626.html
Copyright © 2011-2022 走看看