容器|集合
集合
定义
存储多个数据
与数组区别
数组
一段连续的内存空间
特点
1.引用数据类型
2.定长,长度一旦确定不可改变
3.存储数据的类型相同
4.有序,有索引
集合
特点
存储任意引用类型数据
集合的长度可变,可以根据需求动态的增删数据,长度随之改变
层次
Collection单个值的集合
Set无序不可重复
HashSet
List有序可重复,有索引
LinkedList
ArrayList
Map键值对的集合
KEY-VALUE
HashMap
简单封装容器类型(ArrayList)
声明形式
ArrayList list = new ArrayList<>();
常用方法
.add(需要添加的元素)
增加元素
.size()
集合中元素个数
.get(索引)
根据索引查看容器中的元素
.remove(索引)
根据索引删除容器中的元素
Collection集合
常用方法
boolean add(E e)
增加元素
boolean addAll(Collection<? extends E> c)
将指定集合中的所有元素添加到此集合中
void clear()
从此集合中删除所有元素
boolean isEmpty()
如果此集合不包含任何元素,则返回 true
boolean contains(Object o)
如果此collection包含指定的元素,则返回 true
boolean containsAll(Collection<?> c)
如果此集合包含指定集合中的所有元素,则返回 true
boolean remove(Object o)
从此集合中移除指定元素的单个实例(如果存在)
boolean removeAll(Collection<?> c)
删除此集合的所有元素,这些元素也包含在指定的集合中
boolean retainAll(Collection<?> c)
仅保留此集合中包含在指定集合中的元素
int size()
返回此集合中的元素数
Object[] toArray()
返回包含此集合中所有元素的数组
遍历方式
foreach增强for循环
iterator迭代器
Iterator<E> iterator()
返回此集合中元素的迭代器
举例
Iterator it = collection.iterator();
while(it.hasNext()){System.out.println(it.next());}
泛型
jdk1.5
参数化类型
数据类型作为参数传递
只能配置引用数据类型
优点
代码简单简洁
增强程序健壮性,避免类型转换异常的出现
增强稳定性与可读性
<>定义泛型
泛型的行为发生在编译期间,运行期间发型配置的所有内容无效,泛型擦除
要求先定义泛型,才能使用泛型
泛型类
类型的后面定义泛型,在使用类型的时候可以通过泛型传递具体的类型,类中可以进行使用
List
特点
有序集合(也称为序列)可重复
该接口的用户可以精确控制列表中每个元素的插入位置
新增: 一些列根据索引操作的方法
遍历方式
for普通for循环
foreach 增强for循环
iterator迭代器
常用方法
add(E e)
增加元素
void add(int index, E element)
将指定元素插入此列表中的指定位置
只能添加不能修改
boolean add(E e)
将指定的元素追加到此列表的末尾
E set(int index, E element)
用指定的元素替换此列表中指定位置的元素
只能修改不能添加
boolean addAll(int index, Collection<? extends E> c)
将指定集合中的所有元素插入到指定位置的此列表中
E get(int index)
返回此列表中指定位置的元素
int indexOf(Object o)
返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1
int lastIndexOf(Object o)
返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1
static <E> List<E> of(E... elements)
返回包含任意数量元素的不可修改列表
E remove(int index)
删除此列表中指定位置的元素
优先识别
boolean remove(Object o)
从该列表中删除指定元素的第一个匹配项(如果存在)
List<E> subList(int fromIndex, int toIndex)
返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
Vector
底层结构
数组
特点
与ArrayList相同
区别
1) Vector是同步的|线程安全 ArrayList不同步|线程不安全,相对效率较高
2) Vector每次扩容原容量的2倍 ArrayList每次扩容原容量的1.5倍,相对ArrayList更有利于节省内存
总结
如果不需要线程安全实现,建议使用ArrayList代替Vector
注意
如果存储javabean类型的数据,在调用一些方法时候(indexOf..),默认调用equals方法进行判断,要求对javabean类型重写equals方法
实现类
ArrayList
实现所有可选列表操作,并允许所有元素,包括null
底层结构
数组 Object[] elementData;
特点
根据索引查询遍历效率较高,增删效率低
应用场景
适合应用在大量做查询,少量做增删的位置
扩容问题
初始容量 : 默认初始容量为10 ,在第一次添加add的时候进行构建
private static final int DEFAULT_CAPACITY = 10;
扩容机制
每次扩容原容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
新增功能
void forEach(Consumer<? super E> action)
遍历
普通for
增强for
iterator迭代器
listIterator迭代器
LinkedList
实现所有可选列表操作,并允许所有元素(包括null )
底层结构
双向链表
特点
查询效率低,增删效率高
应用场景
单个数据值的集合中,允许数据有序,且可重复,在大量做增删,销量做查询的时候时候适合使用链表
新增功能
新增了一些与链表头尾相关的方法
注意
请注意,此实现不同步
定义链表结构,存储javabean类型的数据,测试使用,遍历使用
存储javabean类型数据时候,要求javabean类型重写equals方法,否则使用一些判断比较的方法时候回默认调用equals方法
Set
特点
无序,不可重复|去重
无序
存放的顺序与内部真实存储的顺序不一致
去重
集合不包含元素对e1和e2 ,使得e1.equals(e2)和最多一个null元素
新增功能
static <E> Set<E> of(E... elements)
返回包含任意数量元素的不可修改集
遍历方式
foreach
iterator迭代器
实现类
TreeSet
底层结构
红黑树
TreeMap
特点
查询效率较高,自动把数据做升序排序
底层是由TreeMap维护的
新增功能
新增了一些与比较大小相关的方法
遍历方式
foreach
iterator迭代器
注意
TreeSet需要存储相同类型的数据,因为会默认存在比较排序
存储javabean类型的数据
去重与排序
都是根据比较规则实现的,与equals没有关系
比较规则
内部比较器 | 内部比较规则 | 自然排序
比较规则定义在javabean类型的内部
javabean类型实现Comparable接口,重写compareTo(T o)方法,在方法中定义比较规则
外部比较器 | 外部比较规则 | 定制排序
比较规则定义在javabean类型的外部
定义一个实现类,实现Comparator接口,重写int compare(T o1, T o2),在方法中定义比较规则
static <T> void sort(T[] a, Comparator<? super T> c)
根据指定比较器引发的顺序对指定的对象数组进行排序。
HashSet
底层结构
哈希表(数组+链表+红黑树)
HashMap
特点
查询,增删效率高 ,去重,无序
底层是由HashMap维护的
遍历方式
foreach
iterator迭代器
新增方法
无
此类允许null元素
注意
此实现不同步
去重
数据的类型要求重写hashCode与equals方法
Map
特点
无序的,去重的
一个key只能对应一个Value
key相同value覆盖
键值对数据的集合
K键
无序的,去重的|唯一的
V值
无序的,可重复
K-V可以为任意引用数据类型
遍历方式
1.values 获取所有键值对的值
Collection<V> values() 返回此映射中包含的值的Collection视图。
2.keySet 获取所有键值对的key,根据key获取value
Set<K> keySet() 返回此映射中包含的键的Set视图。
3.entrySet
Collection<V> values() 返回此映射中包含的值的Collection视图。
获取所有的键值对,每一个键值对都是一个Entry类型->表示一个键值对
Set<Map.Entry<K,V>> entrySet()
返回此映射中包含的映射的Set视图。
实现类
TreeMap
底层
红黑树
存储键值对类型的数据,自动升序排序,去重的
去重,排序
根据键值对的key实现,与value本身无关
根据key的类型的比较规则
key的数据类型实现内部比较器
传递外部比较规则
注意
此实现不同步
HashMap
底层
哈希表(数组+链表+红黑树)
此实现提供了所有可选的映射操作,并允许null值和null键。
哈希表
数组
节点数组Node[] --> 要求数组的长度为2的整数次幂
Node
int hash,Object key,Object value,Node next
每个索引位置存储的为一个单向链表的首节点(尾插法)
当链表的长度>8,数组的长度>64,会把链表优化成为红黑树
当链表的长度>8,但是数组的长度不大于64,这时候会实现扩容(数组的扩容)
初始容量
哈希表中的数组默认的初始长度 16
源码
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
数组的容量最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
加载因子
0.75 一般不建议改变
源码
static final float DEFAULT_LOAD_FACTOR = 0.75f;
扩容阀值
扩容的临界值 数据的个数size>数组的长度*加载因子 就会扩容
扩容机制threshold
原容量的2倍 int newCap = oldCap << 1
新增功能
无
哈希表存储数据的过程
1.根据key计算哈希值
通过key的hashCode方法的返回值进一步进行hash算法的运算,得到的整数
源码
int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
2.调用putVal方法实现添加数据(hash,key,value)
1)判断是否是第一次调用put方法做添加 if ((tab = table) == null || (n = tab.length) == 0)如果是第一次添加,直接调用resize()实现扩容
2)计算位桶的索引 int index = (n - 1) & hash
3)判断哈希表结构的数组table[index]是否存在数据
如果不存在数据,证明没有头节点,创建新节点,放入当前数组的对应索引位置作为头节点
table[index] = new Node<>(hash, key, value, next);
size数据的个数+1,判断是否>扩容的阀值,如果大于需要调用resize方法进行扩容,如果不大于,不需要扩容直接返回null
if (++size > threshold) resize();
return null;
如果存在数据,作为链表的头结点,遍历这个链表,拿到每一个节点的key与hash值判断是否与要添加的key和hash相同,如果相同,value覆盖
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
value覆盖之后,返回被覆盖的value
V oldValue = e.value;
e.value = value;
return oldValue;
去重
根据key做去重,要求key的数据类型重写hashCode与equals方法
Hashtable
与HasMap的区别
共同点
都是Map接口的实现类,底层结构都是哈希表
异同点
1.继承体系不同
2.线程是否安全不同
HashMap 线程不安全|不同步
Hashtable 线程安全的|同步的
3.扩容机制不同
HashMap扩容机制
每次扩容原容量的2倍
int newCap = oldCap << 1
Hashtable扩容机制
原容量的2倍+1
int newCapacity = (oldCapacity << 1) + 1;
4.键值对数据null值的要求不同
HashMap 可以存储null值的key与value
Hashtable key与value都不为null
5.计算hash值与位桶索引index的算法不同
HashMap
int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
int index = (n - 1) & hash
Hashtable
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
如何处理HashMap线程不安全问题
1.使用Hashtable
2.使用Collections工具类中static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
返回由指定映射支持的同步(线程安全)映射
3.juc高级并发编程包 ConcurrentHashMap<K,V>-> 线程安全的哈希表
Collections
操作集合的工具类
静态工厂
常用方法
void sort(List)
对List容器内的元素排序,排序的规则是按照升序进行排序
void shuffle(List)
对List容器内的元素进行随机排列
void reverse(List)
对List容器内的元素进行逆续排列
void fill(List, Object)
用一个特定的对象重写整个List容器
int binarySearch(List, Object)
对于顺序的List容器,采用折半查找的方法查找特定对象