Java集合类汇总

一、集合类层次关系

如图所示:图中,实线边框的是实现类,折线边框的是抽象类,而点线边框的是接口

下面的图更详细,右键在新标签中打开图片查看

23142347_bIhp.jpg

Collection接口是集合类的根接口,Java中没有提供这个接口的直接的实现类。但是却让其被继承产生了两个接口,就是Set和List。Set中不能包含重复的元素。List是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式。

Map是Java.util包中的另一个接口,它和Collection接口没有关系,是相互独立的,但是都属于集合类的一部分。Map包含了key-value对。Map不能包含重复的key,但是可以包含相同的value。

Iterator,所有的集合类,都实现了Iterator接口,这是一个用于遍历集合中元素的接口,主要包含以下三种方法:
1.hasNext()是否还有下一个元素。
2.next()返回下一个元素。
3.remove()删除当前元素。

二、几种重要的接口和类简介

1、List(有序、可重复)
List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。

2、Set(无序、不能重复)
Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。

3、Map(键值对、键唯一、值不唯一)
Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。

三、遍历

 在类集中提供了以下四种的常见输出方式:

1)Iterator:迭代输出,是使用最多的输出方式。

2)ListIterator:是Iterator的子接口,专门用于输出List中的内容。

3)foreach输出:JDK1.5之后提供的新功能,可以输出数组或集合。

4)for循环

代码示例如下:

 for的形式:for(int i=0;i<arr.size();i++){...}

 foreach的形式: for(int i:arr){...}

 iterator的形式:
Iterator it = arr.iterator();
while(it.hasNext()){ object o =it.next(); ...}

四、集合类内部源码分析

该部分转自http://www.coselding.cn/article/2016-05-31/-1127151883.html,如果你没看过JDK源码,建议打开Eclipse边看源码边看这篇文章,看过的可以把这篇文章当成是知识点备忘录。

   JDK容器类中有大量的空指针、数组越界、状态异常等异常处理,这些不是重点,我们关注的应该是它的一些底层的具体实现,这篇文章就是我看完这部分源码之后的觉得有用的知识点总结,渣渣一枚,大神勿喷。


ArrayList


1、 容器默认大小为10,位置不够了自动扩增,每次增加当前长度的一半;(扩增时用Arrays.copyOf进行扩增)
2、 数组容量扩增到Integer.MAX_VALUE-8的时候,就会开始限制数组扩充,超过Integer.MAX_VALUE的时候,抛内存溢出异常;
3、 clone是浅拷贝,List中的引用指向的还是相同数据;
4、 线程不安全的;
5、 迭代器中的expectedModCount和modCount:迭代器初始化时,会用modCount去初始化expectedModCount,在迭代器的操作中都要检查这两个值的等值性,不想等抛出ConcurrentModificationException异常表示当前List正在被修改,为什么呢?如下:
List本身的add和remove操作时都会修改modCount的值,如果在迭代器循环迭代过程中调用了List本身的add和remove方法就会导致两个值不想等而抛出异常,而迭代器本身的remove则不会有这个问题,它会在remove完成后重新更新一遍expectedModCount保持两个值的等值性。
6、 ListIterator和普通迭代器类似,只是多了双向迭代的功能;
7、 ArrayList本身的sort其实是调用Arrays.sort传入比较器实现的;


LinkedList


1、 没ArrayList那么麻烦了,不需要扩容什么的,处理好指针引用的指向关系就行。
2、 内部维护size,first,last,支持双向遍历,链表增删操作时,注意维护好这三个值;
3、 线程不安全;
4、 链表支持链表头增删,链表尾增删,指定节点前或后增删;
5、 List中的Node为private内部类,无法手动创建,这是为了保证用户拿到的所有Node都是LinkedList生成的,即其成员next和pre为正确指定的值;
6、 LinkedList中的Element元素支持插入空值,和HashMap一样;
7、 LinkedList的迭代器中也有expectedModCount检测链表的修改状态,迭代器循环迭代时只能用迭代器的remove方法;
8、 clone为浅拷贝;
9、 LinkedList可以当Deque用,因为有实现相应接口;


HashMap


