一、汇合框架图

简化图:

阐明:对于以上的框架图有如下几点阐明

1、所有汇合类都位于java.util包下。Java的汇合类次要由两个接口派生而出:Collection和Map,Collection和Map是Java汇合框架的根接口,这两个接口又蕴含了一些子接口或实现类。

2、汇合接口:6个接口(短虚线示意),示意不同汇合类型,是汇合框架的根底。

3、抽象类:5个抽象类(长虚线示意),对汇合接口的局部实现。可扩大为自定义汇合类。

4、实现类:8个实现类(实线示意),对接口的具体实现。

5、Collection 接口是一组容许反复的对象。

6、Set 接口继承 Collection,汇合元素不反复。

7、List 接口继承 Collection,容许反复,保护元素插入程序。

8、Map接口是键-值对象,与Collection接口没有什么关系。

9、Set、List和Map能够看做汇合的三大类:

  • List汇合是有序汇合,汇合中的元素能够反复,拜访汇合中的元素能够依据元素的索引来拜访。
  • Set汇合是无序汇合,汇合中的元素不能够反复,拜访汇合中的元素只能依据元素自身来拜访(也是汇合里元素不容许反复的起因)。
  • Map汇合中保留Key-value对模式的元素,拜访时只能依据每项元素的key来拜访其value。

二、总体剖析

大抵阐明:

看下面的框架图,先抓住它的骨干,即Collection和Map。

1、Collection是一个接口,是高度形象进去的汇合,它蕴含了汇合的基本操作和属性。Collection蕴含了List和Set两大分支。

  • List是一个有序的队列,每一个元素都有它的索引。第一个元素的索引值是0。List的实现类有LinkedList, ArrayList, Vector, Stack。
  • Set是一个不容许有反复元素的汇合。Set的实现类有HastSet和TreeSet。HashSet依赖于HashMap,它实际上是通过HashMap实现的;TreeSet依赖于TreeMap,它实际上是通过TreeMap实现的。

2、Map是一个映射接口,即key-value键值对。Map中的每一个元素蕴含“一个key”和“key对应的value”。AbstractMap是个抽象类,它实现了Map接口中的大部分API。而HashMap,TreeMap,WeakHashMap都是继承于AbstractMap。Hashtable尽管继承于Dictionary,但它实现了Map接口。

3、接下来,再看Iterator。它是遍历汇合的工具,即咱们通常通过Iterator迭代器来遍历汇合。咱们说Collection依赖于Iterator,是因为Collection的实现类都要实现iterator()函数,返回一个Iterator对象。ListIterator是专门为遍历List而存在的。

4、再看Enumeration,它是JDK 1.0引入的抽象类。作用和Iterator一样,也是遍历汇合;然而Enumeration的性能要比Iterator少。在下面的框图中,Enumeration只能在Hashtable, Vector, Stack中应用。

5、最初,看Arrays和Collections。它们是操作数组、汇合的两个工具类。

有了下面的整体框架之后,咱们接下来对每个类别离进行剖析。

三、Collection接口

Collection接口是解决对象汇合的根接口,其中定义了很多对元素进行操作的办法。Collection接口有两个次要的子接口List和Set,留神Map不是Collection的子接口,这个要牢记。

Collection接口中的办法如下:

![img]
其中,有几个比拟罕用的办法,比方办法add()增加一个元素到汇合中,addAll()将指定汇合中的所有元素增加到汇合中,contains()办法检测汇合中是否蕴含指定的元素,toArray()办法返回一个示意汇合的数组。

另外,Collection中有一个iterator()函数,它的作用是返回一个Iterator接口。通常,咱们通过Iterator迭代器来遍历汇合。ListIterator是List接口所特有的,在List接口中,通过ListIterator()返回一个ListIterator对象。

Collection接口有两个罕用的子接口,上面具体介绍。

1.List接口

List汇合代表一个有序汇合,汇合中每个元素都有其对应的顺序索引。List汇合容许应用反复元素,能够通过索引来拜访指定地位的汇合元素。

List接口继承于Collection接口,它能够定义一个容许反复的有序汇合。因为List中的元素是有序的,所以咱们能够通过应用索引(元素在List中的地位,相似于数组下标)来拜访List中的元素,这相似于Java的数组。

