java关于集合

java 集合总体分为两大类,一类是单列集合Collection,一类是双列集合Map

Collection 接口的子接口有List接口,Set接口

List: 一个有序的(元素存入集合的顺序和取出的顺序是一致的)容器,元素可以重复,可以插入多个null元素,元素都有索引;

List接口的实现类主要有ArrrayList,LinkedList,Vector等

Set: 一个无序(存入和取出顺序有可能不一致) 容器,不可以储存重复元素,只允许存入一个null元素,必须保证元素一致性

set接口的主要实现类有HashSet,TreeSet,LinkedHashSet等

Map 是一个键值对集合,存储键,值之间的映射.key无序,唯一,value不要求有序,允许重复

Map接口的主要实现类有: HashMap,TreeMap,HashTable,ConcurrentMap

1. List接口 ArrayList和LinkedList

(1) ArrayList优点: ArrayList底层以数组实现(在内存中是连续的),是一种随机访问模式,实现了RandomAccess 接口,因此查找的时候非常快,在顺序添加一个元素的时候非常方便;

RandomAccess 接口的主要目的是允许一般的算法能更改其行为,从而在随机或连续访问列表时能提供良好的性能。

通俗讲,就是在随机访问或者顺序遍历集合时候,我们可以根据集合实现类是否实现了RandomAccess接口,来决定使用不同的遍历策略。

如果集合类实现了RandomAccess接口,推荐使用for (int i=0, n=list.size(); i < n; i++)遍历,反之使用Iterator迭代器遍历集合。
不过现在机器性能很高了,对于集合大小很小的情况下,其实2种遍历方案性能差不多,如果数据量极大则可以根据情况进行决策。简而言之就是因材施教,切不可盲目滥用。
(2)缺点: 删除和插入的时候,需要做一次元素复制操作,如果复制的元素很多,那么就会比较耗费性能;

(3) LinkedList 是双向链表的数据结构实现的,ArrarList比LinkedList查找效率要高,因为LinkedList是线性的数据存储方式需要移动指针从前往后依次查找

   增加和删除效率: 在非首尾的增加可删除操作,LinkedList效率要比ArrayList高,因为ArrayList增删操作要影响组内其他数据的下标

   内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。

双向链表: 包含两个指针,一个 prev 指向前一个节点,一个 next 指向后一个节点。

理解参考:java中ArrayList为什么比LinkedList查询速度快? - 知乎

ArrayList扩容:

以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为 10

超过容量,新容量会以原先容量的1.5倍扩容

2.Set接口 HashSet和TreeSet

hashSet(无序,唯一) 基于HashMap实现的,底层采用哈希表,它的排序规则是按照hash函数决定的,无法人为设置

TreeSet(有序,唯一)底层是红黑树(自平衡的排序二叉树)可以使用自然排序或者比较器排序,扩容通过结点连接

红黑树: 又叫平衡二叉b树,红黑树的所有节点排成一条线后一定是左小右大,并且在插入新的节点时,

会通过左旋右旋的方式来平衡二叉树;

3.Map接口 HashMap,TreeMap和HashTable

HashMap: JDK1.7是有数组和链表组成的,数组是HashMap的主体,链表主要是为了解决哈希冲突而存在的,jdk1.8 由“数组+链表+红黑树”组成。当链表过长,比较影响HashMap的性能,

因此,JDK1.8 对数据结构做了进一步的优化,引入了红黑树,链表和红黑树在达到一定条件会进行转换:

  • 当链表超过 8 且数据总量超过 64 才会转红黑树。

  • 将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。

解决Hash冲突方法有:开放定址法、再哈希法、链地址法(拉链法)、建立公共溢出区。HashMap中采用的是 链地址法 。

链地址法就是将相同hash值的对象组织成一个链表放在hash值对应的槽位

hashMap的冲突是不得已的,在最优的情况下,应该每个值存在单独的节点上,冲突后才会挂在链表上。冲突超过8个才会转换为红黑树。很少会有这么多冲突,如果出现了,就说明hash方法不适合。

1)、hashMap1.7 扩容: 就是hashmap在存值的时候(默认大小为16,负载因子0.75,阈值12),可能达到最后存满16个值的时候,再存入第17个值才会发生扩容现象,因为前16个值,每个值在底层数组中分别占据一个位置,并没有发生hash碰撞。(集合长度达到阈值(集合长度*0.75)就扩容)

(2)、当然也有可能存储更多值(超多16个值,最多可以存26个值)都还没有扩容。原理:前11个值全部hash碰撞,存到数组的同一个位置(这时元素个数小于阈值12,不会扩容),后面所有存入的15个值全部分散到数组剩下的15个位置(这时元素个数大于等于阈值,但是每次存入的元素并没有发生hash碰撞,所以不会扩容),前面11+15=26,所以在存入第27个值的时候才同时满足上面两个条件,这时候才会发生扩容现象(发生哈希冲突)。

JDK1.8 是先添加,在扩容。具体put是否扩容需要满足一个条件:只要达到阈值就扩容

HashTable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的

hashTable 的key和value都不能为null;

hashTable是线程安全的,因为它的每一个方法都有synchronized 关键字,因此可直接用于多线程中。
虽然HashMap是线程不安全的,但是它的效率远远高于Hashtable,这样设计是合理的,因为大部分的使用场景都是单线程。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。
ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。

TreeMap :红黑树(自平衡的排序二叉树)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值