目录
Collection接口那些方法:(即List与Set实现的接口)
一.Collection接口与uilt包
有关java.util包:
集合有两大父接口:
1) Collection接口: 存储一个一个元素
两大子接口:
1. List: 特征: 元素可重复,有序(拿出元素的顺序与添加顺序一致)
常用实现类: ArrayList,LinkedList
2.Set: 特征: 元素唯一,无序
常用实现类: HashSet, TreeSet
Collection接口那些方法:(即List与Set实现的接口)
1、 int size(); 返回此collection中的元素数。
2、 boolean isEmpty(); 判断此collection中是否包含元素。
3、 boolean contains(Object obj); 判断此collection是否包含指定的元素。
4、 boolean contains(Collection c); 判断此collection是否包含指定collection中的所有元素。
5、 boolean add(Object element); 向此collection中添加元素。
6、 boolean addAll(Collection c);将指定collection中的所有元素添加到此collection中
7、 boolean remove(Object element); 从此collection中移除指定的元素。
8、 boolean removeAll(Collection c); 移除此collection中那些也包含在指定collection中的所有元素。
9、 void clear(); 移除些collection中所有的元素。
10、boolean retainAll(Collectionc); 仅保留此collection中那些也包含在指定collection的元素。
11、Iterator iterator(); 返回在此collection的元素上进行迭代的迭代器。
12、Object[]toArray();把此collection转成数组。
List集合 java.util.List
List 特征: 可重复,有序(有下标 )
特有的方法:
add(int index, 元素) 在指定下标位置插入元素
Object get(int index) 获取指定位置的元素
int indexOf(元素) 找到这个元素第一次出现的位置
int lastIndexOf(元素) 找到这个元素最后一次出现的位置
remove(int index ) 删除指定位置上的元素
set(int index, 新的元素) 修改指定位置上的元素
List<E> subList(int fromIndex, int toIndex) 截取指定位置上元素, 不包括结束位置
常用的实现类: ArrayList, LinkedList
ArrayList
底层使用数组实现, 数据结构与数组一样
构造方法:
注意:
集合: 存放的元素都是对象, 如果是基本数据类型, 自动的装箱,变成包装类对象
private static final Object[] ArrayList 底层是Object[] 数组
2) Map接口: 存储的一对一对的key-value键值对
常用实现类: HashMap,TreeMap
Arrays: 数组的帮助类Collections: Collection集合的帮助类 这个两个类的方法都是static的
二.ArrayList与LinkedList
底层使用数组,
自动扩容:
elementData[] = new int[10];
添加了10个元素, 添加11个, 新创建一个数组: 长度 = 旧数组长度 * 1.5 = 10*1.5 = 15, 再把旧数组中的元素拷贝到新数组, elementData 指向新数组
ArraylIst: 特征: 查找元素效率高, 插入,删除元素效率低
添加元素: 判断数组时候是否需要扩容 elementData的长度 < 最小容量(原来元素个数 + 1) 调用: grow(最小容量) 自动扩容
ArrayList 对elementData数组进行new操作, 初始化, 不是在new ArrayList() , 而是在第一次调用add() 方法
elementData[]={}
第一次添加元素: 初始化elementData = new Object[10];
这个集合已经有元素: 新数组长度 = 旧的数组长度 *1.5 进行数组的拷贝, Arrays.copyof() 往elementData添加新元素 elementData[size++] = 新元素;
LinkedList
LinkedList: 底层存储元素: 使用双向链表: 不连续的空间, 由n个节点组成, 节点就是一个对象: Node
LinkedList: 特征: 查询效率低, 插入,删除效率高
三.TreeSet(排序 )
Set: HashSet, 作用: 去重
判断元素是否存在, 调用 hashCode() --> equlas()
HaseSet: 底层是哈希表, HashMap, 数组加链表
TreeSet: 底层使用红黑树, 左 < 根 < 右 有序的
算法,数据结构可视化网站: 二叉搜索树,AVL树 - VisuAlgo
红黑树的研究, 到达平衡: 变色,左旋,右旋
TreeSet: 可排序
创建TreeSet
TreeSet排序原理
1) 要求元素的类实现比较器: Comparable
compareTo方法的实现规则:
返回 0,表示 this == obj。//则不会添加新对象
返回正数,表示 this> obj //添加到原来对象的右边
返回负数,表示 this < obj // 添加到原来对的左边
使用Comparable 这种方式: 排序方式 已经写死, 动态比较无法实现: 有时需要安装年龄, 有时需要是学号,... 扩展性不好
2) 获取指定Comparator比较器 创建TreeSet时, 才指定排序方式, new TreeSet(Comparator对象), 比Comparable 扩展性好
返回 0,表示 this == obj。//则不会添加新对象
返回正数,表示 this> obj //添加到原来对象的右边
返回负数,表示 this < obj // 添加到原来对的左边
如果元素的类没有实现Comparable接口, 或者new TreeSet 指定Comparator, 往TreeSet添加元素,抛异常:
四.HashMap
Map存储的元素: 一对元素(key-value) kv键值对
Map 位于java.util包下, 接口, 常用子类: HashMap
(线程不安全), HashTable(线程安全),Properties(后期使用, 配置文件)
集合只能存储对象, 1 -->Integer
Map的特征
特征: key: 唯一, value可以重复
添加元素: 新元素的key在Map集合中存在, map替换value , 如果key不存在, 添加
1.1 通过键-值(key-value)对的形式来存储数据
1.2 Map的实现:HashMap(使用频率最高的),TreeMap,HashTable
1.3 Map中,key可以为任意类型,但这里建议使用String,value也可以是任意类型
1.4 Map里面多个value可以是不同类型, 向上转型: Object
1.5 Map里面key是可以重复的,当key重复时,后存入的数据会覆盖前面的数据
1.6 Map里面,value可以重复.
1.7 Map里面的key可以为null,但是只能有一个,多个的时候,后面的会覆盖前面的
1.8 Map中value可以是null,多个value可以同时为null。
1.9 Map中的key在底层可以理解为是一个Set
HashMap 常用的类
作用: 存储的key-value对
创建:
构造方法:
常用方法: 增删改查
put(key,value) 实现添加元素与修改元素
即:修改value新元素的key在Map集合中存在, map替换value , 如果key不存在, 添加
value remove(key) 根据key删除key-value 对
clear() 清空map
value get(key) 根据key获取value
HashMap的原理 面试常面
存储数据结构: 哈希表--> hash算法
public int hash(long obj){ // 有限范围的整数 快速的存储是否包含这个数字 }
HashMap底层存储数据的结构: 数组 + 链表: 在jdk1.7之前, 在JDK1.8 数组 + 链表 /红黑树
LinkedList: 查询效率低
在JDK1.8如果当某一列的链表长度很长, 为了提高查询效率, 把链表转换为红黑树
(具体的长度为8)
链表查询时间复杂度: O(n) 红黑树时间复杂度: O(n) = log2N
HashMap的put()方法添加元素的原理:
对key进行hash算法,得到hash值
调用putVal() , 判断是否是第一次添加,如果是第一次添加, 调用resize() 对数组进行初始化
根据hash值找到元素存在table数组的那个位置(下标), 判断该位置是否为null,
3.1 如果为null, 直接创建一个Node对象, 添加到数组该位置
3.2 如果不为null: 但是该位置第一个节点的key与新添加的key一样, 直接覆盖value
3.3 如果key 不一样: 循环遍历该链表, 如果某个节点的key一样, 覆盖该节点的value
3.4 如果链表中所有的key与添加的key 都不一样, 创建一个新的Node, 添加到链表的末尾: 尾插入, jdk1.7 头插入
如果链表的长度 = 8, 并且 map的容量 > 64 , 变红黑树, 如果map容量 <= 64 , 扩容
如果map的元素个数 > 扩容阈值, 进行扩容
查看value get(key)方法的源码
存储原理:
-
它的底层会调用K的hashCode()方法得出hash值。
-
通过哈希表函数/哈希算法,将hash值转换成数组的下标.
-
下标位置上如果没有任何元素,就新创建一个Node节点,并添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
读取原理:
第一步:先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
第二步:通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。重点理解如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着参数K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value