java中常用集合(边补充)

一、单列集合Collection

主要使用的是List和Set集合

1.1List接口

主要包括ArrayList、LinkedList、Vector(线程安全)、CopyOnWriteArrayList(线程安全)

1.1.1 ArrayList

ArrayList是线程不安全的,底层数据结构是可变数组,查询快,增删慢。
如果有参数扩容1.5倍;如果没参数第一次扩容为10,第二次满了扩容为1.5倍 扩容使用的是Arrays.copyOf()

1.1.2 LinkedList

LinkedList底层维护了一个双向链表,没有实现同步是线程不安全的底层数据结构是链表,查询慢,增删快。

1.1.3 Vector(线程安全)

Vector是线程同步的,即线程安全的,该类方法带有synchronized,类似ArrayList,效率不如ArrayList
如果是无参 第一次扩容为10,第二次满了扩容为2倍;如果指定大小,则每次按照两倍扩容
Stack继承Vector,也是线程安全的,支持push、pop、peek等操作

1.1.4 CopyOnWriteArrayList(线程安全)

(1)首先CopyOnWriteArrayList内部也是通过数组来实现的,在向CopyOnWriteArrayList中添加元素时,会复制一个新的数组,写操作在新数组上进行,读操作在原数组上进行
(2)并且,写操作会加锁,防止出现并发写入丢失数据的问题
(3)写操作结束后会把原数组指向新数组
(4)CopyOnWriteArrayList允许在写操作时来读取数据,大大提高了读的性能,因此适合读多写少的应用场景,但是CopyOnWriteArrayList会比较占用内存,同时可能读到的数据不是实时最新的数据,所以不适合实时性要求很高的场景

应用场景 (1)读多写少的场景:CopyOnWriteArrayList的读操作不需要加锁,因此非常适合在读多写少的场景中使用
(2)不需要实时更新的数据:CopyOnWriteArrayList读取的数据可能不是最新的,因此他适合于不需要实时更新的数据

1.2 Set接口

主要包括HashSet、LinkedHashSet、CopyOnWriteArraySet
主要特点:
1)无序(添加和取出的顺序不一致),取出的顺序虽然不是添加的顺序,但是它的顺序是固定的。
2)不允许有重复元素;可以存放null,最多包含一个null,重复add返回false
3)没有索引,故不能使用索引的方法来获取元素

1.2.1 HashSet

实现了set接口,本质上底层是一个HashMap
主要是hashCode和equals方法

HashSet底层数据结构是哈希表,因此具有很好的存取和查找性能。
哈希表:一个元素为链表的数组,综合了链表(存储速度快)和数组(查询速度快)的优点。
1)使用HashSet添加一个元素时,会先得到hash值,然后转成—>索引值
2)找到存储数据表table,看这个索引位置是否已经存放的有元素。
3)没有则直接加入,如果有,则调用equals方法进行比较
4)在Java8中,如果一条链表的元素个数达到TREEIFY_THRESHOLD (默认是8),并且table的大小 >= MIN_TREEIFY_CAPACITY (默认是64),就会进行树化(红黑树),这样又大大提高了查找的效率。

1.2.2 LinkedHashSet

1)在LinkedHashSet中维护了一个hash表和双向链表(LinkedHashSet有head和tail)
2)每一个节点有before和after属性,这样可以形成双向链表
3)在添加一个元素时,先求hash值,再求索引,确定该元素在table的位置,然后将添加的元素加入到双向链表
4)遍历LinkedHashSet,插入顺序和遍历顺序一致

1.2.3 CopyOnWriteArraySet

每次调用CopyOnWriteArraySet的add方法的时候,其底层是基于CopyOnWriteArrayList的addIfAbsent方法的,
每次在addIfAbsent方法中都要对数组进行遍历,所以CopyOnWriteArraySet的性能低于CopyOnWriteArrayList

public class CopyOnWriteArraySet<E> extends AbstractSet<E>
//CopyOnWriteArraySet底层是基于CopyOnWriteArrayList的
    private final CopyOnWriteArrayList<E> al;
//add方法底层调用的还是CopyOnWriteArrayList的addIfAbsent方法
    public boolean add(E e) {
        return al.addIfAbsent(e);
    }

二、双列集合Map

特点:

键值对映射关系

一个键对应一个值

键不能重复,值可以重复

元素存取无序

集合的遍历(待补充代码)

方法一:
1. 获取所有键的集合。用keySet()方法实现
2. 遍历键的集合,获取到每一个键。用增强for实现  
3. 根据键去找值。用get(Object key)方法实现

方法二:
1. 获取所有键值对对象的集合:Set<Map.Entry<K,V>> entrySet()
2. 遍历键值对对象的集合,得到每一个键值对对象:用增强for实现,得到每一个Map.Entry
3. 根据键值对对象获取键和值:用getKey()得到键;用getValue()得到值

2.1 hashMap

HashMap首先还是会创建一个默认长度为16,默认加载因子为0.75的数组;
然后再利用put方式,就可以添加数据了,put方法的底层会先创建一个Entry对象,Entry对象里面记录的就是要添加的键和值,然后利用键来计算哈希值,跟值无关,然后再计算出元素在数组中应存储的位置的索引,如果该位置为null,直接添加,如果该位置不为null,它会调用equals方法比较键的属性值,如果键的值相同,那么元素就会被覆盖;如果比较完后不一样,则会添加新的Entry对象;
JDK8,如果计算出来的索引相同,且键不一致,那么就会直接挂在当前值的下面;
此外,当链表长度超过8,且数组长度大于等于64的时候,链表就会自动转成红黑树
如果键存储的是自定义对象需要重写hashCode和equals方法,值存储不需要重写

2.2 hashTable(线程安全)

HashTable线程安全 (他的每一个方法都加了锁,适用于多线程并发的环境)
HashTable默认的初始大小为11 每次扩充为2n+1 加载因子0.75

2.3 LinkedHashMap

双向链表
由键决定:
有序、不重复、无素引。
有序:保证存储和取出的顺序一致
原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序

2.4 ConcurrentHashMap(线程安全)

可以理解为hashMap的升级版本,在ConcurrentHashMap中,无论是读操作还是写操作都能保证很高的性能:在进行读操作时(几乎)不需要加锁,而在写操作时通过锁分段技术只对所操作的段加锁而不影响客户端对其它段的访问。特别地,在理想状态下,ConcurrentHashMap 可以支持 16 个线程执行并发写操作(如果并发级别设为16),及任意数量线程的读操作。
通过锁分段技术保证并发环境下的写操作;
通过 HashEntry的不变性、Volatile变量的内存可见性和加锁重读机制保证高效、安全的读操作;
通过不加锁和加锁两种方案控制跨段操作的的安全性。

2.5 TreeMap

TreeMap底层是红黑树结构 增删改查性能较好
不重复 无索引 可排序
依赖自然排序或者比较器排序,对键进行排序
如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值