1、Java集合框架概述html
集合能够看做是一种容器,用来存储对象信息。全部集合类都位于java.util包下,但支持多线程的集合类位于java.util.concurrent包下。java
数组与集合的区别以下:算法
1)数组长度不可变化并且没法保存具备映射关系的数据;集合类用于保存数量不肯定的数据,以及保存具备映射关系的数据。数组
2)数组元素既能够是基本类型的值,也能够是对象;集合只能保存对象。安全
Java集合类主要由两个根接口Collection和Map派生出来的,Collection派生出了三个子接口:List、Set、Queue(Java5新增的队列),所以Java集合大体也可分红List、Set、Queue、Map四种接口体系,(注意:Map不是Collection的子接口)。微信
其中List表明了有序可重复集合,可直接根据元素的索引来访问;Set表明无序不可重复集合,只能根据元素自己来访问;Queue是队列集合;Map表明的是存储key-value对的集合,可根据元素的key来访问value。数据结构
上图中淡绿色背景覆盖的是集合体系中经常使用的实现类,分别是ArrayList、LinkedList、ArrayQueue、HashSet、TreeSet、HashMap、TreeMap等实现类。多线程
2、Java集合常见接口及实现类框架
1. Collection接口常见方法(来源于Java API)性能
2. Set集合
Set集合与Collection的方法相同,因为Set集合不容许存储相同的元素,因此若是把两个相同元素添加到同一个Set集合,则添加操做失败,新元素不会被加入,add()方法返回false。为了帮助理解,请看下面代码示例:
public class Test { public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("hello world"); set.add("hello 冰湖一角"); set.add("hello 冰湖一角");//添加不进去
System.out.println("集合中元素个数:"+set.size()); System.out.println("集合中元素为:"+set.toString()); } }
运行结果以下:
集合中元素个数:2
集合中元素为:[hello world, hello 冰湖一角]
分析:因为String类中重写了hashCode()和equals()方法,用来比较指向的字符串对象所存储的字符串是否相等。因此这里的第二个"hello 冰湖一角"是加不进去的。
下面着重介绍Set集合几个经常使用实现类:
1)HashSet类
HashSet是Set集合最经常使用实现类,是其经典实现。HashSet是按照hash算法来存储元素的,所以具备很好的存取和查找性能。
HashSet具备以下特色:
♦ 不能保证元素的顺序。
♦ HashSet不是线程同步的,若是多线程操做HashSet集合,则应经过代码来保证其同步。
♦ 集合元素值能够是null。
HashSet存储原理以下:
当向HashSet集合存储一个元素时,HashSet会调用该对象的hashCode()方法获得其hashCode值,而后根据hashCode值决定该对象的存储位置。HashSet集合判断两个元素相等的标准是(1)两个对象经过equals()方法比较返回true;(2)两个对象的hashCode()方法返回值相等。所以,若是(1)和(2)有一个不知足条件,则认为这两个对象不相等,能够添加成功。若是两个对象的hashCode()方法返回值相等,可是两个对象经过equals()方法比较返回false,HashSet会以链式结构将两个对象保存在同一位置,这将致使性能降低,所以在编码时应避免出现这种状况。
HashSet查找原理以下:
基于HashSet以上的存储原理,在查找元素时,HashSet先计算元素的HashCode值(也就是调用对象的hashCode方法的返回值),而后直接到hashCode值对应的位置去取出元素便可,这就是HashSet速度很快的缘由。
重写hashCode()方法的基本原则以下:
♦ 在程序运行过程当中,同一个对象的hashCode()方法返回值应相同。
♦ 当两个对象经过equals()方法比较返回true时,这两个对象的hashCode()方法返回值应该相等。
♦ 对象中用做equals()方法比较标准的实例变量,都应该用于计算hashCode值。
2)LinkedHashSet类
LinkedHashSet是HashSet的一个子类,具备HashSet的特性,也是根据元素的hashCode值来决定元素的存储位置。但它使用链表维护元素的次序,元素的顺序与添加顺序一致。因为LinkedHashSet须要维护元素的插入顺序,所以性能略低于HashSet,但在迭代访问Set里的所有元素时由很好的性能。
3)TreeSet类
TreeSet时SortedSet接口的实现类,TreeSet能够保证元素处于排序状态,它采用红黑树的数据结构来存储集合元素。TreeSet支持两种排序方法:天然排序和定制排序,默认采用天然排序。
♦ 天然排序
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素的大小关系,而后将元素按照升序排列,这就是天然排序。若是试图将一个对象添加到TreeSet集合中,则该对象必须实现Comparable接口,不然会抛出异常。当一个对象调用方法与另外一个对象比较时,例如obj1.compareTo(obj2),若是该方法返回0,则两个对象相等;若是返回一个正数,则obj1大于obj2;若是返回一个负数,则obj1小于obj2。
Java经常使用类中已经实现了Comparable接口的类有如下几个:
♦ BigDecimal、BigDecimal以及全部数值型对应的包装类:按照它们对应的数值大小进行比较。
♦ Charchter:按照字符的unicode值进行比较。
♦ Boolean:true对应的包装类实例大于false对应的包装类实例。
♦ String:按照字符串中的字符的unicode值进行比较。
♦ Date、Time:后面的时间、日期比前面的时间、日期大。
对于TreeSet集合而言,它判断两个对象是否相等的标准是:两个对象经过compareTo(Object obj)方法比较是否返回0,若是返回0则相等。
♦ 定制排序
想要实现定制排序,须要在建立TreeSet集合对象时,提供一个Comparator对象与该TreeSet集合关联,由Comparator对象负责集合元素的排序逻辑。
综上:天然排序实现的是Comparable接口,定制排序实现的是Comparator接口。(具体代码实现会在后续章节中讲解)
4)EnumSet类
EnumSet是一个专为枚举类设计的集合类,不容许添加null值。EnumSet的集合元素也是有序的,它以枚举值在Enum类内的定义顺序来决定集合元素的顺序。
5)各Set实现类的性能分析
HashSet的性能比TreeSet的性能好(特别是添加,查询元素时),由于TreeSet须要额外的红黑树算法维护元素的次序,若是须要一个保持排序的Set时才用TreeSet,不然应该使用HashSet。
LinkedHashSet是HashSet的子类,因为须要链表维护元素的顺序,因此插入和删除操做比HashSet要慢,但遍历比HashSet快。
EnumSet是全部Set实现类中性能最好的,但它只能 保存同一个枚举类的枚举值做为集合元素。
以上几个Set实现类都是线程不安全的,若是多线程访问,必须手动保证集合的同步性,这在后面的章节中会讲到。
3. List集合
List集合表明一个有序、可重复集合,集合中每一个元素都有其对应的顺序索引。List集合默认按照元素的添加顺序设置元素的索引,能够经过索引(相似数组的下标)来访问指定位置的集合元素。
实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。
1)ArrayList
ArrayList是一个动态数组,也是咱们最经常使用的集合,是List类的典型实现。它容许任何符合规则的元素插入甚至包括null。每个ArrayList都有一个初始容量(10),该容量表明了数组的大小。随着容器中的元素不断增长,容器的大小也会随着增长。在每次向容器中增长元素的同时都会进行容量检查,当快溢出时,就会进行扩容操做。因此若是咱们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操做而浪费时间、效率。
ArrayList擅长于随机访问。同时ArrayList是非同步的。
2)LinkedList
LinkedList是List接口的另外一个实现,除了能够根据索引访问集合元素外,LinkedList还实现了Deque接口,能够看成双端队列来使用,也就是说,既能够看成“栈”使用,又能够看成队列使用。
LinkedList的实现机制与ArrayList的实现机制彻底不一样,ArrayLiat内部以数组的形式保存集合的元素,因此随机访问集合元素有较好的性能;LinkedList内部以链表的形式保存集合中的元素,因此随机访问集合中的元素性能较差,但在插入删除元素时有较好的性能。
3)Vector
与ArrayList类似,可是Vector是同步的。因此说Vector是线程安全的动态数组。它的操做与ArrayList几乎同样。
4)Stack
Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被看成堆栈使用。基本的push和pop 方法,还有peek方法获得栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚建立后是空栈。
5)Iterator接口和ListIterator接口
Iterator是一个接口,它是集合的迭代器。集合能够经过Iterator去遍历集合中的元素。Iterator提供的API接口以下:
♦ boolean hasNext():判断集合里是否存在下一个元素。若是有,hasNext()方法返回 true。
♦ Object next():返回集合里下一个元素。
♦ void remove():删除集合里上一次next方法返回的元素。
ListIterator接口继承Iterator接口,提供了专门操做List的方法。ListIterator接口在Iterator接口的基础上增长了如下几个方法:
♦ boolean hasPrevious():判断集合里是否存在上一个元素。若是有,该方法返回 true。
♦ Object previous():返回集合里上一个元素。
♦ void add(Object o):在指定位置插入一个元素。
以上两个接口相比较,不难发现,ListIterator增长了向前迭代的功能(Iterator只能向后迭代),ListIterator还能够经过add()方法向List集合中添加元素(Iterator只能删除元素)。
4. Map集合
Map接口采用键值对Map<K,V>的存储方式,保存具备映射关系的数据,所以,Map集合里保存两组值,一组值用于保存Map里的key,另一组值用于保存Map里的value,key和value能够是任意引用类型的数据。key值不容许重复,能够为null。若是添加key-value对时Map中已经有重复的key,则新添加的value会覆盖该key原来对应的value。经常使用实现类有HashMap、LinkedHashMap、TreeMap等。
Map常见方法(来源于API)以下:
1)HashMap与Hashtable
HashMap与Hashtable是Map接口的两个典型实现,它们之间的关系彻底相似于ArrayList与Vertor。HashTable是一个古老的Map实现类,它提供的方法比较繁琐,目前基本不用了,HashMap与Hashtable主要存在如下两个典型区别:
♦ HashMap是线程不安全,HashTable是线程安全的。
♦ HashMap可使用null值最为key或value;Hashtable不容许使用null值做为key和value,若是把null放进HashTable中,将会发生空指针异常。
为了成功的在HashMap和Hashtable中存储和获取对象,用做key的对象必须实现hashCode()方法和equals()方法。
HashMap工做原理以下:
HashMap基于hashing原理,经过put()和get()方法存储和获取对象。当咱们将键值对传递给put()方法时,它调用建对象的hashCode()方法来计算hashCode值,而后找到bucket位置来储存值对象。当获取对象时,经过建对象的equals()方法找到正确的键值对,而后返回对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会存储在链表的下一个节点中。
2)LinkedHashMap实现类
LinkedHashMap使用双向链表来维护key-value对的次序(其实只须要考虑key的次序便可),该链表负责维护Map的迭代顺序,与插入顺序一致,所以性能比HashMap低,但在迭代访问Map里的所有元素时有较好的性能。
3)Properties
Properties类时Hashtable类的子类,它至关于一个key、value都是String类型的Map,主要用于读取配置文件。
4)TreeMap实现类
TreeMap是SortedMap的实现类,是一个红黑树的数据结构,每一个key-value对做为红黑树的一个节点。TreeMap存储key-value对时,须要根据key对节点进行排序。TreeMap也有两种排序方式:
♦ 天然排序:TreeMap的全部key必须实现Comparable接口,并且全部的key应该是同一个类的对象,不然会抛出ClassCastException。
♦ 定制排序:建立TreeMap时,传入一个Comparator对象,该对象负责对TreeMap中的全部key进行排序。
5)各Map实现类的性能分析
♦ HashMap一般比Hashtable(古老的线程安全的集合)要快
♦ TreeMap一般比HashMap、Hashtable要慢,由于TreeMap底层采用红黑树来管理key-value。
♦ LinkedHashMap比HashMap慢一点,由于它须要维护链表来爆出key-value的插入顺序。
如需转载,请注明做者(冰湖一角)和连接https://www.cnblogs.com/bingyimeiling/p/10255037.html
欢迎关注微信公众号【Java典籍】,收看更多Java技术干货!
▼微信扫一扫下图↓↓↓二维码关注