今天要说的是Collection族长下的三名大将之一,List,Set,Queue中的List,它们都继承自Collection接口,所以Collection接口的所有操作,它们自然也是有的。

  List,Set,Queue,分别是列表,集合,队列的意思,代表着Collection家族下的三种不同的势力,它们各有所长,也各有所短,就像骑兵,步兵和水兵,各有各的优势,并没有谁一定比谁更好的说法,合适的才是最好的。接下来,将会分别介绍这三名大将,从中你也会看到它们各自的特点。

  本篇先来介绍一下List接口。

  我们先来看看List的源码:

public interface List<E> extends Collection<E> {
// 查询接口 /**
* 列表元素个数
*/
int size(); /**
* 是否为空
*/
boolean isEmpty(); /**
* 是否包含某元素
*/
boolean contains(Object o); /**
* 返回一个List迭代器
*/
Iterator<E> iterator(); /**
* 将List转换为Object数组
*/
Object[] toArray(); /**
* 转换为指定类型数组
*/
<T> T[] toArray(T[] a); // 修改操作 /**
* 添加元素,成功返回true
*/
boolean add(E e); /**
* 移除某一个元素,成功返回true
*/
boolean remove(Object o); // 批量操作 /**
* 判断是否包含集合C 中的所有元素
*/
boolean containsAll(Collection<?> c); /**
* 将集合C 中所有元素添加到列表
*/
boolean addAll(Collection<? extends E> c); /**
* 将集合C 中所有元素添加到列表,添加在序号为index的元素之后
*/
boolean addAll(int index, Collection<? extends E> c); /**
* 从列表中移除集合C 中所有元素
*/
boolean removeAll(Collection<?> c); /**
* 从列表中移除所有不在集合C 中的元素
*/
boolean retainAll(Collection<?> c); /**
* 全部替换
*/
default void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ListIterator<E> li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
} /**
* 根据指定的比较器来排序,如果传入的比较器是null,则元素必须实现Comparable 接口
*/
@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
} /**
* 移除所有元素
*/
void clear(); // 比较和hash boolean equals(Object o); int hashCode(); // 根据序号进行的操作 /**
* 获取指定序号的元素
*/
E get(int index); /**
* 替换指定序号的元素
*/
E set(int index, E element); /**
* 在指定序号的元素后插入元素
*/
void add(int index, E element); /**
* 移除指定序号的元素
*/
E remove(int index); // 搜索操作 /**
* 返回元素第一次出现的位置,如果未找到则返回-1
*/
int indexOf(Object o); /**
* 返回元素出现的最后一个位置
*/
int lastIndexOf(Object o); // List迭代器 /**
* 返回一个List迭代器
*/
ListIterator<E> listIterator(); /**
* 返回一个序号从Index开始的List迭代器
*/
ListIterator<E> listIterator(int index); // 视图 /**
* 返回一个子队列,序列从fromIndex到toIndex,包含fromIndex,不包含toIndex
* 对子队列的修改会影响原队列
* 如果原队列修改,那么对子队列的影响是未定义的
*/
java.util.List<E> subList(int fromIndex, int toIndex); /**
* 创建一个可分割的迭代器(用于并行计算)
*/
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.ORDERED);
}
}

  其实JDK里的注释已经十分丰富,大家平时有时间可以多看看,为了方便阅读,我这里用简单粗暴的语言进行了精简翻译。

  List即列表,存储的是有序集合,里面的元素有序存储,可以重复,所谓有序集合,顾名思义,就是里面的元素存放是有顺序的,每个插入的元素都对应着一个序号,可以根据序号获取元素。

  List支持的操作也很丰富,最常用的增删改查,批量添加,批量替换,批量删除,还有搜索,排序操作,还支持普通迭代器和可分割式迭代器,前者主要用于遍历,后者则主要用于并行式计算,关于迭代器的知识后面会统一介绍。下面是使用常见操作的一个小栗子:

public class Test {