List接口为Collection间接接口。List所代表的是有序的Collection,即它用某种特定的插入程序来保护元素程序。用户能够对列表中每个元素的插入地位进行准确地管制,同时能够依据元素的整数索引(在列表中的地位)拜访元素,并搜寻列表中的元素。实现List接口的汇合次要有:ArrayList、LinkedList、Vector、Stack

(1)ArrayList

ArrayList是一个动静数组,也是咱们最罕用的汇合。它容许任何合乎规定的元素插入甚至包含null。每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。随着容器中的元素一直减少,容器的大小也会随着减少。在每次向容器中减少元素的同时都会进行容量查看,当快溢出时,就会进行扩容操作。所以如果咱们明确所插入元素的多少,最好指定一个初始容量值,防止过多的进行扩容操作而浪费时间、效率。

size、isEmpty、get、set、iterator和 listIterator 操作都以固定工夫运行。add 操作以摊派的固定工夫运行,也就是说,增加 n 个元素须要 O(n) 工夫(因为要思考到扩容,所以这不只是增加元素会带来摊派固定工夫开销那样简略)。

ArrayList擅长于随机拜访。同时ArrayList是非同步的。

(2)LinkedList

同样实现List接口的LinkedList与ArrayList不同,ArrayList是一个动静数组,而LinkedList是一个双向链表。所以它除了有ArrayList的基本操作办法外还额定提供了get,remove,insert办法在LinkedList的首部或尾部。

因为实现的形式不同,LinkedList不能随机拜访,它所有的操作都是要依照双重链表的须要执行。在列表中索引的操作将从结尾或结尾遍历列表(从凑近指定索引的一端)。这样做的益处就是能够通过较低的代价在List中进行插入和删除操作。

与ArrayList一样,LinkedList也是非同步的。如果多个线程同时拜访一个List,则必须本人实现拜访同步。一种解决办法是在创立List时结构一个同步的List:

List list = Collections.synchronizedList(new LinkedList(...));

(3)Vector

与ArrayList类似,然而Vector是同步的。所以说Vector是线程平安的动静数组。它的操作与ArrayList简直一样。

(4)Stack

Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额定的办法使得Vector得以被当作堆栈应用。根本的push和pop 办法,还有peek办法失去栈顶的元素,empty办法测试堆栈是否为空,search办法检测一个元素在堆栈中的地位。Stack刚创立后是空栈。

2.Set接口

Set是一种不包含反复元素的Collection。它维持它本人的外部排序,所以随机拜访没有任何意义。与List一样,它同样容许null的存在然而仅有一个。因为Set接口的特殊性,所有传入Set汇合中的元素都必须不同,同时要留神任何可变对象,如果在对汇合中元素进行操作时,导致e1.equals(e2)==true,则必定会产生某些问题。Set接口有三个具体实现类,别离是散列集HashSet、链式散列集LinkedHashSet和树形集TreeSet。

Set是一种不蕴含反复的元素的Collection,无序,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。

须要留神的是:尽管Set中元素没有程序,然而元素在set中的地位是由该元素的HashCode决定的,其具体位置其实是固定的。

此外须要阐明一点,在set接口中的不反复是有特殊要求的。

举一个例子:对象A和对象B,原本是不同的两个对象,失常状况下它们是可能放入到Set外面的,然而如果对象A和B的都重写了hashcode和equals办法,并且重写后的hashcode和equals办法是雷同的话。那么A和B是不能同时放入到Set汇合中去的,也就是Set汇合中的去重和hashcode与equals办法间接相干。

为了更好地了解,请看上面的例子:

public class Test{ public static void main(String[] args) {      Set<String> set=new HashSet<String>();      set.add("Hello");      set.add("world");      set.add("Hello");      System.out.println("汇合的尺寸为:"+set.size());      System.out.println("汇合中的元素为:"+set.toString());   } }

运行后果:

汇合的尺寸为:2
汇合中的元素为:[world, Hello]

剖析:因为String类中重写了hashcode和equals办法,用来比拟指向的字符串对象所存储的字符串是否相等。所以这里的第二个Hello是加不进去的。

再看一个例子:

