java中的集合_Java 集合介绍,常用集合类

JAVA 集合

在处理数据的过程中经常会需要一个容器来存储某一类型的数据,Java 中的数组就是这样一种容器。但 Java 中的数组有其局限性,定义后的数组长度不可变,超出数组长度后就不能再存放数据了。而很多时候我们并不知道数据到底有多少,所以就需要有不定长的容器来存放数据,这就是集合,Java 中的集合都采用了泛型实现,可以存入任何类型的对象数据。Java 中的数组:

332887c079fcbdde3c7946f98b8ad3ea.png

Java 中的集合主要分为四类:

List 列表,有序,可重复Queue 队列,有序,可重复Set 集合,不可重复Map 映射,无序,键唯一,值不唯一每种集合类型下都包含多个具体的实现类,如:

a686c9177f3e6709adca893d54806e39fadc55f2.jpeg?token=01c2e0c126de816f1fd33dd840edc2d0&s=59A03C72010F454B4E5560DA0000C0B2

1. List 列表,有序、可重复

常用的 List 实现类有:ArrayList、LinkedList、Vector、Stack。

1.1 ArrayList 列表

ArrayList 数组列表,有序,可重复,内部是通过 Array 实现。初始化对象时,如果没有传大小,则列表的大小为 DEFAULT_CAPACITY 的默认值 10。当列表容量不够时,继续往列表中追加元素,则通过数组拷贝,对原数组进行扩容,扩容的方式为 "int newCapacity = oldCapacity + (oldCapacity >> 1)",即新数组容量 newCapacity 为 10 + 10/2 = 15。如果一次性追加多个元素时比如 6 ,时候列表最小容量 minCapacity 需要 10 + 6 = 16,新的容量 newCapacity 小于最小容量 minCapacity 则新数组容量取最小容量值 newCapacity = minCapacity。

对数组列表进行插入、删除操作时都需要对数组进行拷贝并重排序。所以如果能知道大概存储多少数据时,尽量初始化初始容量,提升性能。

ec2284fda7b0b12d642239062fb379bc.png

1.2 LinkedList 双向链表

LinkedList 是双向链表,也即每个元素都有指向前后元素的指针。既然是链表那么顺序读取的效率非常高,而随机读取的效率较低。当随机获取一个 index 位元素时,链表先比较 index 和链表长度 1/2 的大小,小于时从链表头部查找元素,大于时就从链表尾部查找元素。

3d7871a7a57354aefcc9cd089b5e6019.png

对比 ArrayList 如果随机读取数据较多时使用 ArrayList 性能高,插入删除较多时使用 LinkedList 性能高。

1.3 Vector 向量,线程安全的列表

与 ArrayList 一样也是通过数组实现的,不同的是 Vector 是线程安全的,也即同一时间下只能有一个线程访问 Vector,线程安全的同时带来了性能的耗损,所以一般都使用 ArrayList。Vector 的扩容也与 ArrayList 不同,可以设置扩容值,默认每次扩容原来的一倍。

d3e4a5d62fee4dddde3a5c593133f032.png

1.4 Stack 栈,后进先出(LIFO)

Stack 继承自 Vector 所以也是数组实现的,线程安全的栈。因为 Stack 继承自 Vector 所以就拥有 Vector 中定义的方法,但作为栈数据类型,不建议使用 Vector 中与栈无关的方法,尽量只用 Stack 中的定义的栈相关方法,这样不会破坏栈数据类型。

c7aef3e5e220570cc3d82d3f784a90cc.png

1.5 ArrayQueue 数组队列,先进后出(FIFO)

ArrayQueue 是数组实现的队列,从队尾加入数据,只能队头删除数据,可随机读取队列数据。

56527c59ada9a190564ca64f5f64c98f.png

2. Queue 队列,有序、可重复

继承自 Queue 的队列有:ArrayDeque、LinkedList、PriorityQueue。

2.1 ArrayDeque 数组实现的双端队列

ArrayDeque 是队列,但也可以作为栈使用,而且对比 Stack 更高效。作为双端队列那就可以在队列两端插入和删除元素。当追加元素超过容量限制时,则创建一个两边容量的新数组,并将原数组的内容拷贝到新数组中。

5c629efeffdf9830626e57b4f0adddad.png

2.2 LinkedList 队列也是双向链表

上文 1.2 中已经提过,这里就不赘述了。推荐使用 ArrayDeque。

2.3 PriorityQueue 优先队列,数组实现的二叉树

PriorityQueue 是一个完全二叉树实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值)。

267627a23ca7017837a31b4d4d11baef.png

3. Map 映射/字典,无序,键值对,键唯一

常用的 Map 实现有:HashMap、TreeMap、LinkedHashMap

3.1 HashMap 哈希映射/字典

HashMap就是key->value的键值对数据,key是唯一的,而且key和value都可以为null。HashMap和HashTable相似,HashTable实现了线程同步,在 "Object超类解析" 章节中简单介绍过HashTable的数据存储方式。HashMap 是个无序的字典,遍历时不保证元素顺序。HashMap创建时默认会设置初始容量大小(默认16),和装载因子(默认0.75,扩充容量的阀值),装载因子=已存入元素个数/总容量大小。当然这两个值也可以手动设置。

HashMap的数据存储结构如下图:

8ea5a30456645d99172a3c9b75f352f6.png

HashMap当插入一个数据时,先对key值做hash,用得到的值与容器的大小n减1做&运算得到桶的位置,即:i = (n - 1) & hash,i就是桶的位置。在桶中查找有无元素,没有直接插入,有则比较元素key值是否相同,相同用新值替换。

桶的位置计算为什么是 (n - 1) & hash?先看hash值的计算:

94f6e9e572ad35db334521a01c9feeaf.png

hash() 函数对 key 取值后返回一个整数。又因为 HashMap 的容量 n 大小始终为 2 的幂(默认为 16),那么 n - 1 的二进制始终是最高位为 1,其它位为 0 的数,如:10...0,这个数与整数做 & 运算就得到 hash / n 的余数,余数的取值范围在 0 ~ n-1,很巧妙的设计。相关源码,这里截取了部分:

6a01fb98b8e15cb989461c636a6007c2.png

3.2 TreeMap 红黑树实现的 key->value 容器,可排序

红黑树是一种自平衡二叉查找树,具体查看资料。

3.3 LinkedHashMap 链表映射/字典

LinkedHashMap 继承自 HashMap 所以具有 HashMap 的所有特性。同时又实现了双向链表的特性,保留了元素插入顺序。

297ef88869da986c43b95ddea1ff01ae.png

4. Set 集合,不可重复

常用的 Set 实现有:HashSet、LinkedHashSet、TreeSet、EnumSet。

4.1 HashSet 哈希集合

HashSet是基于HashMap实现的集合,对HashMap做了一些封装。数据结构如图:

fd5771ac0673a1bc66552126f06c1e0e.png

与HashMap不同的是元素的保存为链表形式,插入数据时遍历链表查看是否有相同数据,有则返回false,没有返回true。

96b55080c3791c6e3744e4a58657a686.png

4.2 LinkedHashSet 链表集合

继承自 HashSet 与 LinkedHashMap 相似,是对 LinkedHashMap 的封装。

4.3 TreeSet 红黑树集合

与 TreeMap 相似。是对 TreeMap 的封装。

本文只是对 Java 中的集合类做了个简单介绍,详细设计请查看源码了解详情。

c15dabbd6f27a30a1998ca60034aee8b.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值