JAVA基础--Collection集合

160 阅读6分钟

java集合框架图

image.png

由上面的集合框架图可以看到,java集合框架主要包括两种类型的容器。

  • 集合(Collection) 存储一个元素集合
  • 图(Map) 存储键值对映射

Collection集合

集合概述

  • 集合定义: 集合是java中提供的一种容器,可以用来存储多个数据。
  • 集合和数组的区别:
    • 数组的长度是固定的;集合长度是可变的。
    • 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。
  • Collection接口的子类型:
    • List
    • Set
    • Queue

List集合

java.util.List 接口继承自 Collection 接口,是单列集合的一个重要分支,习惯性地会将实现了List 接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行 存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。

List接口特点:

    1. 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。
    1. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
    1. 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。

List接口常用方法:

  • public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。

  • public E get(int index) :返回集合中指定位置的元素。

  • public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。

  • public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

ArrayList集合

java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用 最多的功能为查询数据、遍历数据,所以 ArrayList 是最常用的集合。

ArrayList特点:

  • ArrayList的底层是数组队列,相当于动态数组。它的容量能够动态增长。
  • ArrayList提供了增删改查等功能。继承了AbstractList。
  • ArrayList支持序列化,能够通过序列化去传输。实现了java.io.Serializable接口。
  • ArrayList能被克隆。实现了Cloneable接口。
  • ArrayList支持快速随机访问。实现了RandomAccess接口。
  • ArrayList中的操作不是线程安全的。

ArrayList经典Demo:

public class ArrayListDemo {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        System.out.println("Before add: "+arrayList.size());
        arrayList.add(1);
        arrayList.add(3);
        arrayList.add(5);
        arrayList.add(7);
        arrayList.add(9);
        arrayList.add(11);
        System.out.println("After add: "+arrayList.size());
        System.out.println("Printing elements of arrayList");
        //一、通过迭代器
        System.out.println("通过迭代器遍历:");
        Iterator<Integer> it = arrayList.iterator();
        while (it.hasNext()){
            System.out.printf(it.next()+"  ");
        }
        System.out.println();
        //二、for i
        System.out.println("通过索引值遍历:");
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.printf(arrayList.get(i)+"  ");
        }
        System.out.println();
        //三、for each
        System.out.println("通过for循环遍历:");
        for (Integer number:arrayList) {
            System.out.printf(number+"  ");
        }
        System.out.println();
        
        //toArray用法
        //第一种
        Integer[] integers = arrayList.toArray(new Integer[0]);
        //第二种
        Integer[] integers1 = new Integer[arrayList.size()];
        arrayList.toArray(integers1);
        System.out.println();
        
        //在指定位置添加元素
        arrayList.add(2,2);
        //删除指定位置的元素
        arrayList.remove(2);
        //删除指定元素
        arrayList.remove((Object)3);
        //判断集合是否含有5
        arrayList.contains(5);
        //清空集合
        arrayList.clear();
        //判断集合是否为空
        arrayList.isEmpty();

    }
}

LinkedList集合

java.util.LinkedList 集合数据存储的结构是链表结构。方便元素添加、删除的集合。

LinkedList特点:

  • LinkedList实现了List接口和Deque接口的双端链表。
  • LinkedList底层的链表结构使得它具有高效的插入和删除操作。
  • LinkedList具有队列特性。
  • LinkedList不是线程安全的。

要使LinkedList线程安全方法:调用synchronizedList方法 Lisi list = Collections.synchronizedList(new LinkedList(...));

LinkedList常用方法:

  • public void addFirst(E e) :将指定元素插入此列表的开头。
  • public void addLast(E e) :将指定元素添加到此列表的结尾。
  • public E getFirst() :返回此列表的第一个元素。
  • public E getLast() :返回此列表的最后一个元素。
  • public E removeFirst() :移除并返回此列表的第一个元素。
  • public E removeLast() :移除并返回此列表的最后一个元素。
  • public E pop() :从此列表所表示的堆栈处弹出一个元素。
  • public void push(E e) :将元素推入此列表所表示的堆栈。
  • public boolean isEmpty() :如果列表不包含元素,则返回true。

