夯实Java基础(十九)——集合

一、前言

集合在Java中的地位想必你们都知道,不用多BB了。不管是在咱们如今的学习中仍是在从此的工做中,集合这样一个你们族都无处不在,无处不用。在前面讲到的数组也是一个小的容器,可是数组不是面向对象对象的,它存在明显的缺陷,而集合刚好弥补了数组带来的缺陷。集合比数组更加灵活、更加实用。并且不一样的集合框架可用于不一样的场景。html

咱们简单来比较一下数组和集合区别:java

  • 一、数组能存放基本数据类型和对象,而集合类中只能存放对象。
  • 二、数组容量固定没法动态改变,集合类容量能够动态改变。
  • 三、数组没法判断其中实际存有多少元素,length只告诉了数组的容量,而集合的size()能够确切知道元素的个数。
  • 四、集合有多种实现方式和不一样适用场合,不像数组仅采用顺序表方式。
  • 五、集合以类的形式存在,具备封装、继承、多态等类的特性,经过简单的方法和属性便可实现各类复杂操做,从而大大提升了软件的开发效率。

为了清晰的认识Java集合你们族,下面是整个Java集合的框架图:算法

经过上面的图片能够看到集合你们族的成员以及他们之间的关系。发现这也太多了吧,不过不要太慌张。咱们如今只须要抓住它们的主干便可,即Collection、Map和Iterator,额外的还有两个对集合操做的工具类Collections和Arrays。其中虚框表示的是接口或抽象类,实框是类,虚箭头是实现,实箭头是继承。而后把它们捋一捋给分个类就应该清楚了。数组

二、集合的分类

上面的Java集合框架图看起来比较的杂乱,因此咱们对它们进行了分类处理,这样更加直观。安全

Collection接口:最基本的集合接口(单列数据)
├——-List接口:全部元素按照进入的前后顺序有序存储,可重复集合
│—————-├ ArrayList:接口实现类,用数组实现,随机访问,增删慢,查询快,没有同步,线程不安全 
│—————-├ LinkedList:接口实现类,用双向链表实现, 插入删除快,查询慢, 没有同步,线程不安全 
│—————-└ Vector:接口实现类,用数组实现,它和ArrayList几乎同样,可是它是同步, 线程安全的(Vector几乎已经不用了)
└———————-└ Stack:继承自Vector类,Stack具备后进先出的特色 
└——-Set接口:不容许包含重复的值(能够有null,可是只有一个),无序,不可重复集合
├—————-└HashSet:使用hash表(数组)存储元素,无序,其底层是包装了一个HashMap去实现的,因此查询插入速度较快
│————————└ LinkedHashSet:继承HashSet类,它新增了一个重要特性,就是元素按照插入的顺序存储
├ —————-TreeSet:底层基于TreeMap实现的,它支持2种排序方式:天然排序(Comparable)和定制排序(Comparator)数据结构

└ ——-Queue接口:队列,它的特色是先进先出框架

Map接口:键值对的集合接口,不容许含有相同的key,有则输出一个key-value组合(双列数据)
├———Hashtable:接口实现类,用hash表实现,不可重复key,key不能为null,同步,效率稍低,线程安全
├———HashMap:接口实现类 ,用hash表实现,不可重复key,key能够为null,没有同步,效率稍高 ,线程不安全
│—————–├ LinkedHashMap:双向链表和hash表实现,按照key的插入顺序存放
│——— WeakHashMap:和HashMap同样,但它的键是“弱键”,垃圾收集器会自动的清除没有在其余任何地方被引用的键值对ide

├ ——–TreeMap:用红黑树算法实现,它默认按照全部的key进行排序
└———IdentifyHashMap:它是一个特殊的Map实现,它的内部判断key是否相等用的是 ==,而HashMap则更加复杂函数

简单完成分类以后咱们就从集合的特色和区别来进行一 一讲解。工具

三、Collection接口

Collection是最基本的集合接口,它是单列数据集合。在JDK中不提供Collection接口的任何直接实现,它只提供了更具体的子接口(即继承自Collection接口),例如List列表,Set集合,Queue队列,而后再由具体的类来实现这些子接口。经过具体类实现接口以后它们的特征就得以凸显出来,有些集合中的元素是有序的,而其余的集合中的元素则是无序的;有些集合容许重复的元素,而其余的集合则不容许重复的元素;有些集合容许排序,而其余的集合则不容许排序。