    public static void main(String[] args){
test();
} static void test(){
List<Integer> integers = new ArrayList<>();
List<Integer> integersA = new ArrayList<>(); //添加元素
integers.add(1);
integers.add(2);
integers.add(3);
integers.add(4); integersA.add(1);
integersA.add(2);
integersA.add(33);
integersA.add(44);
System.out.println("列表大小:" + integers.size());
System.out.println("是否为空:" + integers.isEmpty());
System.out.println("是否包含某元素:" + integers.contains(2));
System.out.println("是否包含全部元素:" + integers.containsAll(integersA)); //转换为数组
Integer[] integerArray = integers.toArray(new Integer[0]);
System.out.println("遍历数组:");
for (int i = 0; i < integerArray.length; i++){
System.out.println(integerArray[i]);
}
System.out.println("当前列表integers:" + integers); //批量添加
System.out.println("批量添加元素");
integers.addAll(integersA);
System.out.println("当前列表integers:" + integers); //移除元素
System.out.println("移除元素");
integers.remove(1);
System.out.println("当前列表integers:" + integers); //批量移除
System.out.println("批量移除元素");
integers.removeAll(integersA);
System.out.println("当前列表integers:" + integers); //开始替换
System.out.println("批量替换元素");
integers.replaceAll(it -> it + 1);
System.out.println("当前列表integers:" + integers); //从列表中移除所有不在集合integersA中的元素
integersA.add(2);
integersA.add(4);
System.out.println("保留元素");
integers.retainAll(integersA);
System.out.println("当前列表integers:" + integers); //插入
System.out.println("开始插入");
System.out.println("当前列表integersA:" + integersA);
integersA.add(2,155);
integersA.add(1,125);
System.out.println("当前列表integersA:" + integersA); //排序
System.out.println("开始排序——使用内部比较器");
integersA.sort(null);
System.out.println("当前列表integersA:" + integersA); System.out.println("开始排序——使用外部比较器");
integersA.sort((itA, itB) -> itB - itA);
System.out.println("当前列表integersA:" + integersA); //序号操作
Integer a = integersA.get(2);
System.out.println("integersA第三个元素是:" + a);
System.out.println("开始替换");
integersA.set(3, 66);
System.out.println("当前列表integersA:" + integersA);
System.out.println("开始移除");
integersA.remove(3);
System.out.println("当前列表integersA:" + integersA); //搜索操作
System.out.println("查找元素2(第一次出现)位置:" + integersA.indexOf(2));
System.out.println("查找元素2(最后一次出现)位置:" + integersA.lastIndexOf(2)); //子队列操作
List<Integer> subList = integersA.subList(0, 4);
System.out.println("子队列:" + subList);
subList.add(5);
subList.add(5);
subList.add(5);
System.out.println("当前子列表:" + subList);
System.out.println("当前列表integersA:" + integersA); integersA.add(1, 233);
integersA.add(1, 233);
integersA.add(1, 233);
System.out.println("当前列表integersA:" + integersA);
System.out.println("当前子列表:" + subList);
}
}

  大家可以先想想结果,再下看面的答案。

  实际输出如下:

