Java集合框架

集合的简介

集合是“由若干个确定的元素所构成的整体”,在程序中,一般代表保存若干个元素(数据)的某种容器类。在数学中,我们经常遇到集合的概念。例如:

  • 有限集合:

        一个班所有的同学构成的集合;

        一个网站所有的商品构成的集合;

        ...

  • 无限集合:

        全体自然数集合:1、2、3,......

        有理数集合;

        实数集合;

        ...

在Java中,如果一个Java对象可以在内部持有(保持)若干其他Java对象,并对外提供访问接口,我们把这种Java对象容器称为集合。很显然,Java的数组也可以看作是一种集合:

String[] ss = new String[10];//可以持有10个String对象
ss[0] = "Hello";//可以放入String对象
String first = ss[0];//可以获取String

既然Java提供了数组这种数据类型,可以充当集合,那么,我们为什么还需要其他集合类?这是因为数组有如下限制:

  • 数组初始化后大小不可变;
  • 数组只能按索引存取;

因此我们需要各种不同的类型集合类来处理不同的数据,例如:

  • 可变大小的顺序链表;
  • 保证无重复元素的集合
  • ...

Collection接口

Collection接口下有三个我们常用的集合子接口,他们都是单列集合分别是List接口、Set接口、Queue接口

List接口

在集合类中,List是最基础的一种集合:他是一种有序列表.List的行为和数组几乎完全相同:List内部按照放入元素的先后顺序存放,每个元素都可以通过索引确定自己的位置,List的索引和数组一样从0开始.

List具有有序且内容允许重复(值不唯一)的特点,其常见实现类可以分为"线程安全"和"线程不安全"的实现类

线程不安全

在我们不考虑有多个线程同时读写删除的情况下我们可以使用“线程不安全”的List集合实现类,毕竟"线程安全"的类会在一定程度上导致程序效率的下降

ArrayList

ArrayList数据结构:数组: Object[ ] elementData

使用场景:查找、遍历的效率高,但是由于其本质为数组,因此其插入、删除的效率低,需要进行遍历

扩容方式:ArrayList的无参构造方法是将数组的容量初始化为0,在添加(add())时会将数组容量扩容为10,其有参构造方法是按照自己输入的参数来创建(指定)初始化的容量大小,如果其中元素数量超过10时或着准确的说是超过数组现有容量时(容量不足时),数组将会扩容至当前的1.5倍(源码中是自身容量+自身容量的二进制数向右位移一位)。

LinkedList

LinkedList数据结构:链表:双向链表

使用场景:因为其数据结构为一个双向链表,插入与删除元素并不会对除了前后两个元素外的其他元素产生影响,因此插入、删除效率高,但是同样的是由于链表的原因,其从本质上来说并不拥有索引,我们做操作时的索引实际上是遍历时所产生的顺序,因此其查找也就是读的效率差。

扩容方式:链表动态扩容,每添加一个节点,链表动态扩容一个元素空间

线程安全

在有多个线程的程序中就可以使用线程安全的List集合的实现类,通过synchronized同步锁实现

Vector

Vector的数据结构:数组:Object[ ] elementData

扩容方式:初始化:无参构造方法,数组的初始化容量为10,

                                有参构造方法,数组按照指定容量初始化。

                  容量不足时:按照数组现有容量的2倍或者指定容量值(capacityIncrement)进行扩容

Stack

特点:先进后出(FIFO),栈存储,自带逆序功能

CopyOnWriteArrayList

数据结构:数组:Object[ ] array

线程安全:通过“ReentrantLock”锁实现;CopyOnWrite:“写入”操作时,先进行数组复制,让在新数组中进行写入操作,然后替换;允许读写同时进行;

Set接口

Map用于存储key-value的映射,对于充当key的对象,是不能重复的。并且。不但需要正确覆写equals()方法,还要正确覆写hashcode()方法。

如果我们只需要存储不重复的key,并不需要存储映射的value,那么就可以使用Set。

Set用于存储不重复的元素集合,它主要提供以下几个方法:

  • 将元素添加进Set<E>:boolean add(E e)
  • 将元素从Set<E>删除:boolean remove(Object e)
  • 判断是否包含元素:boolean contains(Object e)

Set实际上相当于一个只存储key、不存储value的特殊Map。放入Set的元素和Map的key特点类似,不允许重复。所以,我们常用Set用于去除重复元素,并且元素也需要正确实现equals()和hashCode()方法,否则该元素无法正确地放入Set。


Map接口

Map<K,V>是一种键-值映射表,当我们调用put(K key,V value)方法时,就把key和value做了映射并放入Map。当我们调用V get(K key)时,就可以通过key获取到对应的value。如果key不存在,则返回null。和List类似,Map也是一个接口,最常用的实现类是HashMap。

线程不安全

HashMap

特点:无序、查找效率高,是根据key查找value

数据结构:数组(哈希表)+链表(链地址法解决哈希表冲突)+红黑树(自平衡二叉树,提高查找效率)

关键计算:计算key-value键值对再哈希表中的存储位置(桶):

  1. 哈希运算,计算新的哈希值:hash()扰动函数(h=key.hashcode())^(h>>>16),目的是计算新的哈希值,降低哈希冲突的概率
  2. 通过新哈希值,计算下标的位置(桶位置):(n-1)&hash

转换成红黑树的条件:链表的元素个数超过8,并且数组长度大于等于64.

红黑树退化成链表的条件:红黑树中的元素个数少于6

转换为红黑树的优点:

  • 链表过长,会导致搜索效率变低,使用红黑树提高查找效率。
  • 红黑树,是一颗自平衡的二叉查找树,树中所有节点均自动排序,并且自平衡,可以使用二分查找,提高查找效率。

影响性能的关键参数

  • 数组容量:默认为16,容量越大,内存占用越多,产生冲突的概率越小;必须为2的N次幂;每次按照2倍进行扩容,最大容量不超过2的30次幂。
  • 加载因子:默认为0.75,加载因子越高,代表利用率越高,产生冲突的概率越高;加载因子越低,代表利用率越低,产生冲突的概率越低。

扩容条件:

  1. 默认情况下,数组长度为16(自定义时们必须保证数组长度为2^n次幂)
  2. 达到扩容阈值threshold,按照2倍进行扩容
  3. 链表长度大于8,数组长度小于64——链表不会转换成红黑树,执行数组扩容

LinkedHashMap

特点:有序

数据结构:HashMap的子类,多维护了一条双向链表,保存顺序。

TreeMap

特点:自动按照key排序

数据结构:红黑树

线程安全

Hashtable

特点:无序、key和value不允许为null

数据结构:数组+链表

线程安全:通过"synchronized"同步锁实现

ConcurrentHashMap

特点:无序

数据结构:数组+链表+红黑树

线程安全:sychronized同步锁+CAS无锁化编程模型

Collection工具类

封装了集合的常见算法和操作

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓晨CH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值