Java|第十二篇(Java集合详解、ArrayList、Vector、LinkedList、Queue、PriorityQueue、Deque、HashSet、TreeSet)

Java中的集合是我们编程中常用的东西,集合的作用是用来存放对象的,让我更好的管理对象!
Java集合分为三类:List、Queue、Set
1、List List是一个集合,按照元素插入的先后顺序进行排列。
Java|第十二篇(Java集合详解、ArrayList、Vector、LinkedList、Queue、PriorityQueue、Deque、HashSet、TreeSet)
文章图片

1.1、ArrayList
ArrayList的底层是数组,当空间不足的时候,会进行动态扩容。
数组的好处就是随机存储块,但是插入和删除效率不高,删除需要搬运元素,插入有的时候需要动态扩容。
ArrayList是线程不安全的,没有加锁,会出现线程不安全问题
ArrayList需要注意的就是遍历删除指定的元素,这点有点坑。

//错误代码 ArrayList list = new ArrayList(); list.add("jaychou"); list.add("jaychou"); list.add("jay"); for (int i = 0; i < list.size(); i++){ if(list.get(i).equals("jaychou")){ list.remove(i); } }

上面的代码其实是有问题的,因为当删除下标为0第一个"jaychou"的时候,后面的那个“jaychou”,会被移动到下标为0的位置,而下次循环的时候i变成了1,第二个"jaychou"就侥幸逃脱了。
如果通过list.remove(“jaychou”),跟上面的效果是一样的。
//正确代码 int i = 0; while(i < list.size()){ if(list.get(i).equals("jaychou")){ list.remove(i); }else{ i++; } }

上述代码才能正确的删除。
也可以通过Iterator来删除
Iterator it = list.iterator(); while (it.hasNext()){ if (it.next().equals("jaychou")){ it.remove(); } }

创建不变的ArrayList集合
List list = Arrays.asList("jaychou","jaychou");

通过Arrays.asList(),创建的list无法插入和删除元素,会报错!
这种创建的ArrayList的效率更高。
2、Vector
和ArrayList几乎一致,底层都是数组实现的,只不过Vector是线程安全的。
删除等方法都和ArrayList一致
3、LinkedList
LinkedList的底层结构是链表,特点就是删除和插入效率高,查询效率低。
LinkedList除了当线性表外,还可以当Queue,也就是队列。
LinkedList的底层是双向链表,类中实现了首尾节点,实现了双端队列。
add(E e):向队尾加入元素
poll():从队首弹出并返回元素
peek():获取队首元素
addFirst(E e):向队首中加入元素
removeFirst():从队首弹出并返回元素
peekFirst():获取队首元素
addLast(E e):向队尾加入元素
removeLast():从队尾弹出并返回元素
peekLast():获取队尾元素
LinkedList也是线程不安全的。
名称 底层实现 线程安全
ArrayList 数组
Vector 数组
LinkedList 双向链表
2、Queue Queue就是我们熟知的队列
Java|第十二篇(Java集合详解、ArrayList、Vector、LinkedList、Queue、PriorityQueue、Deque、HashSet、TreeSet)
文章图片

这里我们只说下常用的LinkedList和优先队列PriorityQueue和ArrayDeque
LinkedList上面我们已经说过了不在说了
ArrayDeque
ArrayDeque也是双端队列,和LinkedList一样,只不过LinkedList的底层是链表实现的,而ArrayDeque是依靠循环数组实现的。
当ArrayDeque满的时候,会进行双倍扩容。
其使用方法和LinkedList大致一样,就不再单独叙述了。
PriorityQueue
优先队列的底层结构是数组,是用数组模拟的满二叉树。
如下图所示,堆分为大顶堆和小顶堆。PriorityQueue的默认为小顶堆。
如果想要实现自定义排序,可以自定义Comparator对象,然后通过构造方法传入就可以了。
PriorityQueue pq = new PriorityQueue(myCmp);
Java|第十二篇(Java集合详解、ArrayList、Vector、LinkedList、Queue、PriorityQueue、Deque、HashSet、TreeSet)
文章图片

常用方法:
add(E e):向堆中加入元素
remove(E e):从堆中移除指定元素
poll():从堆顶弹出并返回元素
peek():获取堆顶元素
3、Set set也是一个集合,只不过不允许存在重复的元素
Java|第十二篇(Java集合详解、ArrayList、Vector、LinkedList、Queue、PriorityQueue、Deque、HashSet、TreeSet)
文章图片

本篇文章,我们主要介绍HashSet、LinkedHashSet和TreeSet。
1、HashSet
从名字就可以看出来,HashSet的底层是涉及到Hash表的。源码中HashSet中是依靠HashMap实现的。
HashMap的实现你们可以参考上一篇文章:第十一篇:Java中Map详解 HashMap、LinkedHashMap、TreeMap、HashMap扩容原理详解

HashSet set = new HashSet<>(); set.add(1);

HashSet中内部定义了一个PRESENT常量;
private final Object PRESENT = new Object();
比如set.add(1),是将1作为key,PRESENT作为value,插入map中。
通过HashMap,HashSet能够做到元素不重复。
主要方法:
add(E e):加入元素e
remove(E e):移除元素e
contains(E e):判断是否存在元素e
遍历方式:
1、Iterator
Iterator it = set.iterator(); while (it.hasNext()){ System.out.println(it.next()); }

2、for循环
for (String s:set){ System.out.println(s); }

通过for循环我们可以看出来,HashSet中是没有下标的概念的,无法通过下标来获得数据。HashSet中的元素不是按照元素的插入顺序排列的,而是按照一定的Hash算法来排列的。
2、LinkedHashSet
通过Linked关键词,就大概知道LinkedHashSet和HashSet的大概区别了。
HashSet中的元素遍历输出不是按照元素的插入顺序排列的,而LinkedHashSet是按照元素插入元素排列的。
LinkedHashSet是通过LinkedHashMap来实现的。
LinkedHashMap的实现你们可以参考上一篇文章:第十一篇:Java中Map详解 HashMap、LinkedHashMap、TreeMap、HashMap扩容原理详解

【Java|第十二篇(Java集合详解、ArrayList、Vector、LinkedList、Queue、PriorityQueue、Deque、HashSet、TreeSet)】其使用方法和HashSet基本一致。
3、TreeSet
TreeSet是依照TreeMap的原理实现的
TreeMap的实现你们可以参考上一篇文章:第十一篇:Java中Map详解 HashMap、LinkedHashMap、TreeMap、HashMap扩容原理详解

TreeSet和HashSet、LinkedHashSet的区别就是TreeSet中的元素是有序的。
当用户初始化TreeSet的时候,可以传入自定义的Comparator。
如果是自定义对象的TreeSet的话,自定义对象需要实现Comparable接口,要不再put元素的时候会报错。

    推荐阅读