列表大小:4
是否为空:false
是否包含某元素:true
是否包含全部元素:false
遍历数组:
1
2
3
4
当前列表integers:[1, 2, 3, 4]
批量添加元素
当前列表integers:[1, 2, 3, 4, 1, 2, 33, 44]
移除元素
当前列表integers:[1, 3, 4, 1, 2, 33, 44]
批量移除元素
当前列表integers:[3, 4]
批量替换元素
当前列表integers:[4, 5]
保留元素
当前列表integers:[4]
开始插入
当前列表integersA:[1, 2, 33, 44, 2, 4]
当前列表integersA:[1, 125, 2, 155, 33, 44, 2, 4]
开始排序——使用内部比较器
当前列表integersA:[1, 2, 2, 4, 33, 44, 125, 155]
开始排序——使用外部比较器
当前列表integersA:[155, 125, 44, 33, 4, 2, 2, 1]
integersA第三个元素是:44
开始替换
当前列表integersA:[155, 125, 44, 66, 4, 2, 2, 1]
开始移除
当前列表integersA:[155, 125, 44, 4, 2, 2, 1]
查找元素33(第一次出现)位置:4
查找元素33(最后一次出现)位置:5
子队列:[155, 125, 44, 4]
当前子列表:[155, 125, 44, 4, 5, 5, 5]
当前列表integersA:[155, 125, 44, 4, 5, 5, 5, 2, 2, 1]
当前列表integersA:[155, 233, 233, 233, 125, 44, 4, 5, 5, 5, 2, 2, 1]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1239)
at java.util.ArrayList$SubList.listIterator(ArrayList.java:1099)
at java.util.AbstractList.listIterator(AbstractList.java:299)
at java.util.ArrayList$SubList.iterator(ArrayList.java:1095)
at java.util.AbstractCollection.toString(AbstractCollection.java:454)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at com.frank.chapter20.Test.test(Test.java:115)
at com.frank.chapter20.Test.main(Test.java:15)

  不知道符不符合你的预期,这里关于内部比较器和外部比较器的知识只一笔带过,Integer类型是实现了Comparable接口的,所以sort方法传入null时会使用Integer的内部比较器进行排序,而使用外部比较器时,使用的是Java8的新特性,lamada表达式,省去了方法名和参数类型,因为函数式接口不存在重载方法,所以编译器可以推断出参数类型,这样就不用再大费周章的用new语法去创建一个比较器(当然,只是语法糖而已,如果不是很理解比较器,可以先行百度,后面的文章里也会有详细介绍)。在最后报出了一个ConcurrentModificationException,因为原队列修改后,子队列视图就被破坏了,所以再次访问子视图时就会报错。

  List是最常用的容器类,List最大的特点便是要求元素有序存储,List跟数组相比,最大的优势在于List大小可以动态扩展,但数组支持随机存取,所以当元素个数的固定的时候,使用数组往往效率更高。(当然,一般情况下还是使用List吧,因为支持的操作更加丰富,比如进行排序时不需要自己写算法)。

  一般来说,对元素没有特殊要求,不需要去重存储,没有先进先出的要求的场景下,List是最好的选择。

  List接口下有多个常用的实现类,每个类都有其特点,具体选择哪种类需要根据实际情况进行选择。

  希望大家能通过这篇文章,了解List的主要方法及其使用方法以及常用场景,关于List的常见具体实现类的讲解将在之后的文章里进行说明和比较。

  本篇到此结束,欢迎大家继续关注。

【Java入门提高篇】Day20 Java容器类详解(三)List接口的更多相关文章

  1. 【Java入门提高篇】Java集合类详解(一)

    今天来看看Java里的一个大家伙,那就是集合. 集合嘛,就跟它的名字那样,是一群人多势众的家伙,如果你学过高数,没错,就跟里面说的集合是一个概念,就是一堆对象的集合体.集合就是用来存放和管理其他类对象 ...

  2. 【Java入门提高篇】Day34 Java容器类详解(十五)WeakHashMap详解

    源码详解系列均基于JDK8进行解析 说明 在Java容器详解系列文章的最后,介绍一个相对特殊的成员:WeakHashMap,从名字可以看出它是一个 Map.它的使用上跟HashMap并没有什么区别,所 ...

  3. 【Java入门提高篇】Day28 Java容器类详解(十)LinkedHashMap详解

    今天来介绍一下容器类中的另一个哈希表———>LinkedHashMap.这是HashMap的关门弟子,直接继承了HashMap的衣钵,所以拥有HashMap的全部特性,并青出于蓝而胜于蓝,有着一 ...

  4. 【Java入门提高篇】Day26 Java容器类详解(八)HashSet源码分析

    前面花了好几篇的篇幅把HashMap里里外外说了个遍,大家可能对于源码分析篇已经讳莫如深了.别慌别慌,这一篇来说说集合框架里最偷懒的一个家伙——HashSet,为什么说它是最偷懒的呢,先留个悬念,看完 ...

  5. 【Java入门提高篇】Day21 Java容器类详解(四)ArrayList源码分析

    今天要介绍的是List接口中最常用的实现类——ArrayList,本篇的源码分析基于JDK8,如果有不一致的地方,可先切换到JDK8后再进行操作. 本篇的内容主要包括这几块: 1.源码结构介绍 2.源 ...

  6. 【Java入门提高篇】Day31 Java容器类详解(十三)TreeSet详解

    上一篇很水的介绍完了TreeMap,这一篇来看看更水的TreeSet. 本文将从以下几个角度进行展开: 1.TreeSet简介和使用栗子 2.TreeSet源码分析 本篇大约需食用10分钟,各位看官请 ...

  7. 【Java入门提高篇】Day27 Java容器类详解(九)LinkedList详解

    这次介绍一下List接口的另一个践行者——LinkedList,这是一位集诸多技能于一身的List接口践行者,可谓十八般武艺,样样精通,栈.队列.双端队列.链表.双向链表都可以用它来模拟,话不多说,赶 ...

  8. 【Java入门提高篇】Day19 Java容器类详解(二)Map接口

    上一篇里介绍了容器家族里的大族长——Collection接口,今天来看看容器家族里的二族长——Map接口. Map也是容器家族的一个大分支,但里面的元素都是以键值对(key-value)的形式存放的, ...

  9. 【Java入门提高篇】Day30 Java容器类详解(十二)TreeMap详解

    今天来看看Map家族的另一名大将——TreeMap.前面已经介绍过Map家族的两名大将,分别是HashMap,LinkedHashMap.HashMap可以高效查找和存储元素,LinkedHashMa ...

