JAVA常用集合实现方式的总结

    请尊重他人劳动成果,请勿随意剽窃,转载请注明,谢谢! 转载请注明出处: http://blog.csdn.net/evan_man/article/details/50835507
    本篇主要是对之前的集合源码阅读系列博客的一个总结,如果没有看过之前的博客或者集合源码,很可能看不懂下面的内容。
    文章开始之前,首先简单回顾一下数据结构中定义的物理结构和逻辑结构。
    物理结构:
  • 顺序存储结构
  • 链式存储结构
    逻辑结构
  • 线性结构:一般线性表、栈、队列、字符串、数组、广义表
  • 非线性结构:树、图
    关于集合命名规则,Java中集合的命名大体上可以归类为 AbEf的形式:  Ab代表物理结构,Ef代表逻辑结构,但是这只是对于大多数的集合名有效。如ArrayList,就是用数组实现线性表;而LinkedList就是用链表实现的线性表。
    最后补充一个必知的native方法:
  • arraycopy()@java.lang.System.class
  • public static native void arraycopy(Object src,  int  srcPos, Object dest, int destPos, int length);
  • 功能:将src中的srcPos~srcPos+length-1的数据复制到dest中的destPos~destPos+length-1位置处;

顺序存储结构实现的集合(即数组实现)

A、B、C、D是按照底层实现的相似性进行划分的

PartA-线性表&栈

ArrayList:
  • 内部存储了一个Object[];提供随机访问;
  • ArrayList中数据的移动大多是利用System.arraycopy();方法实现,该方法是native方法;
  • 扩容;
    • 默认大小是10;
    • 最大容量Integer.MAX_VALUE - 8;
    • 扩容触发条件:当前要求容量大小大于当前容量大小
    • 正常扩容newCapacity = oldCapacity + (oldCapacity >> 1);
    • 使用System.arraycopy将数据全部移动到新的数组中
  • 缩容:手动调用trimToSize()方法,会缩到当前数组实际存储的数据大小
Vector:
  • Vector与ArrayList共同点
    • 两者实现的功能相同,方法的实现也基本一致;
    • 都具有SubList内部类和Itr迭代器内部类
    • 都能够扩容和缩容
  • Vector与ArrayList区别:
    • 线程安全:Vector对大部分的方法使用了关键字Synchronized声明
    • 额外的%element%方法:这些方法会被Stack类所使用;
Stack:
  • Stack主要使用的是Vector<E>的方法进行具体的实现,自身没有状态量
  • 线程安全:继承Vector,故也是线程安全的
  • pop方法:使用elementAt+removeElementAt
  • push方法:使用addElement
  • search方法:从后往前搜索调用lastIndexOf

PartB-队列

ArrayDeque:
  • 存储有一个Obejct[]数组;数组长度必须是2的幂次,因为这样就方便取余运算;
  • 有一个head和tail指针;
  • tail =(tail+1)&(elements.length-1)
  • head =(head+1)&(elements.length-1)
  • size = (tail-head)&(elements.length-1)
  • 扩容:
    • 正常扩容后大小为原数组长度2倍
    • 利用System.arraycopy方法实现
PriorityQueue:
  • 类中存储有一个Object[]数组
  • size为当前数组中存储的数据的大小
  • 存入的数据类型要求实现了Comparable接口
  • 数据的添加和删除操作伴随着调堆的操作;
  • 具有扩容功能:
    • 扩容大小:当前大小的2倍或者1.5倍
    • 扩容条件:准备存入的数据量大于当前Obejct数组的长度;

PartC-Map

HashMap:
  • 内部存储了一个Node<K,V>[] table;
  • 内部有定义一个Node内部类和TreeNode内部类;后者是一颗红黑树
  • 数组的下标(散列值)等于hash(key)&n-1;
  • 会自动扩容:
    • 默认大小是16;大小必须为2的幂
    • 最大容量是1<<30
    • 填装因子为0.75
    • 扩容触发条件:一旦当前存储数据大于门限(容量*填装因子)
    • 正常扩容newCapacity = oldCapacity<<1;
    • 每个桶中的数据分成两拨一波继续留在原散列值下面,一波移动到原散列值+oldCapacity位置处
  • 不能自动减容;
  • 红黑树的利用:
    • 当一个桶中的元素大于某个固定值,则将该桶中的数据由链表存储结构,转换成红黑树存储结构;
    • 在此之后的所有操作交由红黑树进行处理;
    • 在扩容的时候,对红黑树进行拆分的过程中,如果最后元素个数小于固定值,则将红黑树存储结构转换为普通链表存储结构
HashTable:
  • 基本与HashMap类似;
  • 线程安全:HashTable的大部分方法使用了Synchronized关键字进行标记
  • 没有红黑树:HashTable对桶中数据的存储没有使用红黑树,因此效率相对于hashmap会差一点
  • 不支持存储null:会抛出异常
HashSet:
  • 内部存储了一个HashMap<E,Object>变量
  • 一个简单版本的HashMap;
  • 只使用了key而没有使用value部分,value永远存的都是固定的Object

PartD-String

String
  • 内部存储的是一个final char[]字符数组;
  • 因此不能修改它指向的字符数组
StringBuidler
  • 内部存储的是一个char[]字符数组
  • 因此可以修改里面的字符
  • 对于数组的拷贝大多依赖于System.arraycopy的方法
  • 扩容
    • 默认大小为16
    • 容量最大值:Integer.MAX_VALUE
    • 正常情况扩容大小:int newCapacity = value.length * 2 + 2;
    • 扩容触发条件:准备存储的字符数大于当前数组的长度
  • 缩容:
    • 为当前存储数据的大小
StringBuffer
  • 与Stringbuilder类似
  • 线程安全:方法大多使用了Synchronized关键字标记

链式存储结构实现的集合(即链表实现)

A、B是按照底层实现的相似性进行划分的

PartA-Map

TreeMap:
  • 定义了一个内部类Entry<K,V>;该节点定义了这课红黑树的存储结构;
  • 存储有该树的根节点;要删除这颗树只需要将root指向null即可;GC之后便会回收该红黑树,造成其它节点的引用不可达
  • 每次插入、删除一个树中节点时;都需要对这颗红黑树进行一定的调整;
TreeSet:
  • 内部存储了一个TreeSet<E,Object>对象
  • 一个简单版本的TreeMap;
  • 只使用了key而没有使用value部分,value永远存的都是固定的Object

PartB-List&Map
LinkedList:
  • 内部存储一个双向链表;所有的操作都是对该链表进行操作 
LinkedHashMap:
  • 数据存储是HashMap只是有在其上面加了一个链表结构,每次对该HashMap中的数访问一次都会改变链表结构;保证链表中的最后面的数据是最近刚被访问的那个节点的数据。具有LRU算法特性


















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值