public class TestSet {    public static void main(String[] args){        Set<String> books = new HashSet<String>();        //增加一个字符串对象        books.add(new String("Struts2权威指南"));        //再次增加一个字符串对象,        //因为两个字符串对象通过equals办法比拟相等,所以增加失败,返回false        boolean result = books.add(new String("Struts2权威指南"));        System.out.println(result);        //上面输入看到汇合只有一个元素        System.out.println(books);        }}

运行后果:

false
[Struts2权威指南]

阐明:程序中,book汇合两次增加的字符串对象显著不是一个对象(程序通过new关键字来创立字符串对象),当应用==运算符判断返回false,应用equals办法比拟返回true,所以不能增加到Set汇合中,最初只能输入一个元素。

(1)HashSet

HashSet 是一个没有反复元素的汇合。它是由HashMap实现的,不保障元素的程序(这里所说的没有程序是指:元素插入的程序与输入的程序不统一),而且HashSet容许应用null 元素。HashSet是非同步的,如果多个线程同时拜访一个哈希set,而其中至多一个线程批改了该set,那么它必须放弃内部同步。 HashSet按Hash算法来存储汇合的元素,因而具备很好的存取和查找性能。

HashSet的实现形式大抵如下,通过一个HashMap存储元素,元素是寄存在HashMap的Key中,而Value对立应用一个Object对象。

HashSet应用和了解中容易呈现的误区:

a.HashSet中寄存null值。HashSet中是容许存入null值的,然而在HashSet中仅仅可能存入一个null值。

b.HashSet中存储元素的地位是固定的。HashSet中存储的元素的是无序的,这个没什么好说的,然而因为HashSet底层是基于Hash算法实现的,应用了hashcode,所以HashSet中相应的元素的地位是固定的。

c.必须小心操作可变对象Mutable Object)。如果一个Set中的可变元素扭转了本身状态导致Object.equals(Object)=true将导致一些问题。

(2)LinkedHashSet

LinkedHashSet继承自HashSet,其底层是基于LinkedHashMap来实现的,有序,非同步。LinkedHashSet汇合同样是依据元素的hashCode值来决定元素的存储地位,然而它同时应用链表保护元素的秩序。这样使得元素看起来像是以插入程序保留的,也就是说,当遍历该汇合时候,LinkedHashSet将会以元素的增加程序拜访汇合的元素。

(3)TreeSet

TreeSet是一个有序汇合,其底层是基于TreeMap实现的,非线程平安。TreeSet能够确保汇合元素处于排序状态。TreeSet反对两种排序形式,天然排序和定制排序,其中天然排序为默认的排序形式。当咱们结构TreeSet时,若应用不带参数的构造函数,则TreeSet的应用天然比拟器;若用户须要应用自定义的比拟器,则须要应用带比拟器的参数。

留神:TreeSet汇合不是通过hashcode和equals函数来比拟元素的.它是通过compare或者comparaeTo函数来判断元素是否相等.compare函数通过判断两个对象的id,雷同的id判断为反复元素,不会被退出到汇合中。

四、Map接口

Map与List、Set接口不同,它是由一系列键值对组成的汇合,提供了key到Value的映射。同时它也没有继承Collection。在Map中它保障了key与value之间的一一对应关系。也就是说一个key对应一个value,所以它不能存在雷同的key值,当然value值能够雷同

1.HashMap

以哈希表数据结构实现,查找对象时通过哈希函数计算其地位,它是为疾速查问而设计的,其外部定义了一个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中寄存的索引,如果有抵触,则应用散列链表的模式将所有雷同哈希地址的元素串起来,可能通过查看HashMap.Entry的源码它是一个单链表构造。

2.LinkedHashMap

LinkedHashMap是HashMap的一个子类,它保留插入的程序,如果须要输入的程序和输出时的雷同,那么就选用LinkedHashMap。

LinkedHashMap是Map接口的哈希表和链接列表实现,具备可预知的迭代程序。此实现提供所有可选的映射操作,并容许应用null值和null键。此类不保障映射的程序,特地是它不保障该程序恒久不变。

LinkedHashMap实现与HashMap的不同之处在于,后者保护着一个运行于所有条目标双重链接列表。此链接列表定义了迭代程序,该迭代程序能够是插入程序或者是拜访程序。

依据链表中元素的程序能够分为:按插入程序的链表,和按拜访程序(调用get办法)的链表。默认是按插入程序排序,如果指定按拜访程序排序,那么调用get办法后,会将这次拜访的元素移至链表尾部,一直拜访能够造成按拜访程序排序的链表。

留神,此实现不是同步的。如果多个线程同时拜访链接的哈希映射,而其中至多一个线程从构造上批改了该映射,则它必须放弃内部同步。因为LinkedHashMap须要保护元素的插入程序,因而性能略低于HashMap的性能,但在迭代拜访Map里的全副元素时将有很好的性能,因为它以链表来保护外部程序。

3.TreeMap

TreeMap 是一个有序的key-value汇合,非同步,基于红黑树(Red-Black tree)实现,每一个key-value节点作为红黑树的一个节点。TreeMap存储时会进行排序的,会依据key来对key-value键值对进行排序,其中排序形式也是分为两种,一种是天然排序,一种是定制排序,具体取决于应用的构造方法。

天然排序:TreeMap中所有的key必须实现Comparable接口,并且所有的key都应该是同一个类的对象,否则会报ClassCastException异样。

定制排序:定义TreeMap时,创立一个comparator对象,该对象对所有的treeMap中所有的key值进行排序,采纳定制排序的时候不须要TreeMap中所有的key必须实现Comparable接口。

TreeMap判断两个元素相等的规范:两个key通过compareTo()办法返回0,则认为这两个key相等。

如果应用自定义的类来作为TreeMap中的key值,且想让TreeMap可能良好的工作,则必须重写自定义类中的equals()办法,TreeMap中判断相等的规范是:两个key通过equals()办法返回为true,并且通过compareTo()办法比拟应该返回为0。


五、Iterator 与 ListIterator详解

1.Iterator

Iterator的定义如下:

public interface Iterator<E> {}

Iterator是一个接口,它是汇合的迭代器。汇合能够通过Iterator去遍历汇合中的元素。

Iterator提供的API接口如下:

