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

Java集合框架之List接口浅析的更多相关文章

  1. Java集合框架之Map接口浅析

    Java集合框架之Map接口浅析 一.Map接口综述: 1.1java.util.Map<k, v>简介 位于java.util包下的Map接口,是Java集合框架的重要成员,它是和Col ...

  2. Java集合框架之Set接口浅析

    Java集合框架之Set接口浅析 一.java.util.Set接口综述: 这里只对Set接口做一简单综述,其具体实现类的分析,朋友们可关注我后续的博文 1.1Set接口简介 java.util.se ...

  3. Java集合框架之Collection接口

    Java是一门面向对象的语言,那么我们写程序的时候最经常操作的便是对象了,为此,Java提供了一些专门用来处理对象的类库,这些类库的集合我们称之为集合框架.Java集合工具包位于Java.util包下 ...

  4. java 集合框架(二)Iterable接口

    Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...

  5. Java集合框架之四大接口、常用实现类

    Java集合框架 <Java集合框架的四大接口> Collection:存储无序的.不唯一的数据:其下有List和Set两大接口. List:存储有序的.不唯一的数据: Set:存储无序的 ...

  6. Java集合框架中Map接口的使用

    在我们常用的Java集合框架接口中,除了前面说过的Collection接口以及他的根接口List接口和Set接口的使用,Map接口也是一个经常使用的接口,和Collection接口不同,Map接口并不 ...

  7. Java集合框架中List接口的简单使用

    Java集合框架可以简单的理解为一种放置对象的容器,和数学中的集合概念类似,Java中的集合可以存放一系列对象的引用,也可以看做是数组的提升,Java集合类是一种工具类,只有相同类型的对象引用才可以放 ...

  8. Java集合框架的基础接口有哪些?

    Collection为集合层级的根接口.一个集合代表一组对象,这些对象即为它的元素.Java平台不提供这个接口任何直接的实现. Set是一个不能包含重复元素的集合.这个接口对数学集合抽象进行建模,被用 ...

  9. java集合框架部分相关接口与类的介绍

    集合基础 接口 Iterable //Implementing this interface allows an object to be the target of the "for-ea ...

随机推荐

  1. Redis 学习笔记(篇六):数据库

    Redis 是一个使用 C 语言编写的 NoSql 的数据库,本篇就讲解在 Redis 中数据库是如何存储的?以及和数据库有关的一些操作. Redis 中的所有数据库都保存在 redis.h/redi ...

  2. tcp 3次握手四次挥手

    转载link:http://www.jianshu.com/p/9968b16b607e 最近在复习计算机网络,看到TCP这一章,总结一下. 建立TCP需要三次握手才能建立,而断开连接则需要四次握手. ...

  3. Android开发——通过wifi接收IPCamera视频流

    前面,我们已经了解了怎么在android app上打开关闭和扫描,搜索wifi,现在,我来写一下怎么通过连接wifi来使app获取到IPCamera摄像头的视频. 一.通过URL获取视频的地址 二.创 ...

  4. codeforces 213div(2) 365 A.Good Number 365 B.The Fibonacci Segment

    #include <stdio.h> #include <string.h> bool vis[11]; int n, k; bool judge(int x) { memse ...

  5. jenkins弱口令漏洞

    jenkins弱口令漏洞 一.漏洞描述 通过暴力破解管理控制台,如果爆破成功,可获得后台管理权限.操作后台,后台可通过脚本命令行功能执行系统命令,如反弹shell等,低权限可以通过创建控制台输出方式执 ...

  6. Thread.Sleep太久,界面卡死

    在Winform程序的UI界面使用Thread.Sleep,窗体界面会被卡死,如图1所示,程序sleep 5000毫秒,时间到了之后,按钮的名称才更改过来,窗体也能被鼠标拖动.而用Delay方法,就能 ...

  7. git和githup

    一:Git简介 1.1:VCS的历史 Git是一款代码管理工具(Version Control System),傲视群雄,是目前世界上最先进的免费开源的分布式版本控制系统,没有之一! VCS版本控制系 ...

  8. python_0基础开始_day03

    第三节 一.整形和布尔值的转换 int整型 python3: 全部都是整型 python2: 整型,长整型long 十进制转换二进制 # 将十进制的168转换为二进制 ​#得出结果 将十进制的168转 ...

  9. Java基础:数组Array转成List的几种方法

    在编写Java程序中,经常要用的一个转换就是数组和List对象之间的互转. 最简单的方法就是遍历 数组,然后将数组元素依次添加进list中. 此方法略,虽然方法很简单,但总感觉这样的方法有点笨 第二种 ...

  10. Unity实现放大缩小以及相机位置平移实现拖拽效果

    放大缩小功能是游戏开发中用到的功能,今天就来讲一下Unity中放大缩小怎么实现. 1.IDragHandler, IBeginDragHandler, IEndDragHandler这三个接口是Uni ...