List的几种实现的区别与联系

List主要有ArrayList、LinkedList与Vector几种实现。

ArrayList底层数据结构是数组, 增删慢、查询快; 线程不安全, 效率高; 不可以设置扩展容量, 默认增长1.5倍; 无参构造器初始化时, 初始容量为0。

LInkedList底层数据结构是链表, 增删快、查询慢; 线程不安全, 效率高。

Vector底层数据结构是数组, 增删慢、查询快; 线程安全, 效率低; 可以设置扩展容量, 默认增长2倍; 无参构造器初始化时, 初始容量为10。

List转换及删除元素

数组转List 集合

对于一个数组, 可以通过 Arrays.asList(T... a) 方法转换成List集合, 需要注意的是, 此方法得到的ArrayList对象是基于Arrays内部类 java.util.Arrays$ArrayList 来创建的, 而非 java.util.ArrayList 。这就涉及到了一个问题, 通过 asList(T... a) 转换得到的List集合是不允许进行增删操作的, 我们先看如下代码:

@Testpublic voidconvertList() {

List list = Arrays.asList("张小凡", "陆雪琪", "碧瑶");//list.add("qingshanli");

list.remove(0);

}

运行时会报异常 java.lang.UnsupportedOperationException

我们先来看看 java.util.Arrays$ArrayList 的方法层次结构:

可以看出,  java.util.Arrays$ArrayList 并没有覆写父类AbstractList的 add() 和 remove() 方法, 根据Java的三大特性之多态性可知, 上面代码中的增删操作实际调用的是父类AbstractList的方法, 我们再来看看AbstractList的部分源代码:

public E set(intindex, E element) {throw newUnsupportedOperationException();

}public void add(intindex, E element) {throw newUnsupportedOperationException();

}public E remove(intindex) {throw newUnsupportedOperationException();

}

到此, 可以得知其实通过 Arrays.asList(T... a) 转换得到的List集合是一个固定长度的集合, 所以不能进行增删操作。

如何在遍历时删除ArrayList中元素

方式一: 普通循环

public void test(Listlist) {for (int i = 0; i < list.size(); i++) {if (list.get(i) % 2 == 0) {

list.remove(list.get(i));

i--; //索引改变!

}

}

}

这种方式在删除操作时, 会改变集合的索引和size大小, 遍历时可能会产生角标越界异常, 因此不是特别推荐。

方式二: 高级for循环

public static voidmain(String[] args) {

List list = new ArrayList();for (int i = 0; i < 5; i++){

list.add(i);

}for(Integer num : list) {

System.out.print("value="+num);if (num % 2 == 0) {

list.remove(num);

System.out.println(" delete");

}else{

System.out.println(" not delete");

}

}

}

运行结果如下, 第一个元素删除正常, 后面继续遍历删除则抛异常 java.util.ConcurrentModificationException

如下, 反编译上述代码, 可以看出高级for循环底层其实就是使用iterator迭代器来进行遍历

public static voidmain(String[] args) {

ArrayList list = new ArrayList();for (int i = 0; i < 5; ++i) {

list.add(Integer.valueOf((int)i));

}

Iterator i=list.iterator();while(i.hasNext()) {

Integer num=(Integer)i.next();

System.out.print((String)new StringBuilder().append((String)"value=").append((Object)num).toString());if (num.intValue() % 2 == 0) {

list.remove((Object)num);

System.out.println((String)" delete");continue;

}

System.out.println((String)" not delete");

}

}

再来看看iterator迭代器实现类的部分源代码:

private class Itr implements Iterator{int cursor; //index of next element to return

int lastRet = -1; //index of last element returned; -1 if no such

int expectedModCount =modCount;

Itr() {}public booleanhasNext() {return cursor !=size;

}

@SuppressWarnings("unchecked")publicE next() {

checkForComodification();int i =cursor;if (i >=size)throw newNoSuchElementException();

Object[] elementData= ArrayList.this.elementData;if (i >=elementData.length)throw newConcurrentModificationException();

cursor= i + 1;return (E) elementData[lastRet =i];

}public voidremove() {if (lastRet < 0)throw newIllegalStateException();

checkForComodification();try{

ArrayList.this.remove(lastRet);

cursor=lastRet;

lastRet= -1;

expectedModCount=modCount;

}catch(IndexOutOfBoundsException ex) {throw newConcurrentModificationException();

}

}

@Override

@SuppressWarnings("unchecked")public void forEachRemaining(Consumer super E>consumer) {

Objects.requireNonNull(consumer);final int size = ArrayList.this.size;int i =cursor;if (i >=size) {return;

}final Object[] elementData = ArrayList.this.elementData;if (i >=elementData.length) {throw newConcurrentModificationException();

}while (i != size && modCount ==expectedModCount) {

consumer.accept((E) elementData[i++]);

}//update once at end of iteration to reduce heap write traffic

cursor =i;

lastRet= i - 1;

checkForComodification();

}final voidcheckForComodification() {if (modCount !=expectedModCount)throw newConcurrentModificationException();

}

}