  • boolean hasNext():判断汇合里是否存在下一个元素。如果有,hasNext()办法返回 true。
  • Object next():返回汇合里下一个元素。
  • void remove():删除汇合里上一次next办法返回的元素。

应用示例:

public class IteratorExample {    public static void main(String[] args) {        ArrayList<String> a = new ArrayList<String>();        a.add("aaa");        a.add("bbb");        a.add("ccc");        System.out.println("Before iterate : " + a);        Iterator<String> it = a.iterator();        while (it.hasNext()) {            String t = it.next();            if ("bbb".equals(t)) {                it.remove();            }        }        System.out.println("After iterate : " + a);    }}

输入后果如下:

Before iterate : [aaa, bbb, ccc]
After iterate : [aaa, ccc]

留神:

  • Iterator只能单向挪动。
  • Iterator.remove()是惟一平安的形式来在迭代过程中批改汇合;如果在迭代过程中以任何其它的形式批改了根本汇合将会产生未知的行为。而且每调用一次next()办法,remove()办法只能被调用一次,如果违反这个规定将抛出一个异样。

2.ListIterator

ListIterator是一个性能更加弱小的迭代器, 它继承于Iterator接口,只能用于各种List类型的拜访。能够通过调用listIterator()办法产生一个指向List开始处的ListIterator, 还能够调用listIterator(n)办法创立一个一开始就指向列表索引为n的元素处的ListIterator。

ListIterator接口定义如下:

public interface ListIterator<E> extends Iterator<E> {    boolean hasNext();    E next();    boolean hasPrevious();    E previous();    int nextIndex();    int previousIndex();    void remove();    void set(E e);    void add(E e);}

由以上定义咱们能够推出ListIterator能够:

  • 双向挪动(向前/向后遍历).
  • 产生绝对于迭代器在列表中指向的以后地位的前一个和后一个元素的索引.
  • 能够应用set()办法替换它拜访过的最初一个元素.
  • 能够应用add()办法在next()办法返回的元素之前或previous()办法返回的元素之后插入一个元素.

应用示例:

public class ListIteratorExample {    public static void main(String[] args) {        ArrayList<String> a = new ArrayList<String>();        a.add("aaa");        a.add("bbb");        a.add("ccc");        System.out.println("Before iterate : " + a);        ListIterator<String> it = a.listIterator();        while (it.hasNext()) {            System.out.println(it.next() + ", " + it.previousIndex() + ", " + it.nextIndex());        }        while (it.hasPrevious()) {            System.out.print(it.previous() + " ");        }        System.out.println();        it = a.listIterator(1);        while (it.hasNext()) {            String t = it.next();            System.out.println(t);            if ("ccc".equals(t)) {                it.set("nnn");            } else {                it.add("kkk");            }        }        System.out.println("After iterate : " + a);    }}

输入后果如下:

Before iterate : [aaa, bbb, ccc]aaa, 0, 1bbb, 1, 2ccc, 2, 3ccc bbb aaa bbbcccAfter iterate : [aaa, bbb, kkk, nnn]

六、异同点

1.ArrayList和LinkedList