1、 HashMap支持null的key和value;
2、 Equals会比较两个Map地址,若地址不等,则迭代比较每个元素,都相同才返回true;
3、 Hashcode为每个元素Entry的hashcode的和;
4、 Entry是一个键值对封装体,都复写了Object的很多相应方法,建立了K-V映射关系;
5、 Clone浅拷贝;
6、 HashMap默认大小16,最大大小2的30次方;
7、 结构:一开始使用数据结构书中的以链表为元素的数组存储元素,元素得到的哈希值相同的放在数组中哈希值对应位置的链表的末尾,操作很简单,但是有弊端,当同一个哈希值存在的元素过多的话,查询速度很差,这不是是同哈希表想看到的结果,这时候采取的是转换成红黑树的办法。
8、 填充比:其中设置一个填充比,当链表中的元素数量超过填充比对应的值的时候,链表会转换成红黑树,提高查询效率,填充比在HashMap的构造函数可以设置,默认0.75。
9、 临界值:数组中的位置使用率达到临界值的时候,数组会扩容;
10、 线程不安全;
11、 Put方法:hashCode()计算Key的哈希值,从而找到数组中的元素位置,
(1)该位置中没元素,直接放入;
(2)该位置中有元素调用equals,对比Key是否真的相等,若相等,用新的Value替代旧的Value;
(3)若equals不相等(冲突),则把这个元素放到原来的元素后面(链表)
注:因此作为HashMap的Key的数据类型,有必要好好考虑Key的hashCode和equals重写,尽量避免冲突,提升效率;
12、 resize():重新调整数组大小,新旧数组复制,较耗时;
13、 get()方法:计算key的hashCode,从而找到数组位置,对比数组中元素第一个节点和key是否一致,一致返回该节点,否则判断节点是否是红黑树节点来分类讨论(红黑树按照红黑树的方式查找该key,链表则循环下去接着找),如果找到key一致的则返回,否则返回null,表示该key暂时还没有值;
14、 put()方法步骤:
(1)检查表是否需要扩容;
(2)检查hashCode指定位置是否需要newNode;
(3)数组中指定位置已经有节点了,先检查和第一个节点是否一致,一致则找到节点;
(4)不一致,检查是否为红黑树,通过红黑树查找节点;
(5)不是红黑树的,接着链表查找,找到元素节点或者找不到新建节点,并检查是否需要转换成红黑树,默认长度为8时变;
(6)若找到的节点不为空,赋值Value;
(7)检查数组是否需要扩容;
(8)返回oldValue;
15、 Remove()方法:通过hashCode找到数组位置,对比第一个节点,再对比红黑树或链表,找到节点之后删除节点并返回;
16、 HashMap的增删方法也和List一样有ConcurrentModificationException异常,使用迭代器需注意;

ps:JDK1.8对HashMap的改进强烈建议看一下这篇博文

http://blog.csdn.net/zdsicecoco/article/details/51775545,尤其是 扩容机制。1.8主要改进除了引入红黑树,还改进了扩容机制,利用位计算非常巧妙的回避了再扩容时每个元素重新计算hash,重新插入HashMap中,大大地提高了性能


LinkedHashMap


1、 HashMap的子类;与HashMap区别是,在HashMap基础上LinkedHashMap内部多了一个双向循环链表的维护,该链表是有序的,可以按元素插入顺序或元素最近访问顺序(LRU)排列
2、 存储方式和HashMap都一样,都是直接继承的,只是在put元素的时候顺带存储了元素的存入先后顺序,在迭代器遍历的时候,输出的结果顺序是和插入元素时的插入先后顺序一致的;
3、 有ConcurrentModificationException;
4、 可以设置插入元素时自动删除最旧的元素;


TreeMap


1、 实现了NavigableMap接口(是SortedMap的子接口);
2、 使用红黑树作为底层实现,排序平衡树,有序,提供一系列有序集合才有的方法(获取第一个,获取某一范围内的),排序按照Key为标准进行比较;
3、 默认为升序排序,descendingMap()返回降序排序的实例;
4、 维护了比较器comparator、树根节点root、size属性;
5、 putAll方法时,先判断传入的集合是否是SortedMap,是的话利用比较器直接通过红黑树批量插入再调整红黑树,较为高效,若不是,则遍历整个集合把每个元素一一插入;
6、 元素间比较:若内部比较器不为空,则用内部比较器进行key的比较,否则元素本身要实现Comparable接口以提供比较;
7、 不允许key为空;
8、 Entry就是红黑树的节点;
9、 Put:按照排序树查找key,找到直接修改value,没找到就插入一个节点,并进行红黑树调整;
10、 Remove:按照key查找相应的Entry,再把这个节点从红黑树中删除,并进行红黑树调整;
11、 浅拷贝;
12、 Replace要求提供的oldValue要和key对应的Entry的value一致才能成功替换;
13、 非迭代器的增删方法也有ConcurrentModificationException;