View Code

可以看出, 迭代器内部的每次遍历操作 next() 、 remove() 方法都会记录List集合内部的modCount当做预期值expectedModCount, 然后在每次循环中判断预期值expectedModCount与List的成员变量modCount是否相等。但是因为上面 list.remove() 调用的是List集合的 remove() 方法, 继续跟踪源代码发现每次调用该方法就会 modCount++; , 但是迭代器内记录的预期值expectedModCount并没有跟着改变, 所以当第二次删除操作时就会发生异常。

方式三: iterator迭代器遍历

publicvoidtest(List list) {Iterator it =list.iterator();while(it.hasNext()) {int num =it.next();

System.out.print("value="+num);if (num % 2 == 0) {

it.remove();

System.out.println(" delete");

}else{

System.out.println(" not delete");

}

}

}

原理与方式二基本类似, 但是这里使用的是迭代器iterator的 remove() 方法, 我们再回顾之前迭代器实现类的源代码, 发现 remove() 方法中有 expectedModCount = modCount; 这个操作, 即调用迭代器的 remove() 方法时会同步List集合的modCount到迭代器的预期值expectedModCount当中, 所以迭代器方式删除才不会产生。

什么是快速失败, 安全失败机制

快速失败(fail-fast)

fail-fast机制是java集合中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。

使用迭代器遍历一个集合对象时,如果遍历过程中对集合进行了增删改, 则会抛出 ConcurrentModificationException 。

for(Integer id : list) {if (id == 2) {

list.remove(id);

}

}

在前面我们已经介绍过, 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个modCount变量来作为预期值expectedmodCount。集合在被遍历期间如果内容发生变化,就会改变集合内部的modCount值。每当迭代器使用而而迭代遍历调用 next() 方法时每次都会检测  if(modCount==expectedmodCount)  ,符合条件就返回遍历;否则将抛出异常终止遍历。

如果集合发生变化时修改modCount值, 并且又同步到expectedmodCount预期值, 比如前文中提到的iterator迭代器的 remove() 方法, 异常则不会抛出。因此, 不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。另外, 在java.util包下的集合类都是快速失败的, 是不能在多线程下发生并发修改的(即迭代过程中被修改)。

安全失败(fail-safe)

采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是在开始遍历时先复制原有集合内容,在拷贝的集合上进行遍历, 即在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发ConcurrentModificationException。java.util.concurrent包下的容器都是安全失败的, 可以在多线程下并发修改。

对象排序

实体类自身具备排序能力

Comparable接口用于使某个类具备可排序能力。实体类实现该接口后覆写其 compareTo() 方法,即可使实体类自身具备可排序的能力 。代码清单如下:

public class Student implements Comparable{privateString name;private intage;

@Overridepublic intcompareTo(Student o) {int flag = this.name.compareTo(o.name);if(flag == 0) {

flag= this.age -o.age;

}returnflag;

}

}

实体类具备了排序能力后, 调用List集合的 sort(Comparator super E> c) 或者Collections工具类的 sort(List list) 方法即可实现排序。

List list = new ArrayList();

list.sort(null);//Collections.sort(list);

使用比较器排序

Comparator是一个比较器接口,可以用来给不具备排序能力的对象进行排序。实现该比较器需覆写其 compare() 方法即可进行排序, 代码清单如下:

public classStudent {privateString name;private intage;

}public class StudentComparator implements Comparator{

@Overridepublic intcompare(Student o1, Student o2) {int flag =o1.getName().compareTo(o2.getName());if(flag == 0) {

flag= o1.getAge() -o2.getAge();

}returnflag;

}

}public classTest {public voidsortTest() {

List list = new ArrayList();

list.sort(newStudentComparator());//Collections.sort(list, new StudentComparator());

}

}

参考资料

作者:张小凡

出处:https://www.cnblogs.com/qingshanli/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如果觉得还有帮助的话,可以点一下右下角的【推荐】。

