java集合框架

java集合

概述

  • 什么是集合

集合是将对象集合在一起存储的容器。

  • 为什么要用到集合?

之前我们保存多个数据使用的是数组,而数组有下面这几个缺点:

  1. 长度固定。如果为了长度够用往往会创建一个比实际需要的数组长的数组,会导致内存的浪费。
  2. 存储的元素类型要相同。一个数组只能存一种类型,如果有很多种类型要存就要创建很多个数组了。
  3. 数组的增删改查比较麻烦,没有现成的方法。

而集合就很好地解决了以上这些数组的缺点,但是集合只能存放引用类型,而数组什么都可以存放。

  • 集合体系图

img

其中最下层为Collection接口中常用的实现子类,List、Set为Collection的两个子接口,都为单例集合。

img

Map体系中常用的集合体系结构如上,都为双例集合。

详细体系图

img

Collection体系

  • Collection接口实现类的特点

    1. 因为是接口类,不能实例化,也没有可实例化的子类,只能通过它的可实例化的子子类实现。
    2. 实现的子类可以存多个元素,每个元素可以是Object型
    3. List分支的Collection的实现类可以放重复的元素,且元素有序,有下标
    4. Set分支的Collection的实现类不可以放重复的元素,且元素无序,无下标
  • 常用方法

boolean add(Object obj) //添加一个对象。
boolean addAll(Collection c) //讲一个集合中的所有对象添加到此集合中。
void clear() //清空此集合中的所有对象。
boolean contains(Object o) //检查此集合中是否包含o对象。
boolean equals(Object o) //比较此集合是否与指定对象相等。
boolean isEmpty() //判断此集合是否为空。
boolean remove(Object o) //在此集合中移除o对象。
int size() //返回此集合中的元素个数。
Object[] toArray() //姜此集合转换成数组。

迭代器

为什么跌代时只能用iterator.move,不能用集合的move()方法

List接口

常用方法(相比Collection多了的用索引的方法)

List接口的实现子类

ArrayList

特点:有序,可重复,可添加null,有下标,不安全,查改快,增删慢

常用方法(基本和List没多大出入吧)

无参构造的初始容量,0

扩容机制(源码)0->10->每次1.5倍 or 初始size->每次1.5倍

Vector

特点:有序,可重复,可添加null,有下标,线程安全(有synchronize修饰),查改快,增删慢

常用方法

无参构造的初始容量,10

扩容机制跟ArrayList源码差不多,10->每次2倍 or 初始size ->每次2倍

LinkList

特点:以链表形式存储,增删快,查改慢,线程不安全(前面两个都是以数组实现的)

常用方法

无参构造,啥也不干

add:默认尾插

插入删除机制:基本的链表操作,看源码

Set接口

特点:元素无序,不重复,无下标

常用方法:基本都是Collection继承下来的

Set接口的实现子类

HashSet

存储机制:就是HashMap->数组+链表+红黑树

无参构造:构造一个默认容量为0HashMap,第一次扩容容量变为16

添加元素机制(源码):

​ 计算hash值,在用hash值计算数组索引值,数组对应位置有无值,无 -> 直接加,有 -> 比较hashcode和equals(不同类的这两个可能不一样,怎么重写取决于需求,或者没重写就是直接比较引用是否相同),等就不加,不等就加,加完后判断size是否到阈值threshold(容量*加载因子),到了就扩容,两倍扩容。

​ 还有一个TREEIFY_THRESHOLD = 8,如果数组中的链表有元素达到这个阈值,而数组容量达到64,就将链表转为红黑树,如果数组容量没到64,就只扩容数组(hash值相同的不同元素就继续加到那个8的链表后)

添加的时候,用到的hash值并不是直接用的key.hashCode(),还经过了一些处理。

LinkedHashSet

底层维护的是一个LinkedHashMap,其实在下一层也是HashMap(HashMap的一个子类)

存的是LinkedHashMap$Entry

LinkedHashMap E n t r y 继 承 了 H a s h M a p Entry继承了HashMap EntryHashMapNode,多了before和after两个引用,用来做双链表的前后指针

一个数组+双链表,底层添加机制与hashMap差不多,都是重复就不添加了,判断重复和添加的位置计算都是一样的,不一样的是它的加入顺序和取出顺序一致。

TreeSet

底层是TreeMap(红黑树),跟HashMap也差不太多,将value定死,只把要加的对象以key加入。

主要区别是创建对象时一般需要传入一个Comparator比较器,用来对加入的对象(都是同类型的对象)给出比较方法,不传传进比较器的话那就要求加入的对象实现Comparable接口,以重写的toCompare方法进行比较。

比较如果结果为零就认为相同不加入key,更新对应的value,当然这里的value写死了,所以就是不加入key;如果比较结果大于零,就走右孩子,如果右孩子为null就加入成为右孩子,不为null就再跟这个右孩子进行比较;如果比较结果小于零就走左孩子,左孩子为null就加入为左孩子,不为null就再跟这左孩子比较;以此类推,最后不是比到有相同不加了,就是找到相应null的位置加入了

最后在调用fixAfterInsertion()调整红黑树

Map体系

HashMap$Node存k-v值

增加是put(k, v);

Map$Entry

EntrySet里面存放的实际运行对象是HashMap$Node(可以通过getClass得知),因为Node实现了Entry的接口,所以可以将EntrySet里面的元素转型为Entry,就相当于EntrySet里都是Entry了

为什么要放Entry中?

​ 因为Entry中有getkey,getvalue两个方法,方便遍历Map

Map方法中keySet()返回一个存有全部key的Set,这些key都不是重新创建的对象,都是指向跟Node里面指向相同的key,values()返回Collection,存储跟key一样。

HashMap

更HashSet机制基本一样,这里就不在重复了

Hashtable

不能存key或value是null的,效率慢

线程安全,初始容量为11,每次扩容是原来的两倍加一

现在基本不用了

properties

Hashtable的子类

不能存key或value是null的

常用于配置文件的读取

TreeMap

跟TreeSet机制基本一样,就不重复了。

不在重复了

Hashtable

不能存key或value是null的,效率慢

线程安全,初始容量为11,每次扩容是原来的两倍加一

现在基本不用了

properties

Hashtable的子类

不能存key或value是null的

常用于配置文件的读取

TreeMap

跟TreeSet机制基本一样,就不重复了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值