HashTable


1、 Dictionary的子类;(因为遍历该集合要用到Enumeration迭代器)
2、 浅拷贝;
3、 Keyset,ValueSet,EntrySet三种值的获取方式使用了标记位的方式,代码重用,不像之前的,每个都各写一个;
4、 Map操作是方法粒度的线程安全的;
5、 不允许key为空或value为空;
6、 遍历迭代器使用Enumeration方式;(Iterator是Enumeration的升级版,在其中加入了ConcurrentModificationException保证Fail-Fast,但是遍历性能却下降了。在HashTable、Vector中已经用synchronized保证了线程安全,故仅需使用更高效的Enumeration遍历即可)
7、 HashMap的get方法返回null表示没有该key或者该key对应的value为空;而HashTable的get返回空则一定是没有该key;

HashTable详细代码可查阅:http://blog.csdn.net/zheng0518/article/details/42199477


IdentityHashMap

 

1、  底层用一个数组实现存储,下标0,2,4,6…存储key,下标1,3,5,7…存储value

2、 和WeakHashMap一样,用一个特殊值表示null的key

3、put时根据hash来确定位置,当hashcode相等,hashCode采用native底层实现,根据内存地址计算哈希值,出现冲突的时候,通过线性探索发解决冲突问题 ;

4、remove时,将相应位置的值赋空,并把后面的元素往前移

5、比较的是引用相等,IdentityHashMap与常用的HashMap的区别是: 
前者比较key时是“引用相等”而后者是“对象相等”,即对于k1和k2,当k1==k2时,IdentityHashMap认为两个key相等,而HashMap只有在k1.equals(k2) == true 时才会认为两个key相等。 
2、 线程不安全;
3、 浅拷贝;


WeakHashMap


1、 允许Key为空,但是在存储底层是使用了内部一个特殊Object对象来表示Null的Key;
2、 维持了一个弱引用队列,Map的Entry就是一个弱引用对象;
3、 底层实现和HashMap基本一致,只是tables中的引用对象都是弱引用;
4、 弱引用:不能保证引用还存在时避免引用指向的内存不被垃圾回收机制回收;
5、 Entry在new的时候创建了一个弱引用对象并加入弱引用队列中,该弱引用指向的内存空间随时可能被回收,被回收后再使用该弱引用返回null,并且内部的多数Map操作都附带了弱引用回收操作,把那些已经被回收的弱引用从弱引用队列中移除,不影响该弱引用在hashTable中链表指向的下一个节点。

6、主要应用场景:做缓存


HashSet


 底层由HashMap提供支持,实现容器中元素单一出现的目的。其实就是定义一个私有的HashMap变量,key的值用Set中的key,value用一个叫Object的PRESENT常量代替,利用了HashMap中key不重复的特性。


TreeSet

 

1、 有序的Set,默认根据自然排序,若有特殊需求,要实现Comparable接口,要求compareTo和equals的返回结果一致;

2、底层为TreeMap提供支持,Set中的元素就是Map的Key;value用一个叫Object的PRESENT常量代替
3、 具有有序集合的一些性质:比如提取比某个值大的子集合,提取在某一范围内的子集合等有序才具有的操作;
4、 实现了NavigableSet接口,NavigableSet是SortedSet的子接口;
5、 底层为TreeMap提供支持,Set中的元素就是Map的Key;
6、 浅拷贝;


Queue


   单向队列接口,队头取出,队尾加入。实现子类是LinkedList


Deque


   双向队列接口,双向添加删除,分别有两个方向的迭代器。继承自Queue,实现子类也是LinkedList


Vector


   和ArrayList都一样,但是提供了方法粒度级别的同步机制,大量的synchroniaed方法。


Stack


1、 继承于Vector,线程安全,底层数组实现,自动扩张;
2、 栈顶增删查操作(基本上就是调用Vector的函数),并提供整栈元素搜索功能。