既然Collection接口是集合的层次结构的根接口,那么一定有经常使用的方法,咱们来看一下:

  1. boolean add(E e):向集合中添加一个元素。集合更改则添加成功返回true,若是该集合不容许重复而且已经包含指定的元素。返回false。部分子类的add方法可能会限制添加到集合中的元素类型,或者不会将NULL添加到集合中。
  2. boolean addAll(Collection<? extends E> c):将指定集合中的全部元素添加到此集合中。在添加过程当中若是被添加的集合发生了更改,addAll方法不具备幂等性。
  3. void clear():清空掉集合中的全部元素。
  4. boolean contains(Object o):若是集合中包含指定元素那么返回true。特别的,若是集合中也包含NULL元素的时候而且要查找的元素也是NULL的时候也返回true。
  5. boolean containsAll(Collection<?> c):若是该集合中包含指定集合中的全部元素的时候返回true。
  6. boolean isEmpty():若是集合中不包含元素返回true。
  7. Iterator<E> iterator():返回在此集合的元素上进行迭代的迭代器。关于元素返回的顺序没有任何保证,除非此集合是某个能提供保证顺序的类实例。 
  8. boolean remove(Object o):删除集合中的指定的元素。若是存在NULL,也删除。
  9. boolean removeAll(Collection<?> c):删除当前集合中全部等于指定集合中的元素。
  10. boolean retainAll(Collection<?> c):仅保留此集合中那些也包含在指定集合的元素。移除此集合中未包含在指定集合中的全部元素。
  11. int size():返回该集合中元素的个数。若是超过了Integer.MAX_VALUE,那么返回Integer.MAX_VALUE。
  12. Object[] toArray():返回包含此集合中因此元素的数组。
  13. <T> T[] toArray():返回包含此集合中全部元素的数组; 返回的数组的运行时类型是指定数组的运行时类型。

四、Iterator接口

咱们从上面Collection结构中能够看到其内部有一个iterator()方法,这个方法不是Collection中所特有的,而是重写了父类Iterable中的。由于Collection接口继承了java.lang.Iterable接口,而该接口中有一个iterator()方法。也就是说全部实现了Collection接口的集合类中都有iterator()方法,它用来返回实现了Iterator接口的迭代器对象。

Iterator接口的内部结构比较简单,其内部只定义的四个方法,它们分别是:

  1. boolean hasNext():若是迭代具备更多元素,则返回true。
  2. E next():返回迭代器中游标的下一元素。
  3. default void remove():从集合中删除此迭代器返回的最后一个元素。每次调用next后只能调用一次此方法,不能屡次调用,不然会报错。若是在进行迭代时用调用此方法以外的其余方式修改了该迭代器所指向的集合,那么则迭代器的行为是不肯定的。
  4. default void forEachRemaining(Consumer<? super E> action):对每一个剩余元素执行给定的操做,直到全部元素都被处理或动做引起异常。若是指定了迭代的顺序,则按迭代的顺序执行。操做引起的异常将被转发给调用者。

迭代器的简单举例:

public static void main(String[] args) {
        //hasNext()、next()测试
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
        coll.add('A');
        coll.add(true);
        coll.add(new String("Collection..."));
        //建立迭代器对象
        Iterator iterator = coll.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        System.out.println("----------------------");

        //remove()测试。若是还未调用next()或在上次调用next()方法以后已经调用了remove()方法,
        //那么在再次用remove()方法会报错java.lang.IllegalStateException
        Iterator iterator1 = coll.iterator();
        while (iterator1.hasNext()) {
            //iterator1.remove();不能在next()前先调用
            Object next = iterator1.next();
            if (next.equals(456)) {
                iterator1.remove();
                //iterator1.remove();不能在next()后再次调
            }
        }
        iterator1 = coll.iterator();
        while (iterator1.hasNext()) {
            System.out.println(iterator1.next());
        }
    }
    //运行结果:
    //123
    //456
    //A
    //true
    //Collection...
    //----------------------
    //123
    //A
    //true
    //Collection...