  • ArrayList是实现了基于动静数组的数据结构,LinkedList基于链表的数据结构。
  • 对于随机拜访get和set,ArrayList相对优于LinkedList,因为LinkedList要挪动指针。
  • 对于新增和删除操作add和remove,LinedList比拟占优势,因为ArrayList要挪动数据。

这一点要看理论状况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要挪动插入点及之后的所有数据。

2.HashTable与HashMap

相同点:

  • 都实现了Map、Cloneable、java.io.Serializable接口。
  • 都是存储"键值对(key-value)"的散列表,而且都是采纳拉链法实现的。

不同点:

(1)历史起因:HashTable是基于古老的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现 。

(2)同步性:HashTable是线程平安的,也就是说是同步的,而HashMap是线程序不平安的,不是同步的 。

(3)对null值的解决:HashMap的key、value都可为null,HashTable的key、value都不可为null 。

(4)基类不同:HashMap继承于AbstractMap,而Hashtable继承于Dictionary。

  • Dictionary是一个抽象类,它间接继承于Object类,没有实现任何接口。Dictionary类是JDK 1.0的引入的。尽管Dictionary也反对“增加key-value键值对”、“获取value”、“获取大小”等基本操作,但它的API函数比Map少;而且Dictionary个别是通过Enumeration(枚举类)去遍历,Map则是通过Iterator(迭代M器)去遍历。然而因为Hashtable也实现了Map接口,所以,它即反对Enumeration遍历,也反对Iterator遍历。
  • AbstractMap是一个抽象类,它实现了Map接口的绝大部分API函数;为Map的具体实现类提供了极大的便当。它是JDK 1.2新增的类。

(5)反对的遍历品种不同:HashMap只反对Iterator(迭代器)遍历。而Hashtable反对Iterator(迭代器)和Enumeration(枚举器)两种形式遍历。

3.HashMap、Hashtable、LinkedHashMap和TreeMap比拟

Hashmap 是一个最罕用的Map,它依据键的HashCode 值存储数据,依据键能够间接获取它的值,具备很快的访问速度。遍历时,获得数据的程序是齐全随机的。HashMap最多只容许一条记录的键为Null;容许多条记录的值为Null;HashMap不反对线程的同步,即任一时刻能够有多个线程同时写HashMap;可能会导致数据的不统一。如果须要同步,能够用Collections的synchronizedMap办法使HashMap具备同步的能力。

Hashtable 与 HashMap相似,不同的是:它不容许记录的键或者值为空;它反对线程的同步,即任一时刻只有一个线程能写Hashtable,因而也导致了Hashtale在写入时会比较慢。

LinkedHashMap保留了记录的插入程序,在用Iterator遍历LinkedHashMap时,先失去的记录必定是先插入的,也能够在结构时用带参数,依照利用次数排序。在遍历的时候会比HashMap慢,不过有种状况例外,当HashMap容量很大,理论数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和理论数据无关,和容量无关,而HashMap的遍历速度和他的容量无关。

如果须要输入的程序和输出的雷同,那么用LinkedHashMap能够实现,它还能够按读取程序来排列,像连接池中能够利用。LinkedHashMap实现与HashMap的不同之处在于,后者保护着一个运行于所有条目标双重链表。此链接列表定义了迭代程序,该迭代程序能够是插入程序或者是拜访程序。对于LinkedHashMap而言,它继承与HashMap、底层应用哈希表与双向链表来保留所有元素。其基本操作与父类HashMap类似,它通过重写父类相干的办法,来实现本人的链接列表个性。

TreeMap实现SortMap接口,外部实现是红黑树。可能把它保留的记录依据键排序,默认是按键值的升序排序,也能够指定排序的比拟器,当用Iterator 遍历TreeMap时,失去的记录是排过序的。TreeMap不容许key的值为null。非同步的。

个别状况下,咱们用的最多的是HashMap,HashMap外面存入的键值对在取出的时候是随机的,它依据键的HashCode值存储数据,依据键能够间接获取它的值,具备很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的抉择。

TreeMap取出来的是排序后的键值对。但如果您要按天然程序或自定义程序遍历键,那么TreeMap会更好。

LinkedHashMap 是HashMap的一个子类,如果须要输入的程序和输出的雷同,那么用LinkedHashMap能够实现,它还能够按读取程序来排列,像连接池中能够利用。

import java.util.HashMap;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.TreeMap;public class MapTest {    public static void main(String[] args) {        //HashMap        HashMap<String,String> hashMap = new HashMap();        hashMap.put("4", "d");        hashMap.put("3", "c");        hashMap.put("2", "b");        hashMap.put("1", "a");        Iterator<String> iteratorHashMap = hashMap.keySet().iterator();        System.out.println("HashMap-->");        while (iteratorHashMap.hasNext()){            Object key1 = iteratorHashMap.next();            System.out.println(key1 + "--" + hashMap.get(key1));        }        //LinkedHashMap        LinkedHashMap<String,String> linkedHashMap = new LinkedHashMap();        linkedHashMap.put("4", "d");        linkedHashMap.put("3", "c");        linkedHashMap.put("2", "b");        linkedHashMap.put("1", "a");        Iterator<String> iteratorLinkedHashMap = linkedHashMap.keySet().iterator();        System.out.println("LinkedHashMap-->");        while (iteratorLinkedHashMap.hasNext()){            Object key2 = iteratorLinkedHashMap.next();            System.out.println(key2 + "--" + linkedHashMap.get(key2));        }        //TreeMap        TreeMap<String,String> treeMap = new TreeMap();        treeMap.put("4", "d");        treeMap.put("3", "c");        treeMap.put("2", "b");        treeMap.put("1", "a");        Iterator<String> iteratorTreeMap = treeMap.keySet().iterator();        System.out.println("TreeMap-->");        while (iteratorTreeMap.hasNext()){            Object key3 = iteratorTreeMap.next();            System.out.println(key3 + "--" + treeMap.get(key3));        }    }}

输入后果:

HashMap-->3--c2--b1--a4--dLinkedHashMap-->4--d3--c2--b1--aTreeMap-->1--a2--b3--c4--d

4.HashSet、LinkedHashSet、TreeSet比拟

Set接口

Set不容许蕴含雷同的元素,如果试图把两个雷同元素退出同一个汇合中,add办法返回false。

Set判断两个对象雷同不是应用==运算符,而是依据equals办法。也就是说,只有两个对象用equals办法比拟返回true,Set就不会承受这两个对象。

HashSet

HashSet有以下特点:

  • 不能保障元素的排列程序,程序有可能发生变化。
  • 不是同步的。
  • 汇合元素能够是null,但只能放入一个null。

当向HashSet联合中存入一个元素时,HashSet会调用该对象的hashCode()办法来失去该对象的hashCode值,而后依据 hashCode值来决定该对象在HashSet中存储地位。简略的说,HashSet汇合判断两个元素相等的规范是两个对象通过equals办法比拟相等,并且两个对象的hashCode()办法返回值也相等。

留神,如果要把一个对象放入HashSet中,重写该对象对应类的equals办法,也应该重写其hashCode()办法。其规定是如果两个对象通过equals办法比拟返回true时,其hashCode也应该雷同。另外,对象中用作equals比拟规范的属性,都应该用来计算 hashCode的值。

LinkedHashSet

LinkedHashSet汇合同样是依据元素的hashCode值来决定元素的存储地位,然而它同时应用链表保护元素的秩序。这样使得元素看起来像是以插入程序保留的,也就是说,当遍历该汇合时候,LinkedHashSet将会以元素的增加程序拜访汇合的元素。

LinkedHashSet在迭代拜访Set中的全副元素时,性能比HashSet好,然而插入时性能略微逊色于HashSet。

TreeSet类

TreeSet是SortedSet接口的惟一实现类,TreeSet能够确保汇合元素处于排序状态。TreeSet反对两种排序形式,天然排序和定制排序,其中天然排序为默认的排序形式。向TreeSet中退出的应该是同一个类的对象。

TreeSet判断两个对象不相等的形式是两个对象通过equals办法返回false,或者通过CompareTo办法比拟没有返回0。

天然排序

天然排序应用要排序元素的CompareTo(Object obj)办法来比拟元素之间大小关系,而后将元素依照升序排列。

Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)办法,该办法返回一个整数值,实现了该接口的对象就能够比拟大小。obj1.compareTo(obj2)办法如果返回0,则阐明被比拟的两个对象相等,如果返回一个负数,则表明obj1大于obj2,如果是正数,则表明obj1小于obj2。如果咱们将两个对象的equals办法总是返回true,则这两个对象的compareTo办法返回应该返回0。

定制排序

天然排序是依据汇合元素的大小,以升序排列,如果要定制排序,应该应用Comparator接口,实现 int compare(T o1,T o2)办法。

package com.test;  import java.util.HashSet;  import java.util.LinkedHashSet;  import java.util.TreeSet;  /**   * @description 几个set的比拟   *    HashSet:哈希表是通过应用称为散列法的机制来存储信息的,元素并没有以某种特定程序来寄存;   *    LinkedHashSet:以元素插入的程序来保护汇合的链接表,容许以插入的程序在汇合中迭代;   *    TreeSet:提供一个应用树结构存储Set接口的实现,对象以升序顺序存储,拜访和遍历的工夫很快。   * @author Zhou-Jingxian   *   */  public class SetDemo {      public static void main(String[] args) {          HashSet<String> hs = new HashSet<String>();          hs.add("B");          hs.add("A");          hs.add("D");          hs.add("E");          hs.add("C");          hs.add("F");          System.out.println("HashSet 程序:\n"+hs);          LinkedHashSet<String> lhs = new LinkedHashSet<String>();          lhs.add("B");          lhs.add("A");          lhs.add("D");          lhs.add("E");          lhs.add("C");          lhs.add("F");          System.out.println("LinkedHashSet 程序:\n"+lhs);          TreeSet<String> ts = new TreeSet<String>();          ts.add("B");          ts.add("A");          ts.add("D");          ts.add("E");          ts.add("C");          ts.add("F");          System.out.println("TreeSet 程序:\n"+ts);      }  }

输入后果:

HashSet 程序:[D, E, F, A, B, C]LinkedHashSet 程序:[B, A, D, E, C, F]TreeSet 程序:[A, B, C, D, E, F]

5、Iterator和ListIterator区别

咱们在应用List,Set的时候,为了实现对其数据的遍历,咱们常常应用到了Iterator(迭代器)。应用迭代器,你不须要干预其遍历的过程,只须要每次取出一个你想要的数据进行解决就能够了。然而在应用的时候也是有不同的。

List和Set都有iterator()来获得其迭代器。对List来说,你也能够通过listIterator()获得其迭代器,两种迭代器在有些时候是不能通用的,Iterator和ListIterator次要区别在以下方面:

  • ListIterator有add()办法,能够向List中增加对象,而Iterator不能
  • ListIterator和Iterator都有hasNext()next()办法,能够实现程序向后遍历,然而ListIterator有hasPrevious()previous()办法,能够实现逆向(程序向前)遍历。Iterator就不能够。
  • ListIterator能够定位以后的索引地位,nextIndex()previousIndex()能够实现。Iterator没有此性能。
  • 都可实现删除对象,然而ListIterator能够实现对象的批改,set()办法能够实现。Iierator仅能遍历,不能批改。

因为ListIterator的这些性能,能够实现对LinkedList等List数据结构的操作。其实,数组对象也能够用迭代器来实现。

6、Collection 和 Collections区别

(1)java.util.Collection 是一个汇合接口(汇合类的一个顶级接口)。它提供了对汇合对象进行基本操作的通用接口办法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的汇合提供了最大化的对立操作形式,其间接继承接口有List与Set。

 Collection   ├List   │├LinkedList   │├ArrayList   │└Vector   │ └Stack   └Set 

(2)java.util.Collections 是一个包装类(工具类/帮忙类)。它蕴含有各种无关汇合操作的动态多态办法。此类不能实例化,就像一个工具类,用于对汇合中元素进行排序、搜寻以及线程平安等各种操作,服务于Java的Collection框架。

代码示例:

import java.util.ArrayList; import java.util.Collections; import java.util.List; public class TestCollections {     public static void main(String args[]) {         //留神List是实现Collection接口的         List list = new ArrayList();         double array[] = { 112, 111, 23, 456, 231 };         for (int i = 0; i < array.length; i++) {             list.add(new Double(array[i]));         }         Collections.sort(list);         for (int i = 0; i < array.length; i++) {             System.out.println(list.get(i));         }         // 后果:23.0 111.0 112.0 231.0 456.0     } }

文末福利

肝了全网,43份Java思维导图,须要自取!!!

《Java面试手册》V1.0版本,高清PDF收费获取