整个Java集合框架图以下所示。线比较多,但各个接口及实现类之间的关系仍是比较清楚的。算法
(1)长度区别。数组长度不可变,集合长度可变。数组
(2)内容区别。数组能够存储基本数据类型和对象引用,集合只能存储对象引用。安全
(3)数组只能存储同一类型的元素,集合能够存储不一样类型的元素。数据结构
Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另外一种是图(Map),存储键/值对映射。多线程
继承关系以下图所示,经常使用的实现类有ArrayList,LinkedList,HashSet,LinkedHashSet。框架
Collection集合的方法以下图所示:函数
Map保存的每项数据都是键值对(key-value),Map中的key是不可重复的,key用于标识集合里的每项数据。性能
其中,HashMap和TreeMap是常常用到的实现类。ui
(1)List和Set的区别spa
此外,
List和Set都继承自Collection接口,Map则不是 。
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引发元素位置改变。
List:和数组相似,List能够动态增加,查找元素效率高,插入删除元素效率低,由于会引发其余元素位置改变。
(2)List
经常使用实现类:
(1)ArrayList:底层数据结构是数组,地址连续,查询快,增删慢,线程不安全,效率高,能够存储重复元素 。
(2)LinkedList 底层数据结构是链表,地址不连续,查询慢,增删快,线程不安全,效率高,能够存储重复元素 。
(3)Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,能够存储重复元素 。
List适用场景分析:
当须要对数据进行屡次访问的状况下选用ArrayList,当须要对数据进行屡次增长删除修改时采用LinkedList。
ArrayList和Vector都是用数组实现的,主要有这么三个区别:
(1).Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不肯定的结果。而ArrayList不是,这个能够从源码中看出,Vector类中的方法不少有synchronized进行修饰,这样就致使了Vector在效率上没法与ArrayList相比;
(2)两个都是采用的线性连续空间存储元素,可是当空间不足的时候,两个类的增长方式是不一样。
*(3)*Vector能够设置增加因子,而ArrayList不能够。
*(4)*Vector是一种老的动态数组,是线程同步的,效率很低,通常不同意使用。
(3)Set
3.1 HashSet底层数据结构采用哈希表实现,元素无序且惟一,线程不安全,效率高,能够存储null元素,元素的惟一性是靠所存储元素类型是否重写hashCode()和equals()方法来保证的,若是没有重写这两个方法,则没法保证元素的惟一性。
具体实现惟一性的比较过程:存储元素首先会使用hash()算法函数生成一个int类型hashCode散列值,而后已经的所存储的元素的hashCode值比较,若是hashCode不相等,则所存储的两个对象必定不相等,此时存储当前的新的hashCode值处的元素对象;若是hashCode相等,存储元素的对象仍是不必定相等,此时会调用equals()方法判断两个对象的内容是否相等,若是内容相等,那么就是同一个对象,无需存储;若是比较的内容不相等,那么就是不一样的对象,就该存储了,此时就要采用哈希的解决地址冲突算法,在当前hashCode值处相似一个新的链表, 在同一个hashCode值的后面存储存储不一样的对象,这样就保证了元素的惟一性。
Set的实现类的集合对象中不可以有重复元素,HashSet也同样他是使用了一种标识来肯定元素的不重复,HashSet用一种算法来保证HashSet中的元素是不重复的, HashSet采用哈希算法,底层用数组存储数据。默认初始化容量16,加载因子0.75。
Object类中的hashCode()的方法是全部子类都会继承这个方法,这个方法会用Hash算法算出一个Hash(哈希)码值返回,HashSet会用Hash码值去和数组长度取模, 模(这个模就是对象要存放在数组中的位置)相同时才会判断数组中的元素和要加入的对象的内容是否相同,若是不一样才会添加进去。
Hash算法是一种散列算法。
Set hs=new HashSet();
hs.add(o);
|
o.hashCode();
|
o%当前总容量 (0–15)
|
| 不发生冲突
是否发生冲突—————–直接存放
|
| 发生冲突
| 假(不相等)
o1.equals(o2)——————-找一个空位添加
|
| 是(相等)
不添加
覆盖hashCode()方法的原则:
一、必定要让那些咱们认为相同的对象返回相同的hashCode值
二、尽可能让那些咱们认为不一样的对象返回不一样的hashCode值,不然,就会增长冲突的几率。
三、尽可能的让hashCode值散列开(两值用异或运算可以使结果的范围更广)
HashSet 的实现比较简单,相关HashSet的操做,基本上都是直接调用底层HashMap的相关方法来完成,咱们应该为保存到HashSet中的对象覆盖hashCode()和equals(),由于再将对象加入到HashSet中时,会首先调用hashCode方法计算出对象的hash值,接着根据此hash值调用HashMap中的hash方法,获得的值& (length-1)获得该对象在hashMap的transient Entry[] table中的保存位置的索引,接着找到数组中该索引位置保存的对象,并调用equals方法比较这两个对象是否相等,若是相等则不添加,注意:因此要存入HashSet的集合对象中的自定义类必须覆盖hashCode(),equals()两个方法,才能保证集合中元素不重复。在覆盖equals()和hashCode()方法时, 要使相同对象的hashCode()方法返回相同值,覆盖equals()方法再判断其内容。为了保证效率,因此在覆盖hashCode()方法时, 也要尽可能使不一样对象尽可能返回不一样的Hash码值。
若是数组中的元素和要加入的对象的hashCode()返回了相同的Hash值(相同对象),才会用equals()方法来判断两个对象的内容是否相同。
3.2 LinkedHashSet底层数据结构采用链表和哈希表共同实现,链表保证了元素的顺序与存储顺序一致,哈希表保证了元素的惟一性。线程不安全,效率高。
3.3 TreeSet底层数据结构采用二叉树来实现,元素惟一且已经排好序;惟一性一样须要重写hashCode和equals()方法,二叉树结构保证了元素的有序性。根据构造方法不一样,分为天然排序(无参构造)和比较器排序(有参构造),天然排序要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素经过比较返回的int值来判断排序序列,返回0说明两个对象相同,不须要存储;比较器排须要在TreeSet初始化是时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法。
set适用场景分析
HashSet是基于Hash算法实现的,其性能一般都优于TreeSet。为快速查找而设计的Set,咱们一般都应该使用HashSet,在咱们须要排序的功能时,咱们才使用TreeSet。
Map 没有继承 Collection 接口, Map 提供 key 到 value 的映射,你能够经过“键”查找“值”。一个 Map 中不能包含相同的 key ,每一个 key 只能映射一个 value 。 Map 接口提供 3 种集合的视图, Map 的内容能够被看成一组 key 集合,一组 value 集合,或者一组 key-value 映射。
(1)Map的主要方法
(2)HashMap和HashTable的比较
(2)TreeMap:
适用场景分析:
HashMap和HashTable:HashMap去掉了HashTable的contains方法,可是加上了containsValue()和containsKey()方法。
HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。HashMap容许空键值,而HashTable不容许。
HashMap:适用于Map中插入、删除和定位元素。
Treemap:适用于按天然顺序或自定义顺序遍历键(key)。
5.线程安全集合类与非线程安全集合类 LinkedList、ArrayList、HashSet是非线程安全的,Vector是线程安全的;
HashMap是非线程安全的,HashTable是线程安全的;
StringBuilder是非线程安全的,StringBuffer是线程安全的。
参考书目及博客:略。