简易分析一下:当返回了Iterator对象以后能够理解为有一个指针,它指在第一个对象的上面(即123的上面,此时指针为空),当咱们调用iterator.hasNext()的时候,判断是否还有下一个元素,若是有则返回true。而后调用iterator.next()使指针往下移而且返回下移之后集合位置上的元素,这样以此类推就输出了以上结果。

五、List接口

List接口直接继承了Collection接口,它对Collection进行了简单的扩充,从而让集合凸显出它们各自的特征。在List中全部元素的存储都是有序的,并且是可重复存储的。用户能够根据元素存储位置的索引来操做元素。实现了List接口的集合主要有如下几个:ArrayList、LinkedList、Vector和Stack。

注意:List集合它有一个特有的迭代器——ListIterator。Iterator的子接口ListIterator是专门给List集合提供的迭代元素的接口,它的内部对Iterator功能进行一些扩充。例如增长的方法有hasPrevious()、nextIndex()、previousIndex()等等。

既然List接口直接继承了Collection接口,并且List是有序存储结构,那么List除了从Collection中继承的方法以外,一定会本身添加一些根据索引来操做集合元素的方法,咱们来看一下:

  1. void add(int index, E element):将指定的元素插入此列表中的指定位置(可选操做)。
  2. boolean addAll(int index, Collection<? extends E> c):将指定集合中的全部元素插入到此列表中的指定位置。 
  3. E get(int index):返回此列表中指定位置的元素。 
  4. int indexOf(Object o):返回此列表中指定元素的第一次出现的索引,若是此列表不包含元素,则返回-1。 
  5. int lastIndexOf(Object o):返回此列表中指定元素的最后一次出现的索引,若是此列表不包含元素,则返回-1。 
  6. E remove(int index):删除该列表中指定位置的元素(可选操做)。 
  7. E set(int index, E element):用指定的元素(可选操做)替换此列表中指定位置的元素。 
  8. List<E> subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置上的子集合。

5.一、ArrayList

ArrayList应该是咱们最多见的集合,同时也是List中最重要的一个。ArrayList的特色是:随机访问、查询快,增删慢,轻量级,线程不安全。它的底层是用Object数组实现的,咱们能够把ArrayList看作是一个可改变大小的数组。随着愈来愈多的元素被添加到ArrayList中,其容量是动态增长的(初始化容量是10,增量是原来的1.5倍  int newCapacity = oldCapacity + (oldCapacity >> 1);)。

5.二、LinkedList

LinkedList底层是经过双向链表实现的,因此它不能随机访问,并且须要查找元素必需要从开头或结尾(从靠近指定索引的一端)开始一个一个的找。使用双向链表则让增长、删除元素比较的方便,但查询变得困难。因此LinkedList的特色是:查询慢,增删快,线程不安全。

因为LinkedList是双向链表实现的,因此它除了有List中的基本操做方法外还额外提供了一些方法在LinkedList的首部或尾部进行操做的方法(实际上是继承Deque中的),如addXXX()、getXXX()、removeXXX()等等。同时,LinkedList还实现了Queue接口的子接口Deque,因此他还提供了offer(), peek(), poll()、pop()、push()等方法。咱们简单来看一下:

  1. void addFirst(E e):在该列表开头插入指定的元素。
  2. void addLast(E e):将指定的元素追加到此列表的末尾。
  3. E element():检索但不删除此列表的头(第一个元素)。
  4. E getFirst():返回此列表中的第一个元素。
  5. E getLast():返回此列表中的最后一个元素。
  6. boolean offer(E e):将指定的元素添加为此列表的尾部(最后一个元素)。
  7. boolean offerFirst(E e):在此列表的前面插入指定的元素。
  8. boolean offerLast(E e):在该列表的末尾插入指定的元素。
  9. E poll XXX():检索并删除此列表的头(第一个元素)。
  10. E peek XXX():检索但不删除此列表的头(第一个元素)。
  11. E pop():今后列表表示的堆栈中弹出一个元素。
  12. void push(E e):将元素推送到由此列表表示的堆栈上。
  13. E remove XXX():从列表中删除指定元素的第一个出现(若是存在)。

5.三、Vector

