集合
1.单列集合:
均是collection根接口的实现类
List:是一个有序可重复的,可以利用索引快速查找
单列集合 | 底层 | 特点 | 区别 | 使用 |
---|---|---|---|---|
ArrayList | 数组 | 查询快,增删慢,不安全,效率高 | 1. Arraylist底层使用的是数组(存读数据效率高,插入删除特定位置效率低) | 一般程序只用Arraylist |
LinkList | 链表 | 查询慢,增删快,不安全,效率高 | 1.LinkedList底层使用的是双向循环链表数据结构(插入,删除效率特别高) | 当数据特别多,而且经常需要插入删除元素时建议选用LinkedList. |
Vector | 数组 | 查询快,增删慢,安全,效率低 | 1.所有方法都是同步的。可以由两个线程安全地访问一个Vector对象 | 取出使用的是枚举,与迭代器类似 |
备注:
ArrayList****自动扩充机制
实现机制:ArrayList.ensureCapacity(int minCapacity)
首先得到当前elementData属性的长度oldCapacity。然后通过判断oldCapacity和minCapacity参数谁大来决定是否需要扩容, 如果minCapacity大于oldCapacity,那么我们就对当前的List对象进行扩容。
扩容的的策略为:取(oldCapacity * 3)/2 + 1和minCapacity之间更大的那个。然后使用数组拷贝的方法,把以前存放的数据转移到新的数组对象中。如果minCapacity不大于oldCapacity那么就不进行扩容。
Set:是一个不可重复的
Set | 特点 | 底层 | 特性 |
---|---|---|---|
HashSet | 无序、唯一 | 哈希表 | 根据对象的hashCode(哈希值即对象在哈希表中的位置)和equals(如果产生哈希冲突使用)方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。 |
LinkedHashSet | 有序、唯一 | 链表+哈希表 | 根据HashCode的值来决定元素的存储位置,但同时它还用一个链表来维护元素的插入顺序,插入的时候即要计算hashCode又要维护链表 |
TreeSet | 有序、唯一 | 红黑树(自平衡排序二叉树) | TreeSet指定排序规则:方式一:元素自身具备比较性;方式二:容器具备比较性 分为:自然排序和定制排序 |
EnumSet | 有序 | 枚举类型 | 存取速度快,批量操作快 |
备注:
\1. 二叉树知识:
先去寻找是否有相同节点,如果没就开辟一个新的节点,和上一级根节点比较大的话放在左边,小的换放在右边
取出的时候先取出所有的左边的元素再取自己最后取出右边的
\2. TreeSet排序
一:自然排序(在元素中写排序规则)
TreeSet (底层就是一个二叉树)
会调用compareTo方法比较元素大小,然后按升序排序。所以自然排序中的元素对象,都必须实现了Comparable接口—à提供自然排序,否则会抛出异常。TreeSet只允许存入同一类的元素否则就会抛出类型转换异常
二:定制排序(在集合中写排序规则)
TreeSet还有一种排序就是定制排序,定制排序时候,需要关联一个 Comparator对象(实现Comparator接口),由Comparator提供排序逻辑。
遍历方式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A90QrQXy-1571611750425)(file:///C:/Users/墩妞/AppData/Local/Temp/msohtmlclip1/01/clip_image001.png)]
\1. 增强for循环:
可以简化数组,集合的遍历
\2. 迭代器:
iterator是迭代器接口,迭代器接口的方法 hashnext()是用于判断是否有下一个元素. next()是取出下一个元素的方法 在迭代的时候尽量不要用add或者remove方法 来改变集合的长度,因为迭代器记忆的是之前的长度. 导致并发修改异常.
使用迭代器更加线程安全,因为它可以确保,在当前遍历的集合元素被更改的时候,它会抛出ConcurrentModificationException。
2.双列集合:
Map:使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象,每个key只能映射一个value
保证key的唯一性依赖于它本身的方法和使用hashcode和equals方法(如果是一个类的键,重写hashcode,equals)
哈希表结构是一种数组+链表的结构:
JDK8引入了二叉树,加快了查询速度,当某一个索引下的长度达到一定长度的时候,自动将链表转为二叉树结构
当有元素存进来先使用hashcode方法比较数组中是否有相同的,没有就开辟一个新的索引位置,有就进行equals方法的比较相同的话不予添加,不同的话在索引下方链表(jdk8达到长度后二叉树)挂载
Map | 特性 | |
---|---|---|
HashMap | 键值对,key不能重复,但是value可以重复;允许null的键或值;储存顺序无序的,不同步的 | key的实现就是HashSet;value对应着放; |
HashTable | 线程安全的,不允许null的键或值; 同步的线程安全 | HashTable内部的方法基本都经过synchronized修饰。 效率低,逐渐淘汰,转而使用ConcurrentHashMap |
ConcurrentHashMap | 将数据分段存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。 内部:是由Segment数组结构和HashEntry数组结构组成 | 在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,获得锁的顺序是固定的,这可以确保不会出现死锁 Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。 |
LinkedHashMap | 此实现与 HashMap 相同 | 维护着一个运行于所有条目的双重链接列表。 存储的数据是有序的。 |
TreeMap | 对key排好序的Map; 二叉树进行存储键和值 | key 就是TreeSet, value对应每个key; key要实现Comparable接口或TreeMap有自己的构造器; |
Properties | key和value都是String类型,用来读配置文件; | 实例,数据源的配置信息 |
遍历:
需要用到的方法:
public Set keyset() : 将Map所有的key封装到一个Set的集合。
public V get(Object key): 根据key(键)获取Map中对应的value(值)。
public set <Map. Entry<K,V>> entrySet()>: 获取所有的键值对对象集合。
public Collection values() : 将 Map中所有的value封装到一个Collection体系的集合。
第一种遍历方式:
- 通过public Set keyset()方法获取到所有的键集合;
遍历键的集合得到每一个键–à增强for
根据键使用get方法在map中找到对应的value
- 通过public set <Map. Entry<K,V>> entrySet()>获取所有的键值对集合
迭代器遍历键值对集合,获取每一个键值对对象/使用增强for循环获取每一个键值对对象
通过getKey,getValue方法获取键和值
- 通过public Collection values()获取到所有的值集合
键值对集合,获取每一个键值对对象/使用增强for循环获取每一个键值对对象
通过getKey,getValue方法获取键和值
- 通过public Collection values()获取到所有的值集合
遍历集合获取所有的值