随机推荐

  1. 开机自启动Nginx的脚本

    1.1 编写shell脚本 这里使用的是编写shell脚本的方式来处理 vi /etc/init.d/nginx  (输入下面的代码) #!/bin/bash # nginx Startup scri ...

  2. 线程中的读写锁ReadWriteLock

    Lock锁还有两个非常强大的类 ReadWriteLock接口实现类ReentrantReadWriteLock(非常重要的锁) 想实现 读取的时候允许多线程并发访问,写入的时候不允许. 这种效果.. ...

  3. webgl之3d动画

    之前的几篇文章都是静态的,而这里主要介绍如何使物体动起来,并且学会使用性能监视器来监测性能. 而如果要让物体动起来,实际上我们是有两种方法的,第一种是让物体真的动起来,另外一种是让摄像机动起来这样物体 ...

  4. python垃圾回收

    python垃圾回收 python垃圾回收主要使用引用计数来跟踪和回收垃圾.在引用计数的基础上,通过“标记—清除”解决容器对象可能产生的循环引用问题,通过“分代回收”以空间换时间的方法提高垃圾回收效率 ...

  5. charles撰写工具/compose和Compose New

    撰写工具/compose和Compose New compose 是在原有的请求基础上,修改: compose New 是新出一个弹窗,自己手动一个个的去写: 可以写各种状态:– URL:– Meth ...

  6. JavaScript -- Window-Blur

    -----030-Window-Blur.html----- <!DOCTYPE html> <html> <head> <meta http-equiv=& ...

  7. 【Java初探03】——流程控制语句

    做任何事情都应当遵守一定的原则,程序设计也是如此,需要有流程控制语言来实现与用户的交流.流程控制对于任何一门编程语言来说都是至关重要的,它提供了控制程序步骤的基本手段,如果没有流程控制语句,整个程序将 ...

  8. mysql5.7主从复制配置——读写分离实现

    为什么使用主从架构?1.实现服务器负载均衡:2.通过复制实现数据的异地备份:3.提高数据库系统的可用性:4.可以分库[垂直拆分],分表[水平拆分]: 主从配置的前提条件1.MySQL版本一致:2.My ...

  9. 26-hadoop-hbase简介

    hadoop的生态系统 1, hbase简介 –HBase–HadoopDatabase,是一个高可靠性.高性能.面向列.可伸缩.实时读写的分布式数据库 –利用HadoopHDFS作为其文件存储系统, ...

  10. centos7.0安装docker-18.06.1-ce不能启动问题

    最近用centos7.0 yum安装了一个docker-ce18.06.1  但是发现安装好不能启动,于是上官网看了一下,说是docker-ce18.06.1是从centos7.2开始支持的,但是7. ...