Vector和ArrayList几乎同样,它们都是经过Object数组来实现的。可是Vector是线程安全的,和ArrayList相比,Vector中不少方法是用synchronized关键字处理过来保证证数据安全,这就必然会影响其效率,因此你的程序若是不涉及到线程安全问题,那么推荐使用ArrayList集合。其实不管如何你们都会选择ArrayList的,由于Vector已经不多用了,几乎面临淘汰。

另外两者还有一个区别就是Vector和ArrayList的扩容策略不同,Vector的扩容增量是原来容量的2倍,而ArrayList是原来的1.5倍。

5.四、Stack

Stack的名称是堆栈。它是继承自Vector这个类,这就意味着,Stack也是经过数组来实现的。Stack的特性是:先进后出(FILO, First In Last Out)。此外Stack中还提供5个额外的方法使得Vector得以被看成堆栈使用。咱们来看一下这五个方法:

  1. boolean empty():测试堆栈是否为空。Stack刚建立后就是空栈。
  2. E peek():查看此堆栈顶部的对象,而不从堆栈中删除它。
  3. E pop():出栈,删除此堆栈顶部的对象,并将该对象做为此函数的值返回。 
  4. E push(E item):压栈,将元素推送到此堆栈的顶部。
  5. int search(Object o):返回一个对象在此堆栈上的基于1的位置。

六、Set接口

Set和List同样都是继承自Collection接口,可是Set和List的特色彻底不同。Set集合中的元素是无顺序的,且没有重复的元素。若是你试图将多个相同的对象添加到Set中,那么很差意思,它会立马阻止。Set中会用equals()和hashCode()方法来判断两个对象是否相同,只要该方法的结果是true,Set就不会再次接收这个对象了。实现了Set接口主要有一下几个:HashSet、LinkedHashSet、TreeSet、EnumSet。Set中没有增长任何新的方法,用的都是继承自中Collection中的。

6.一、HashSet

HashSet是按照哈希算法(hashCode)来存储集合中的对象,因此它是无序的,同时也不能保证元素的排列顺序。其底层是包装了一个HashMap去实现的,因此其查询效率很是高。并且在增长和删除的时候因为运用hashCode的值来比较肯定添加和删除元素的位置,因此不存在元素的偏移,效率也很是高。所以HashSet的查询、增长和删除元素的效率都是很是高的。可是HashSet增删的高效率是经过花费大量的空间换来的:由于空间越大,取余数相同的状况就越小。HashSet这种算法会创建许多无用的空间。使用HashSet接口时要注意,若是发生冲突,就会出现遍历整个数组的状况,这样就使得效率很是的低。HashSet使用简单举例:

public class HashSetTest {
    public static void main(String[] args) {
        //建立HashSet的实例
        HashSet<String> hashSet = new HashSet<>();
        //添加了两个AA元素
        hashSet.add("AA");
        hashSet.add("AA");
        hashSet.add("BB");
        //添加了两个CC元素
        hashSet.add("CC");
        hashSet.add("CC");
        hashSet.add("DD");
        hashSet.add("EE");
        hashSet.add("FF");
        hashSet.add("GG");
        //遍历打印结果
        for (String s : hashSet) {
            System.out.println(s+",hash值是:"+s.hashCode());
        }
    }
}
//运行结果:
//AA,hash值是:2080
//BB,hash值是:2112
//CC,hash值是:2144
//DD,hash值是:2176
//EE,hash值是:2208
//FF,hash值是:2240
//GG,hash值是:2272

6.二、LinkedHashSet

LinkedHashSet继承自HashSet类,它不只实现了哈希算法(hashCode),还实现了链表的数据结构,提供了插入和删除的功能。他有HashSet所有特性,但它新增了一个重要特性,就是元素按照插入的顺序存储。因此当遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里的元素。正是由于多加了这样一种数据结构,因此它的效率较低,不建议使用,若是要求一个集合急要保证元素不重复,也须要记录元素的前后添加顺序,才选择使用LinkedHashSet。LinkedHashSet使用简单举例:

