集合
概念:
集合可以看作是一种容器,用来存储对象信息
和数组的关系:
1、数组长度固定,集合长度不固定;
2、数组可以存储基本数据类型和引用数据类型。集合只能存储引用数据类型。
Collection和map
Java的集合类主要由两个根接口派生出来,分别是Collection 和 Map。
Java中的集合类可以分为两大类:一类是实现Collection接口;另一类是实现Map接口
Collection是一个基本的集合接口,Collection中可以容纳一组集合元素(Element)。
Map没有继承Collection接口,与Collection是并列关系。Map提供键(key)到值(value)的映射。一个Map中不能包含相同的键,每个键只能映射一个值。
Collection 里还定义了很多方法,主要是用于数据的[增删改查],也叫 CRUD
add()、clear()
List:
List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。。
ArrayList、LinkedList、Vactor
List下的arraylist和linkedlist的区别
ArrayList是Array(动态数组)的数据结构,LinkedList是Link(链表)的数据结构。
ArrayList:查询快,增删慢。
LinkedList:查询慢,增删快。
ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;
LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。
LinkedList是基于双向循环链表实现的,除了可以当做链表来操作外,它还可以当做栈、队列和双端队列来使用。
LinkedList同样是非线程安全的,只在单线程下适合使用。
LinkedList实现了Serializable(sei瑞来自包)接口,因此它支持序列化,能够通过序列化传输,实现了Cloneable(可漏A包)接口,能被克隆
什么是链表
链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链表又分为单向链表和双向链表,而单向/双向链表又可以分为循环链表和非循环链表
单向链表
单向链表就是通过每个结点的指针指向下一个结点从而链接起来的结构,最后一个节点的next指向null。
单向循环链表
单向循环链表和单向列表的不同是,最后一个节点的next不是指向null,而是指向head节点,形成一个“环”
双向链表(pre-指向前一个结点的指针)
从名字就可以看出,双向链表是包含两个指针的,pre指向前一个节点,next指向后一个节点
双向循环链表
双向循环链表和双向链表的不同在于,第一个节点的pre指向最后一个节点,最后一个节点的next指向第一个节点,也形成一个“环”。LinkedList就是基于双向循环链表设计的
Set
Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中
hashSet、treeSet
HashSet:
采用 HashMap 的 key 来储存元素,主要特点是无序的
存储结构:哈希表(数组+链表+红黑树)
存储过程
1.根据hashCode计算保存的位置,如果位置为空,直接保存,若不为空,进行第二步
2.再执行equals方法,如果equals为true,则认为是重复,否则形成链表
LinkedHashSet:
这个是一个 HashSet + LinkedList 的结构
TreeSet:
采用红黑树结构,特点是可以有序,可以用自然排序或者自定义比较器来排序;缺点就是查询速度没有 HashSet 快。
那每个 Set 的底层实现其实就是对应的 Map
Map
map接口的特点:
1、用于存储任意的键值对(Key—Value)
2、键:无序,无下标,不允许重复(唯一)
3、值:无序,无下标,允许重复。
HashMap【重点】
存储结构:哈希表(数组+链表+红黑树)
使用key可使hashcode和equals作为重复
1、HashMap刚创建时,table是null,节省空间,当添加第一个元素时,table容量调整为 16
2、当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目 的是减少调整元素的个数
3、jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高 效率
4、jdk1.8 当链表长度 <6 时 调整成链表
Hash Map的put()和get()的实现原理:
1、map.put(k,v)实现原理
(1)首先将k,v封装到Node对象当中(节点)。
(2)然后它的底层会调用K的hashCode()方法得出hash值。
(3)通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
2、map.get(k)实现原理
(1)先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
(2)通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。