Collections


1、 封装了集合的很多常用工具静态方法,二分查找、排序、子集合、替换、比较等;
2、 synchronizedCollection等一系列的方法提供了将普通集合转换成代码块粒度的同步,使用mutex进行同步;
3、 singleton提供了集合中单元素的集合静态方法;
4、 unmodifiableCollection提供了将所给集合变成不可写的集合的方法;
5、 等等。。。。。


Arrays


1、 数组的常用工具静态方法,排序,二分查找,数组填充,子数组提取,深equals,深hashCode,数组复制等;
2、 基本数据类型使用插入排序(长度小于7)和快速排序(长度大于7);
3、 Object的数组使用归并排序(稳定排序);


Array


   反射包中的Array,表示所有的数组,由native本地方法实现,一个数组就相当于是一个Object。原生数组中的相关调用就相当于是调用这个类中的相关方法。

更多系列博客可查看http://www.cnblogs.com/skywang12345/p/3323085.html


String


1、 对char数组的封装,相当于是一个元素为char的ArrayList,没有长度自动伸缩功能;
2、 封装了字符串操作的常用方法,底层实现都是在反复操纵char[];
3、 Equals重写成了char[]的各个元素;
4、 hashCode重写成char[]计算的哈希值;
5、 split通过不断查找切割子串的位置来substring字符串得到字符串分割结果数组;
6、 String长度创建后不变,改变的话就是整个char[]变了,不能对char[]数组中的指定下标进行随机修改;

7、因为内部char[]是final的,所以String是线性安全的


StringBuilder


1、 底层char[]实现,相当于ArrayList的char元素的实现,提供元素增删改查;
2、 线程不安全;
3、 可设定初始长度,防止扩充长度的资源消耗;
4、 可修改指定下标的char值;
5、 动态修改动态添加,长度可变;


StringBuffer


   与StringBuilder继承相同抽象类,底层相同实现,但是StringBuffer是线程安全的。


ThreadLocal


1、 多线程同时访问统一共享属性的时候产生的线程安全问题的一种解决方案,适用于每个线程对这个共享属性的修改都不会影响到其他线程,即不需要线程间通信的这种情况;这样做是为了避免使用同步锁导致的效率问题(每个线程各创建一个共享数据的副本分别服务于各自的线程);
2、 每个Thread内部有两个类似Map的属性ThreadLocalMap,通过Thread.currentThread();获取当前的线程实例,再获取本线程中的Map实例,通过对这个Map中进行数据的增删,实现共享数据的副本和线程绑定的目的,从而在一定程度上避免线程安全问题。

 


额外收获:
1. transient:关键字,修饰的变量不参与序列化操作;
2. volatile:关键字,修饰的变量在每次使用时都会去查询其最新值,防止编译器优化使用缓存错过他的最新值;
注:这里的每次使用指的是从堆区复制这个值的瞬间,当一个线程访问时,会从堆区拷贝这个值一份到自己的线程栈中,之后线程就只修改线程栈中的这个值,对于堆区的值没有修改,这是volatile的局限性。详细看:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html
3. 集合equals判断:先判断地址是否相同,再判断类型是否相同,再判断size,之后判断集合中每个元素是否相同;
4. 集合hashCode:集合中每个非空元素的hashCode之和;
5. Remove如果删除了集合中没有的元素,集合没有任何改变,返回false;
6. HashMap、LinkedHashMap、TreeMap区别(迭代遍历顺序):
   HashMap存储和查询顺序根据Hash而定,顺序不确定;
   LinkedHashMap:按照元素插入先后顺序;
   TreeMap:按照元素Key比较顺序,或临时设定的比较器决定的顺序输出;
7. Comparable和Comparator:
   Comparable是Entity元素的可实现接口,实现该接口的Entity在和本类型的其他Entity比较时就是通过该接口的compareTo方法进行比较;
   Comparator:提供给集合的比较器接口,该比较器可以通过传入相同类型的两个对象进行compare比较并返回相应值判断出大小关系(通常保证比较结果要和该类型的equals返回结果相一致)。


参考博客:
1. http://zengzhaoshuai.iteye.com/blog/1130376
2. http://mikewang.blog.51cto.com/3826268/880775/

转载于:https://my.oschina.net/zlb1992/blog/864512

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值