public class LinkedHashSetTest {
    public static void main(String[] args) {
        //建立LinkedHashSet实例
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
        //无序添加元素
        linkedHashSet.add("DD");
        linkedHashSet.add("BB");
        linkedHashSet.add("AA");
        linkedHashSet.add("GG");
        linkedHashSet.add("EE");
        linkedHashSet.add("FF");
        linkedHashSet.add("CC");
        //遍历打印值
        for (String s : linkedHashSet) {
            System.out.println(s+",hash值:"+s.hashCode());
        }
        //删除GG元素
        boolean gg = linkedHashSet.remove("GG");
        System.out.println(gg);
    }
}
//运行结果:
//DD,hash值:2176
//BB,hash值:2112
//AA,hash值:2080
//GG,hash值:2272
//EE,hash值:2208
//FF,hash值:2240
//CC,hash值:2144
//true

6.三、TreeSet

TreeSet的底层是基于TreeMap中实现的。它不只能保证元素的惟一性,还能对元素按照某种规则进行排序。它继承了AbstractSet抽象类,实现了NavigableSet <E>,Cloneable,可序列化接口。而NavigableSet <E>又继承了SortedSet接口,此接口主要用于排序操做,即实现此接口的子类都属于排序的子类,有可排序的功能。TreeSet中的元素支持2种排序方式:天然排序或者定制排序,使用方式具体取决于咱们使用的构造方法(默认使用天然排序)。TreeSet使用简单举例:

public class TreeSetTest {
    public static void main(String[] args) {
        //建立TreeSet实例、使用Comparator定制排序
        TreeSet<Integer> treeSet = new TreeSet<>(new Comparator<Integer>() {
            //排序方式为:降序
            @Override
            public int compare(Integer o1, Integer o2) {
                if (o1>o2){
                    return -1;
                }else if(o1<o2){
                   return 1;
                }else {
                    return 0;
                }
            }
        });
        treeSet.add(2);
        treeSet.add(2);
        treeSet.add(4);
        treeSet.add(4);
        treeSet.add(1);
        treeSet.add(1);
        treeSet.add(3);
        treeSet.add(3);
        for (Integer integer : treeSet) {
            System.out.println(integer);
        }
    }
}
//输出结果:
//4
//3
//2
//1

6.四、EnumSet

EnumSet是专门为枚举类而设计的有序集合类,EnumSet中全部元素都必须是指定枚举类型的枚举值,在建立EnumSet时必须显式或隐式指定它对应的枚举类。EnumSet使用简单举例:

//建立枚举类
public enum Season {
    SPRING,SUMMER,AUTUMN,WINNER;
}

class Test{
    public static void main(String[] args) {
        //EnumSet的简单使用
        EnumSet<Season> seasons = EnumSet.allOf(Season.class);
        //遍历
        for (Season season : seasons) {
            System.out.println(season);
        }
    }
}
//输出结果:
//SPRING
//SUMMER
//AUTUMN
//WINNER

七、Queue接口

Queue接口与List、Set是同一级别的,都继承了Collection接口。Queue表示的是队列,它的特色是:先进先出(FIFO,First-in-First-Out) 。队列主要分为两大类:一类是BlockingDeque阻塞队列(Queue的子接口),它的主要实现类包括ArrayBlockQueue、PriorityBlockingQueue. LinkedBlockingQueue。另外一类是Deque双端队列(也是Queue的子接口),支持在头部和尾部两端插入和移除元素,主要实现类包括:ArrayDeque、LinkedList。

Queue接口中包含的方法有:

  1. booleab add(E e):插入指定的元素要队列中,并返回true或者false,若是队列数量超过了容量,则抛出IllegalStateException的异常。
  2. boolean offer(E e):插入指定的元素到队列,并返回true或者false,若是队列数量超过了容量,不会抛出异常,只会返回false。
  3. E remove():搜索并删除最顶层的队列元素,若是队列为空,则抛出一个Exception。
  4. E poll():搜索并删除最顶层的队列元素,若是队列为空,则返回null。
  5. E element():检索但不删除并返回队列中最顶层的元素,若是该队列为空,则抛出一个Exception。
  6. E peek(): 检索但不删除并返回最顶层的元素,若是该队列为空,则返回null。

对于BlockingDeque阻塞队列的详解能够参考这篇博客:BlockingQueue(阻塞队列)详解 ,写的很是不错。

八、Map接口

