集合
什么是集合
集合是用来存储对象的容器,定义了对多个对象进行操作的常用方法,实现了数组的功能,位于java.util.*下
集合和数组的区别
- 数组长度不可变,集合长度可变
- 数组可以存放基本数据类型和引用类型,集合只能存放引用类型
介绍一下Java中的集合体系
jave中的集合主要分为两大类,一类为Collection,一类为map;Collection又主要分为List和Set,其中List为保证插入顺序,且可以存放重复值的集合,他的代表是ArrayList;而Set是不保证顺序,且不能有重复值的集合,他的代表是HashSet;Map是Key - Value方式存储值的一种集合,他的代表是HashMap;
Collection集合接口
Collection接口常用的方法
- add添加一个对象
- addAll将一个集合中的所有对象添加到此集合
- clear清空此集合所有对象
- contains检查此集合中是否包含某个对象
- isEmpty判断此集合是否为空
- remove移除某个元素
- size返回集合元素个数
- toArray将此集合转换为数组
- equals比较此集合是否与指定对象相等
- reverse反转集合中的元素
- sort升序排序
- shuffle随机重置元素顺序
- binarySearch 查找集合中的元素是否存在,位置下标
- copy 复制集合到新集合
这里需要注意的是需要先给新集合所有元素添加为0 - toArray 集合转化为数组
- Arrays.asList 数组转化为集合
转化的集合为受限集合,不能添加删除
基本数据类型数组转化为集合需要先变为包装类
集合遍历方式
增强for循环
iterator迭代器
注意: 在使用迭代器时不能使用Collection接口的方法
- hasNext(): 有没有下一个元素
- next(): 获取下一个元素
- remove(): 移除元素当前
一、list接口
有序,有下标,可以重复
list中的方法:
- add: 指定在某个位置插入对象
- addAll: 指定在某个位置插入一个集合
- get: 获取指定位置的元素
- subList: 获取某一段index之间的元素(注意含头不含尾)
- indexOf: 返回指定元素第一次出现的索引
- listIterator: 列表迭代器,比Collection的迭代器功能更强大
遍历方式:
- for
- foreach
- iterator
- listIterator: 通过hasPrevious()可以逆序遍历,也可以在迭代的时候增删改
注意: 删除数字的时候,会误以为删除下标为数字的元素,需要对数字进行强转包装类
1.1ArrayList
底层基于数组,所以查询快,增删慢(增删慢是因为要维护下标),线程不安全
底层分析:
默认容量是10(当我们调用无参构造创建了ArrayList,并且没有添加元素的时候长度是0,添加了元素就会扩容为10)
就是一个elementData数组
每次扩容1.5倍(位运算右移了一位)
1.2Vector
底层基于数组,查询快,增删慢,线程安全(使用了Synchronized修饰方法)
1.3LinkedList
底层基于双向链表,查询慢(需要遍历所有),增删快
底层分析:
通过first.last.newNode节点实现
二、set接口
无序,无下标,不可以重复
2.1HashSet
底层结构: 哈希表(数组+链表+红黑树),就是HashMap
存储原理: 先根据HashCode计算出存储在数组中得位置,然后根据equals判断是否重复,如果重复拒绝存储,如果不重复存储到链表中,当链表元素等于8时转为为红黑树,当小于6时转化为链表
基于HashMap
2.2TreeSet
底层结构: 红黑树
存储原理: 因为是数型结构,所以必须要指定排序规则
实现Comparable接口
指定Comparator定制比较器基于TreeMap
三、Map接口
用于存储任意键值对
key: 无序,无下标,不可重复(注意: 当key相同时会覆盖前一个Value)
value: 无序,无下标,可以重复
Map接口常用方法:
- put
- get
- keySet() 返回一个Set集合,含有所有的key
- Collection values()
- set<Map.entry<K,V>>
Map接口的遍历
keySet方法
通过keySet方法拿到所有key的一个set集合
使用foreach遍历set集合,通过map.get(Key)拿到所有的value
entrySet方法
通过entrySet方法拿到entries的Set集合(entry就是一个key-value映射)
使用foreach遍历Set集合,通过map.getKey拿到Key,通过map.getValue拿到Value
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2VyY1J7h-1615477629001)(1615464855818.png)]
3.1HashMap
基本概念
存储结构: 哈希表(数组+链表+红黑树)
线程不安全,允许null作为Key或Value
默认初始容量: 16
默认加载因子: 0.75
判断重复的标准是HashCode和Equals,所以我们在使用自定义类型的的时候需要重写
源码分析:
HashMap刚创建的时候table是null,当添加第一个元素之后扩容为16
当元素个数大于阈值(16*0.75=12)时,进行2倍扩容
java1.8之后当链表长度大于等于8并且元素个数大于等于64的时候,链表才会转化为红黑树,当小于等于6时又转化为链表
java1.8之后采用尾插,为什么要使用尾插,因为保证安全,头插会使链表顺序翻转,造成死循环
3.2HashTable
线程安全的,不允许为null
初始容量: 11
Properties
HashTable的子类,要求Key,Value都是String,通常用于配置文件的读取
3.3TreeMap
实现了SortedMap,可以对Key排序
注意: 使用的时候需要指定排序规则(Comparable或Comparator )
如果需要从一个List集合中频繁的删除和添加元素,是选择ArrayList还是LinkedList?为什么?
频繁添加和删除选择使用LinkedList;
-
ArrayList的底层是数组,数组具有索引,所以他可以快速定位元素,查询效率较快。但是数组在内存中是一段连续的内存空间,删除和添加会涉及到内存空间的移位和扩容操作,所以添加和删除的效率低下;
-
而LinkedList的底层使用的是双向链表的结构;这种结构不要求在内存空间中连续,只需要前后指定上下个节点的引用位置即可;查询时需要遍历整个集合,所以效率较慢,但添加和删除只需要改变引用即可,所以添加和删除效率较快;
什么是Hash冲突(碰撞)
Hash冲突是指的是,两个不同的值根据Hash算法得到的Hash值一样,这种情况叫做Hash冲突;我们一般选择使用拖链表、再Hash、开发寻址、或者创建冲突区来解决Hash冲突;
HashMap为什么要使用链表,又为什么要使用红黑树
HashMa是使用的Hash来计算元素存储的位置的,但因为Hash冲突的缘故,所以需要使用到链表结构来解决Hash冲突的元素存储问题;
使用红黑树是为了解决,当某些节点Hash冲突过多,链表拖的过长,导致查找效率较慢的情况,使用红黑树可以有效提升查询效率。
HashMap是否是线程安全的,如果不是,那么在多线程环境中我们应该使用哪个集合?
HashMap的线程是不安全的,HashTable是线程安全的HashMap,但因为他低下的效率已经过时不用了。在当前开发环境下,如多线程环境我们推荐使用ConcurrentHashMap。