java中的集合分为value值(Collection)、key-value键值对(Map)两种。
存储值的有:List和Set
List:有序,可重复
- 常用的有ArrayList和LinkedList
- ArrayList底层使用的是数组
特点是:查询快,增删慢(因为数组在内存中是一块连续的内存,如果插入删除可能需要大量移动内存)
使用场景:用于查询使用较多,插入删除使用较少的情况
缺点: 线程不安全,效率高- LinkedList底层使用的是链表
特点是:增删快,查询慢(链表在内存中是不连续的,当前元素中存放有上一个和下一个元素的地址。查询时需要从头部开始,一个一个找,所以查询效率低;插入时不需要移动内存只需要改变指向)
使用场景:用于查询使用较少,而插入删除使用较多的情况
缺点: 线程不安全,效率高Set:无序,不可重复(根据equals和hashcode判断)
一个对象要存储在set中,必须重写equals和hashcode方法
存储键值对的为Map
Connection接口:
— List 有序,可重复
-
ArrayList
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程不安全,效率高 -
Vector
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程安全,效率低 -
LinkedList
优点: 底层数据结构是链表,查询慢,增删快。
缺点: 线程不安全,效率高
—Set 无序,唯一
- HashSet
底层数据结构是哈希表。(无序,唯一)
如何来保证元素唯一性?
1.依赖两个方法:hashCode()和equals() - LinkedHashSet
底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一 - TreeSet
底层数据结构是红黑树。(唯一,有序)
- 如何保证元素排序的呢?
自然排序
比较器排序
2.如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
针对Collection集合我们到底使用谁呢?(掌握)
唯一吗?
- 是:Set
排序吗?
是:TreeSet或LinkedHashSet
否:HashSet
如果你知道是Set,但是不知道是哪个Set,就用HashSet。
- 否:List
要安全吗?
是:Vector
否:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
如果你知道是List,但是不知道是哪个List,就用ArrayList。
如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。
如果你知道用集合,就用ArrayList。
map
Map接口有三个比较重要的实现类,分别是HashMap、TreeMap和HashTable。
- TreeMap是有序的,HashMap和HashTable是无序的。
- Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。
这就意味着:
- Hashtable是线程安全的,HashMap不是线程安全的。
- HashMap效率较高,Hashtable效率较低。 如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap。
查看Hashtable的源代码就可以发现,除构造函数外,Hashtable的所有 public 方法声明中都有
synchronized关键字,而HashMap的源码中则没有。 - Hashtable不允许null值,HashMap允许null值(key和value都允许)
- 父类不同:Hashtable的父类是Dictionary,HashMap的父类是AbstractMap
参考https://blog.csdn.net/zhangqunshuai/article/details/80660974
面试问题:说一下你对Map的理解
**思路:**先说一下map集合的特点,再说一下有哪些实现类,最后依次讲一下每个实现类特点
- Map主要用于存储键值对,根据键得到值,因此不允许键重复,但允许值重复。
- 在java中的一个接口java.util.Map,它有四个实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap.
- 实现类
hashmap是最常用的map,它根据键的hashcode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。
(HashMap的本质可以认为是一个数组,数组的每个索引被称为桶,每个桶里放着一个单链表,一个节点连着一个节点。)
这里补充一下时间复杂度,hashmap查询分四步:
- 判断key根据key算出索引
2.根据索引获得索引位置所对应的键值对链表
3.遍历键值对链表,根据key找到对应的entry键值对
4.拿到value
分析:
以上四步要保证HashMap的时间复杂度O(1),需要保证每一步都是O(1),现在看起来就第三步对链表的循环的时间复杂度影响最大,链表查找的时间复杂度为O(n),与链表长度有关。我们要保证那个链表长度为1,才可以说时间复杂度能满足O(1)。但这么说来只有那个hash算法尽量减少冲突,才能使链表长度尽可能短,理想状态为1。因此可以得出结论:HashMap的查找时间复杂度只有在最理想的情况下才会为O(1),而要保证这个理想状态不是我们开发者控制的
遍历的时候,取得的数据都是随机的。只允许最多有一条记录的键为Null;HashMap不是线程安全的,也就是说,多个线程同时写hashMap可能会导致数据不一致。
线程同步实现方法:
1、使用Collections.sychronizedMap方法 原理 同步代码块
2、使用ConcurrentHashMap 原理 切分成多个桶,每个桶都是一个线程安全的Hashtable,性能更高,推荐使用。
hashTable与hashMap类似,都继承自dictionary类,不同的是,它不允许空的键或值;但是支持线程同步,同步方式是方法上加锁sychronized,属于对象锁,一次只允许一个线程通过,所以写入速度会很慢。
linkedHashMap是HashMap的子类。所以它的特点是插入的时候会按照应用次数排序。遍历的时候得到的数据是先插入的。
TreeMap实现sortMap集合,把键按照升序排序。也可以指定比较器。使用iterator遍历时,得到的数据时排好序的。
参考https://blog.csdn.net/zgy956645239/article/details/105216680
https://www.cnblogs.com/123-shen/p/11603761.html
底层真的看不下去,以后再看吧
https://blog.csdn.net/visant/article/details/80045154hashmap