Map接口与Collection接口是彻底不一样的。Map中保存的是具备“映射关系”的数据,便是由一系列键值对组成的集合,提供了key到value的映射,也就是说一个key对应一个value,其中key和value均可以是任何引用数据类型。可是Map中不能存在相同的key值,对于相同key值的Map对象会经过equals()方法来判断key值是否相等,只要该方法的结果是true,Map就不会再次接收这个对象了,固然value值能够相同。实现了Map接口的类主要的有如下几个:HashMap、Hashtable、LinkedHashMap、WeakHashMap、TreeMap、IdentifyHashMap、EnumMap。其中Map集合还和Set集合有着很是紧密的联系,由于不少Set集合中底层就是用Map来实现的。

咱们来看一下Map键值对根接口中的方法:

  1. void clear():删除该map集合中的全部键值对映射。
  2. boolean containsKey(Object key):检测map中有没有包含指定值为key的元素,若是有则返回true,不然返回false。
  3. boolean containsValue(Object value):检测map中有没有包含指定值为value的元素,若是有则返回true,不然返回false。
  4. Set<Map.Entry<K,V>> entrySet():返回map到一个Set集合中,以map集合中的Key=Value的形式返回到set中。
  5. V get(Object key):根据map集合中指定的key值来获取相应value值。
  6. Set<K> keySet():返回map集合中全部key。
  7. V put(K key,V value):向map集合中添加key的值和value的值,当添加成功时返回null,不然返回value。
  8. void putAll(Map<? extends K,? extends V> m):把一个map集合合并到另外一个map集合里。
  9. V remove(Object key):删除指定值为key的元素。
  10. int size():返回map集合中元素大小。
  11. Collection<V> values():返回map集合中全部的value值到一个Collection集合。

遍历Map中的对象:Java中四种遍历Map对象的方法

8.一、Hashtable

Hashtable是一个古老的Map实现类,在JDK1.0就提供了,它继承自Dictionary类,底层基于hash表结构+数组+链表实现实现,内部全部方法都是同步的,即线程很安全,可是效率低。注意在Hashtable中key和value均不可为null。

8.二、HashMap

HashMap是Map集合中使用最多的,它是Hashtable的一个轻量级版本,它是继承了Abstractmap类,底层也是基于hash表结构+链表(红黑树,链表长度大于8会将链表转化成红黑树)+数组实现的,内部全部方法是不一样步的,即线程不安全,可是效率高。在HashtMap中key和value均都可为null。

8.三、LinkedHashMap

LinkedHashMap基于双向链表和数组实现,内部结构和HashMap相似,就是多加了一个双向链表结构。根据key的插入顺序进行存储。(注意和TreeMap对全部的key-value进行排序进行区分)

8.四、WeakHashMap

WeakHashMap与HashMap的用法基本类似。区别在于,HashMap的key保留了对实际对象的"强引用",这意味着只要该HashMap对象不被销毁,该HashMap所引用的对象就不会被垃圾回收。但WeakHashMap的key只保留了对实际对象的弱引用,这意味着若是WeakHashMap对象的key所引用的对象没有被其余强引用变量所引用,则这些key所引用的对象可能被垃圾回收,当垃圾回收了该key所对应的实际对象以后,WeakHashMap也可能自动删除这些key所对应的key-value对。

8.五、TreeMap

TreeMap底层是用红黑树算法实现,它实现SortMap接口,因此其内部元素默认按照全部的key进行排序。固然也支持2种排序方式:天然排序或者定制排序。其中TreeMap中的key不可null,而它非线程安全的。使用能够参考上面的TreeSet示例,使用方式差很少。

8.六、IdentifyHashMap

IdentityHashMap是一种可重复key的集合类。它和HashMap相似,因此咱们通常都是拿IdentityHashMap和HashMap来进行比较,由于它们二者判断重复key的方式不同。IdentifyHashMap中判断重复key相等的条件是:(k1==k2),也就是说它只比较普通值是否相等,不比较对象中的内容。而HashMap中类判断重复key相等的条件是: (k1==null?k2==null:k1.equals(k2))==true),它不只比较普通值,并且比对象中的内容是否相等。简单举例:

