浅析Java集合

概述

Java集合是Java类库中提供的一些现成的数据结构并实现了这些数据结构的常用的操作(e.g. 增删改查),主要分为两大类,一类是实现了Collection接口的类,另一类是实现了Map接口的类

实现了Collection接口的类

在Java中直接实现类Collection接口的类是AbstractCollection类,常见的数据结构例如:List,Set,Queue,这些数据结构都是继承了AbstractCollection类的,同时也实现了相对应的接口(List,Set,Queue)这些接口也都继承了Collection接口

ArrayList

ArrayList是基于数组为原形,实现了自动扩容方法的List,继承了AbstractList

//构造方法
ArrayList<E> list = new ArrayList<>(int size);

这个构造方法会实例化一个Object的数组,在未指定大小时,默认大小为10

//插入元素
list.add(E);
//指定位置插入元素
list.add(int index,E)

当调用add方法时,会先基于当前的大小+1,产生一个叫minCapacity的变量
minCapacity<Object数组大小的时候,则在直接插入这个数组
minCapacity>Object数组大小的时候,创建一个新的数组,大小为当前数组大小x1.5+1,如果还是小于minCapacity,则将minCapacity作为新的数组大小,扩容后调用Arrays.copyOf来将原来数组中的数据复制到新的数组中

//删除元素
list.remove(E)

如果要删除的对象为null则遍历数组中已有值的元素,比较其是否为null,如果要删除的对象不为null 则通过元素的equals方法来比较。找到后,使用fastRemove方法来删除元素。
fastRemove方法:将要删除元素后面的元素往前复制一位,并将最后一个元素值设为null,释放引用

//删除指定位置元素
list.remove(int index,E)

该方法性能更好,需要检查index是否在数组容量范围内,但是不用再查询对象的位置

//获取单个对象(需要检查index是否在数组容量范围内)
list.get(int index)
//获取元素所在的位置(从前往后搜索)
list.indexOf(E)
//获取元素所在的位置(从后往后前搜索)
list.lastIndexOf(E)
//遍历元素(迭代器)
Iterator<E> it = list.iterator();
while(it.hasNext()){
	Object e = it.next();
}
//遍历元素(加强forloop)
for(Object e:list){
	//e.todo
}

当用调用next方法时,会比较创建iterator时当modCount于当前的modCount,如果不同,说明list的大小发生了改变(增、删)并抛出ConcurrentModificationException,如果相同iterator则调用get方法来获取元素

//判断元素是否存在
list.contains(E)

注意要点
ArrayList会在插入元素时扩容,在删除元素时并不会减小数组的容量(可以手动调用trimToSize()方法来缩小容量)
ArrayList是非线程安全的

LinkedList

LinkedList是基于双向链表的实现的,继承了AbstractList,在LinkedList中用一个内部类Entry来代表集合中的元素

//构造方法
LinkesList<E> list = new LinkedList<>();

会先创建一个element,next,previous属性为nullEntry,并赋值给全局属性header,并将headernextprevious都指向header形成一个双向链表闭环

//插入元素
list.add(E);

先创建一个Entry对象将next指向headerprevious指向header.previous完成设置后,将当前元素的后一个元素的previous指向新增的元素,前一个元素的next指向新增元素,保存双向链表闭环

//删除元素
list.remove(E)

同样要遍历整个集合,遍历和匹配的元素的方法和ArrayList基本相同,删除时直接当前元素的所有属性设置为null并将后前的元素连接起来

//删除元素
list.get(int index)

先判断index是否在返回内,如果超过范围就抛出异常IndexOutOfBoundException,在返回为则再次判断index是否小于集合大小的一半,如果小于则从头开始往后找(通过next),反之则从尾往前找(通过previous)

//遍历元素(迭代器)
Iterator<E> it = list.iterator();
while(it.hasNext()){
	Object e = it.next();
}
//遍历元素(加强forloop)
for(Object e:list){
	//e.todo
}

同样会检查modCount,不同的是可以往前遍历通过hasPreviousprevious完成向前遍历

//判断元素是否存在
list.contains(E)

注意要点
LinkedList同样是非线程安全的

Vector

VectorArrayList一样是基于数组方式实现的,功能也基本一直,不同的是Vector是线程安全的,扩容机制也不同
如果capacityIncrement大于0,扩容时新数组的大小等于当前的size+capacityIncrement
如果capacityIncrement小于0,扩容时新数组的大小等于当前的size的两倍,可以通过传入capacityIncrement来控制扩容

Stack

Stack继承来Vector并增加了pop()push()peek()方法
push():通过Vectoradd方法来完成
peek():获取当前数组的大小,并返回最后一个元素
pop():调用peek()方法,并删除数组的最后一个元素

实现了Set接口的类

SetList的区别是Set不运行重复的元素存在

HashSet

基于HashMap来实现的,构造HashSet时,实际上构造出一个HashMap,因此所有的操作都是基于的HashMap
add(E)方法:调用了HashMapput(key,value)方法来实现,keyvalue都是传入的对象
HashSet中的元素是没有顺序的,因此不能使用get(int index)来获取指定位置的元素
HashSet是非线程安全的

TreeSet

TreeSet是基于的TreeMap实现的,TreeSet支持排序,同样不支持get(int index)方法
可以通过传入Comparator来实现对TreeSet的排序和按照(降序/升序)遍历

注意要点
TreeSet非线程安全

实现了Map接口的类

Map是一种存储键值对的数据结构

HashMap

是最常用的实现类Map接口的类

//构造方法
HashMap<K,V> map = new HashMap<>();

默认的loadFactor为0.75,threshold为12,并创建大小的为16的Entry对象数

//插入元素
map.put(Object key,Object value);

通过hash出来的值来确定存储的位置,确定位置后,获取相对应的Entry对象,并遍历这Entry数组,如果key相对或者equalsEntry对象,则替换对象的值,如果没有则创建一个新的Entry对象
Entry数组中已用大小大于threshold时,数组扩大为当前大小两倍,并对所有的元素重新hash,并填充数组,最后重新设置数组
HashMap是通过链表的方式来解决hash冲突的

//获取元素
map.get(Object key);

与put方法过程类似,通过hash来找到位置,并遍历数组来找到元素

//删除元素
map.remove(Object key);
//判断元素是否存在
map.containsKey(Object key);

通过调用getEntry方法来完成与get方法过程基本相同

注意要点
HashMap非线程安全

TreeMap

TreeMap是基于红黑树实现的,是支持排序的Map

//插入对象
map.put(Object key,Object value);

先判断红黑树的root是否为null,如果是则新建一个Entry并赋值给root,如果不是,则通过Comparator来比较key来决定放在树的左边还是右边,如果key已经存在则更新对应的value,不存在则新建一个Entry对象并将其parent属性设置好

//获取元素
map.get(Object key);

基于红黑树的查找

注意要点

TreeMap是非线程安全

小结

实现了List接口的类在元素数量较大时,查询和删除元素性能较差,基于实现类MapSet的类性能较好,因此对象查询和删除较多的的场景适合使用MapSet

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值