Java基础五 集合
-
特点:
-
Set 无序、不可重复
-
List 有序、重复
-
Queue 队列
-
Map 映射关系
关系:
-
HashSet -> Set
-
TreeSet -> NavigableSet -> SortedSet -> Set -> Collection -> Iterable
-
ArrayList -> List -> Collection -> Iterable
-
LinkedList -> list & Deque
-
LinkedList -> Deque & list
-
ArrayDeque -> Deque -> Queue -> Collection -> Iterable
-
HashMap -> Map
-
TreeMap -> NavigableMap -> SortedMap -> Map
携带三个问题去学习并找到对应答案:
-
1.怎么存数据?
-
2.是否有排序机制?
-
3.存储数据上限,是否有扩容机制?
1、HashSet – 是Set接口的典型实现
特点:不保证元素的排列顺序,非线程安全,集合内元素值可以为null,底层由HashMap实现,元素存在key上,而value则为空对象。
1、在hashset中定义了hashmap,使用transient修饰,不在value中初始化值,节省空间,transient - 不需要序列化的对象;
2、定义一个静态的常量的Object对象,用于比较;
3、初始化方法
4、add添加方法,静态常量对象判断是否有当前值,
5、remove移除方法
6、iterator迭代方法,使用map.keySet().Iterator()进行迭代;
7、写入、读取
2、TreeSet
特点:确保集合元素处于排序状态,支持自然排序和定制排序两种排序方式,底层由TreeMap实现,是非线程安全的,内部元素值不能为null;
1、定义了NavigableMap 可排序的map,同样使用transient修饰;
2、定义静态常量PRESENT;
3、构造方法使用new TreeMap实现;
4、添加、移除、排序等均相同;
3、ArrayList
基于数组实现的List,封装了动态的、允许再分配的Object[]数组,使用initialCapacity参数来设置数组长度,当元素超过该数组长度时,initialCapacity会自动增加实现自动扩容,若需缩容,则需要主动调用trimToSize()方法。
1、默认容量为10;每次扩容1.5倍;
2、定义两个空数组用于初始化时知道创建时是否选择容量;
3、add 先看是否扩容(底层计算容量,比较容量与传入的参数比较……),再追加数据;使用copyof方法将原数组拷贝到新容量数组中;
4、迭代规则,1、iterator自带的;2、自定义实现,添加listIterator,返回listIterator;可从前往后,从后往前迭代;
4、LinkedList
基于双向链表实现的List,内部元素可以为null、可以重复、是非线程安全的。
1、首节点、尾节点
2、linkLast末尾添加;linkeBefore头部添加;
3、使用node(index)进行获取和删除节点数,node使用前后两段进行查找。
实现list和Deque两个接口,可以当作双端队列使用,既可以当栈、也可以当队列。
1、offerFirst() - addFirst() - LinkFirst()、offerLast() - addLast() - LinkLast()
2、poll()/pollFirst() - unlinkFirst()、pollLast() - unlinkLast()
3、push() - addFirst() - linkFirst()、pop() - removeFirst() - unlinkFirst()
5、Queue
用于模拟队列,是一种先进先出的容器(FIFO)
1、add()将元素加入队列尾部;offer(),当有容量限制的队列使用更好;
2、remove()获取头部元素并删除、poll() ,队列为空返回null;
3、element()获取头部元素不删除、peek(),队列为空返回null;
6、Deque
双端队列,支持入栈出栈操作,在queue基础上,添加两类方法。
1、offerFirst()、offerLast() 头尾添加队列;
2、pollFirst()、pollLast()、头尾删除头部元素;
3、peekFirst()、peekLast() 头尾获取头部元素;
7、ArrayDeque
底层通过数组实现,是循环数组能够满住两端插入或删除元素,是非线程安全的,容器中不允许放入null;可扩容,但没有缩容的机制。
1、头尾指针、常量;head、tail。
2、最小/默认容量为8;
3、addFirst/addLast,head=(head-1)&(elements.length-1)
4、扩容,先拷贝头指针往右元素,再拷贝头指针左侧的元素;
5、pollFirst/pollLast,heat=(heat+1)&(elements.length-1)/tail=(tail-1)&(elements.length-1)
6、入栈:push() - addFirst();出栈pop() - removeFirst() - pollFirst()同一个方向出和入
8、Map
在JDK8中,HashMap底层采用“数组+链表+红黑树”实现。
重点:
数据结构
put过程
扩容机制
1、数据结构:table数组,数组值是Node单链表,数组规模达到一定程度时变为TreeNode,交叉继承了LinkedHashMap、HashMap、Node;
2、put过程:1、数组为空,初次扩容;2、若头节点为空,则新建链表节点;3、若头节点非空,则将元素插入槽;(元素等于头节点,直接覆盖;元素为树型节点,添加到树;元素为链表节点,链表长度小于8,添加至链表;元素为链表节点,链表长度超过8,则扩容或转为树,但是链表属性保留,再添加元素)4、元素的个数超过阈值,则再次扩容。
3、扩容机制,翻倍扩容左移一位。(若原为16,新为32。则数组内容位置为:原位、原位+16进行扩展)
4、状态参数,threshold记录容量,传入参数必须是2^n,
如果不行,就通过扩容的机制实现2^n、loadFactor负载因子,是否添加到表后或是新表中。
9、HashMap
1、查询机制:先定位,再从槽中迭代链表或树;
2、迭代机制:先遍历槽,再遍历槽中的链表或树,遍历出所有节点;
3、相关参数默认值:默认初始容量 16; 最大容量2^30;负载因子:0.75f;转为树的零界点8;转链表的零界点为6;支持树结构的最小容量:64;
10、TreeMap
底层为红黑树,插入时元素要进行比较,得到排序结果,有自然排序和定制排序两种;
属性:key、value、左右节点、父节点、颜色标识,默认为black;
11、Collections
解决并发:
1、同步集合
提供了多个synchronizedXxx()方法,set、list、queue迭代器没有加锁,需要用户自己加,map加了的;
2、不变集合(只读)
提供三类方法返回一个不可变集合,emptXxx();返回一个空的不可变集合对象;singletonXxx();返回一个只包含指定对象的不可变集合对象;unmodifiable()返回指定集合对象的不可变视图;
12、JUC下的集合,并发下的集合
1、CopyOnWriteArrayList
采用复制底层数组的方式来实现写操作;
读取时直接读取本身,无需加锁与阻塞;
修改时,需要复制一份新的数组,并对新的数组进行修改,执行过程需要加所,执行的是副本修改,是线程安全的;
2、ConcurrentHashMap
JDK7中,把一个hashMap拆分成多个子hashMap,每个子hashMap叫Segment,多线程操作多个Segment相互独立,分段锁。
好处:减少hash冲突,避免一个槽中原所过多;提高读写并发度,段与段之间相互独立;提高扩容的并发度,子模块单独可以进行扩容。
JDK8中,不分段,引入红黑树
好处:很好解决hash冲突,头节点分别加锁,并发粒度更细,但是扩容难度增加。
本文介绍了Java中的五种主要集合框架:HashSet、TreeSet、ArrayList、LinkedList和各种类型的队列/双端队列,以及它们的特点、排序机制和容量管理。同时涵盖了Map接口的实现如HashMap和TreeMap,以及并发编程工具Collections和JUC下的并发集合。

被折叠的 条评论
为什么被折叠?