public class MapTest {
    public static void main(String[] args) {
        //建立HashMap实例,添加Integer实例为key
        HashMap hashMap=new HashMap();
        hashMap.put(1,"hello");
        hashMap.put(1,"hello");
        hashMap.put(new Integer(2),"hello");
        hashMap.put(new Integer(2),"hello");
        hashMap.put(new Integer(2),"hello");
        System.out.println("HashMap:"+hashMap.toString());
        //建立IdentityHashMap实例,添加Integer实例为key
        IdentityHashMap<Object, Object> identityHashMap = new IdentityHashMap<>();
        identityHashMap.put(3,"world");
        identityHashMap.put(3,"world");
        identityHashMap.put(new Integer(4),"world");
        identityHashMap.put(new Integer(5),"world");
        identityHashMap.put(new Integer(4),"world");
        System.out.println("IdentityHashMap:"+identityHashMap.toString());
    }
}
//运行结果:
//HashMap:{1=hello, 2=hello}
//IdentityHashMap:{4=world, 4=world, 3=world, 5=world}

8.七、EnumMap

EnumMap这个类是专门为枚举类而设计的有键值对的集合类。集合中的全部键(key)都必须是单个同一个类型的枚举值,建立EnumMap时必须显式或隐式指定它对应的枚举类。当EnumMap建立后,其内部是以数组形式保存,因此这种实现形式很是紧凑高效。EnumMap根据key的天然顺序(即枚举值在枚举类中的定义顺序)来维护来维护key-value对的次序。能够经过keySet()、entrySet()、values()等方法来遍历EnumMap便可看到这种顺序。EnumMap不容许使用null做为key值,但容许使用null做为value。若是试图使用null做为key将抛出NullPointerException异常。若是仅仅只是查询是否包含值为null的key、或者仅仅只是使用删除值为null的key,都不会抛出异常。EnumMap的代码示例以下:

//建立枚举类
public enum Season {
    SPRING,SUMMER,AUTUMN,WINNER;
}

class Test{
    public static void main(String[] args) {
        //EnumMap的简单使用
        EnumMap<Season,String> map=new EnumMap<Season, String>(Season.class);
        map.put(Season.SPRING,"春暖花开");
        map.put(Season.SUMMER,"夏日炎炎");
        map.put(Season.AUTUMN,"秋高气爽");
        map.put(Season.WINNER,"冬暖夏凉");
        //遍历map有不少种方式,这里是map遍历的一种方式,这种方式是最快的
        for (EnumMap.Entry<Season,String> entry:map.entrySet()){
            System.out.println(entry.getKey()+","+entry.getValue());
        }
    }
}
//输出结果:
//SPRING,春暖花开
//SUMMER,夏日炎炎
//AUTUMN,秋高气爽
//WINNER,冬暖夏凉

九、Collections工具类

Collections是集合的一个工具类或者帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各类操做。

  1. addAll(Collection<? super T> c, T... elements):将全部指定的元素添加到指定的集合。
  2. copy(List<? super T> dest, List<? extends T> src):将全部元素从一个列表复制到另外一个列表中。
  3. disjoint(Collection<?> c1, Collection<?> c2):若是两个指定的集合没有共同的元素,则返回 true 。
  4. fill(List<? super T> list, T obj):用指定的元素代替指定列表的全部元素。
  5. max(Collection<? extends T> coll):根据其元素的天然顺序返回给定集合的最大元素。
  6. min(Collection<? extends T> coll):根据其元素的天然顺序返回给定集合的最小元素。
  7. nCopies(int n, T o):返回由指定对象的 n副本组成的不可变列表。
  8. replaceAll(List<T> list, T oldVal, T newVal):将列表中一个指定值的全部出现替换为另外一个。
  9. reverse(List<?> list):反转指定列表中元素的顺序。
  10. rotate(List<?> list, int distance):将指定列表中的元素旋转指定的距离。
  11. shuffle(List<?> list):使用默认的随机源随机排列指定的列表。
  12. sort(List<T> list):对集合列表进行排序。
  13. swap(List<?> list, int i, int j):交换指定列表中指定位置的元素。

以上只是一些常见的方法,若是须要了解更多的方法能够自行去查看Collections的API。

Relevant Link

http://www.javashuo.com/article/p-wjyklgab-n.html

http://www.javashuo.com/article/p-miqztzvv-a.html

相关文章
相关标签/搜索