LinkedList经典Demo:

public class LinkedListDemo {
    public static void main(String[] srgs) {
        //创建存放int类型的linkedList
        LinkedList<Integer> linkedList = new LinkedList<>();

        /************************** linkedList的基本操作 ************************/
        linkedList.addFirst(0); // 添加元素到列表开头
        linkedList.add(1); // 在列表结尾添加元素
        linkedList.add(2, 2); // 在指定位置添加元素
        linkedList.addLast(3); // 添加元素到列表结尾
        System.out.println("LinkedList(直接输出的): " + linkedList);
        System.out.println("getFirst()获得第一个元素: " + linkedList.getFirst()); // 返回此列表的第一个元素
        System.out.println("getLast()获得第最后一个元素: " + linkedList.getLast()); // 返回此列表的最后一个元素
        System.out.println("removeFirst()删除第一个元素并返回: " + linkedList.removeFirst()); // 移除并返回此列表的第一个元素
        System.out.println("removeLast()删除最后一个元素并返回: " + linkedList.removeLast()); // 移除并返回此列表的最后一个元素
        System.out.println("After remove:" + linkedList);
        System.out.println("contains()方法判断列表是否包含1这个元素:" + linkedList.contains(1)); // 判断此列表包含指定元素,如果是,则返回true
        System.out.println("该linkedList的大小 : " + linkedList.size()); // 返回此 列表的元素个数

        /************************** 位置访问操作 ************************/
        System.out.println("-----------------------------------------");
        linkedList.set(1, 3); // 将此列表中指定位置的元素替换为指定的元素
        System.out.println("After set(1, 3):" + linkedList);
        System.out.println("get(1)获得指定位置(这里为1)的元素: " + linkedList.get(1)); // 返回此列表中指定位置处的元素

        /************************** Search操作 ************************/
        System.out.println("-----------------------------------------");
        linkedList.add(3); System.out.println("indexOf(3): " + linkedList.indexOf(3)); // 返回此列表 中首次出现的指定元素的索引
        System.out.println("lastIndexOf(3): " + linkedList.lastIndexOf(3));// 返回此列表中最后出现的指定元素的索引

        // /************************** Queue操作 ************************/
        System.out.println("-----------------------------------------");
        System.out.println("peek(): " + linkedList.peek()); // 获取但不移除此列表的头
        System.out.println("element(): " + linkedList.element()); // 获取但不移除此列表的头
        linkedList.poll(); // 获取并移除此列表的头
        System.out.println("After poll():" + linkedList);
        linkedList.remove();
        System.out.println("After remove():" + linkedList); // 获取并移除此列表的头
        linkedList.offer(4);
        System.out.println("After offer(4):" + linkedList); // 将指定元素添加到此列 表的末尾

        /************************** Deque操作 ************************/
        System.out.println("-----------------------------------------");
        linkedList.offerFirst(2); // 在此列表的开头插入指定的元素
        System.out.println("After offerFirst(2):" + linkedList);
        linkedList.offerLast(5); // 在此列表末尾插入指定的元素
        System.out.println("After offerLast(5):" + linkedList);
        System.out.println("peekFirst(): " + linkedList.peekFirst()); // 获取但不 移除此列表的第一个元素
        System.out.println("peekLast(): " + linkedList.peekLast());// 获取但不移 除此列表的第一个元素
        linkedList.pollFirst(); // 获取并移除此列表的第一个元素
        System.out.println("After pollFirst():" + linkedList);
        linkedList.pollLast(); // 获取并移除此列表的最后一个元素
        System.out.println("After pollLast():" + linkedList);
        linkedList.push(2); // 将元素推入此列表所表示的堆栈(插入到列表的头)
        System.out.println("After push(2):" + linkedList);
        linkedList.pop(); // 从此列表所表示的堆栈处弹出一个元素(获取并移除列表第一个元 素)
        System.out.println("After pop():" + linkedList);
        linkedList.add(3);
        linkedList.removeFirstOccurrence(3); // 从此列表中移除第一次出现的指定元素(从 头部到尾部遍历列表)
        System.out.println("After removeFirstOccurrence(3):" + linkedList);
        linkedList.removeLastOccurrence(3); // 从此列表中移除最后一次出现的指定元素(从 尾部到头部遍历列表)
        System.out.println("After removeFirstOccurrence(3):" + linkedList);

        /************************** 遍历操作 ************************/
        System.out.println("-----------------------------------------");
        linkedList.clear(); for (int i = 0; i < 100000; i++) {
            linkedList.add(i);
        }
        // 迭代器遍历
        long start = System.currentTimeMillis();
        Iterator<Integer> iterator = linkedList.iterator();
        while (iterator.hasNext()) { 
            iterator.next();
        }
        long end = System.currentTimeMillis(); 
        System.out.println("Iterator:" + (end - start) + " ms");
        // 顺序遍历(随机遍历) 
        start = System.currentTimeMillis();
        for (int i = 0; i < linkedList.size(); i++) {
            linkedList.get(i);
        }
        end = System.currentTimeMillis();
        System.out.println("for:" + (end - start) + " ms");
        // 另一种for循环遍历
        start = System.currentTimeMillis(); 
        for (Integer i : linkedList) ; 
        end = System.currentTimeMillis();
        System.out.println("for2:" + (end - start) + " ms"); 
        // 通过pollFirst()或pollLast()来遍历LinkedList 
        LinkedList<Integer> temp1 = new LinkedList<>(); 
        temp1.addAll(linkedList); 
        start = System.currentTimeMillis(); 
        while (temp1.size() != 0) { 
            temp1.pollFirst();
        }
        end = System.currentTimeMillis(); 
        System.out.println("pollFirst()或pollLast():" + (end - start) + " ms");
        
        // 通过removeFirst()或removeLast()来遍历LinkedList 
        LinkedList<Integer> temp2 = new LinkedList<>(); 
        temp2.addAll(linkedList); 
        start = System.currentTimeMillis();
        while (temp2.size() != 0) { 
            temp2.removeFirst(); 
        }
        
        end = System.currentTimeMillis(); 
        System.out.println("removeFirst()或removeLast():" + (end - start) + " ms");
    }
}