java list 博客园_Java集合系列(一)List集合相关推荐

  1. java知识点博客园_JAVA基础知识回顾

    JAVA基础知识回顾 一.背景介绍 JavaSE(J2SE)(Java2 Platform Standard Edition,java平台标准版) JavaEE(J2EE)(Java 2 Platfo ...

  2. java数据结构博客园_Java数据结构

    一.线性数据结构 1.Java一维数组的创建 (1)预先定义数组的内存空间 int[] arr = new int[3]; // new int[3]是代表创建3个内存地址空间 // 地址空间的序号是 ...

  3. java 入门 博客园_java入门基础

    什么是java? java是一门编程语言  编程语言有很多种 你比如 C语言 等等 为什么学习java呢! 因为你要和计算机交互  当然了你用汉语跟她说她听不懂 所以你要学习编程语言 那么额咱们的ja ...

  4. java知识点博客园_Java知识点总结1

    (1)普通代码块:就是类中方法的方法体 public void xxx(){ //code } (2)构造块:用{}裹起来的代码片段,构造块在创建对象时会被调用,每次创建对象 时都会被调用,并且优先于 ...

  5. java课程设计 博客园_Java课程设计博客(团队)

    Java课程设计博客(团队) 1. 团队/项目名称 使用JAVA实现简易HTTP服务器 2. 团队成员 组长:林一心 组员:张杭镖 3. 项目git地址 4. 项目git提交记录截图 5. 项目功能架 ...

  6. java 个人博客开发_Java实现个人博客系统

    导读:进入二十一世纪,以Internet为核心的现代网络积水和通信技术已经得到了飞速的发展和广泛的应用,各种网络交流互动工具也应运而生.其中以论坛.博客.社区.空间最为受广大网民朋友的欢迎,也是目前为 ...

  7. java课程设计 博客园_java课程设计

    Java程序设计 课程设计 3.本人负责的主要功能展示与代码分析 //这是一个文件夹类 public class Folder { private String name;//文件夹的名称 priva ...

  8. java 网络编程 博客园_java网络编程

    1.计算机网络基础 OSI参考模型(开放系统互连参考模型): 物理层:物理层处于OSI的最底层,是整个开放系统的基础.物理层涉及通信信道上传输的原始比特流(bits),它的功能主要是为数据端设备提供传 ...

  9. java接口自动化+博客园_java+接口自动化+eclipse之-----环境搭建

    根据金字塔的比重总结,UI测试占用10%,接口测试占有20%,单元测试占用70%.考虑到之前学过一段时间的单元测试.UI测试,而接口测试未曾接触过,所以最近打算看看接口测试是怎么实现的. 首先,我们先 ...

最新文章

  1. python中time模块获取时间的使用
  2. c#中 cmd.parameters.add() 方法的问题
  3. 【Java数据结构】自己实现一个HahMap(实现其put, toString, get方法)
  4. 爬虫爬出来的数据不全_斥巨资学完Python数据分析后,给运营人总结7个小建议...
  5. httpclient 3.0初步研究
  6. 运维架构师-并不遥远的彼岸
  7. android jersey 上传图片,图片上传--Jersey实现RESTful接口
  8. 201约花鸟画 考c语言试题,全国计算机二级C语言上机100题..doc
  9. 管理工作时间的软件有哪些?
  10. 什么是量子加密(二)
  11. ETL(数据抽取、转换、装载)
  12. netperf的安装、性能测试、参数、启动报错的坑、实例
  13. 网易校招流程是怎样的?有哪些常见的笔试面试题?
  14. ROS学习笔记之——MAC安装ubuntu虚拟机
  15. C++ printf打印二进制,三进制,八进制,十六进制等
  16. 程序猿生存指南-55 初为人师
  17. 如何去开发一个webApp
  18. 微信小程序之头部选项卡和左侧选项卡
  19. 大白话说期权——除了买涨买跌,我们还能怎么交易?二元期权又是什么鬼?
  20. 主机/虚拟机/开发板三者互通

热门文章

  1. Day11 - Ruby的block,proc,lamdba方法比较
  2. 技术实现之http请求封装
  3. 杨辉三角c语言程序jian,杨辉三角C语言程序队列实现(带源码+解析)
  4. 提供良好客户服务的5大原则
  5. 人工智能、机器人、编程啥关系?(科普)
  6. java中JAO,Java
  7. 人眼感知到的颜色与真实物理世界的颜色有什么区别?
  8. tcp/ip通讯 linux xpe,XPE最基本组件 分享
  9. mysql嵌套查询效率低,连接查询代替嵌套查询提高select效率
  10. 2017年蓝桥杯A组 跳蟋蟀 (BFS)