Set集合

java.util.Set 接口和 java.util.List 接口一样,同样继承自 Collection 接口,它与 Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比 Collection 接口更加严格了。与 List 接口不同的是, Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。

HashSet集合

java.util.HashSet 是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。 java.util.HashSet 底层的实现其实是一个 java.util.HashMap 支持。

HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于: hashCode 与 equals 方法。

HashSet特点:

  • 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也可能发生变化;
  • HashSet不是同步的;
  • 集合元素值可以是null;

image.png

LinkedHashSet集合

我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?在HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构。

TreeSet

TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。

内部存储机制
TreeSet内部实现的是红黑树,默认整形排序为从小到大。

TreeSet常用方法:

  • Comparator comparator():如果TreeSet采用了定制顺序,则该方法返回定制排序所使用的Comparator,如果TreeSet采用自然排序,则返回null;
  • Object first():返回集合中的第一个元素;
  • Object last():返回集合中的最后一个元素;
  • Object lower(Object e):返回指定元素之前的元素。
  • Object higher(Object e):返回指定元素之后的元素。
  • SortedSet subSet(Object fromElement,Object toElement):返回此Set的子集合,含头不含尾;
  • SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成;
  • SortedSet tailSet(Object fromElement):返回此Set的子集,由大于fromElement的元素组成;

EnumSet

  • EnumSet是一个专门为枚举类设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。
  • EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用内存很小,而且运行效率很好。
  • EnumSet集合不允许加入null元素。

Queue

队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作。

Queue特点:

  • 先进先出
  • 线程安全 Queue常用操作:

add        增加一个元索                     如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常
offer       添加一个元素并返回true       如果队列已满,则返回false
poll         移除并返问队列头部的元素    如果队列为空,则返回null
peek       返回队列头部的元素             如果队列为空,则返回null
put         添加一个元素                      如果队列满,则阻塞
take        移除并返回队列头部的元素     如果队列为空,则阻塞