Java中的采集框架--深入研究

116 阅读7分钟

什么是集合

Java中的集合是将一组对象合并为一个对象。

什么是框架

一个框架是一组类和接口,它提供了一个定义明确的架构,可以随时随地使用:

  • Java中的集合框架是一个用于创建、操作和更新对象的定义明确的架构。
  • 它由高效的算法组成,可以降低各种操作的成本,如搜索、排序、追加等。
  • 总之,它们是可重复使用的数据结构。
  • JavaJDK 1.2开始引入集合框架。

在Java中使用集合框架的好处

  • 减少了编程工作: 由于集合框架提供了有用的数据结构和算法,它为我们节省了更多的时间来关注我们程序的重要领域。
  • 提高了程序的速度和质量: 此外,它还为开发者提供了高效和高性能的数据结构和算法的实现。
  • 一致的API :API由各种接口组成,例如List、Set、Map、Collection,并且可以由ArrayList、HashMap、HashSet等各种类来实现。

集合框架的接口

集合框架的核心接口

集合接口

  • 它是集合框架的父接口/根接口。
  • 此外,集合框架还有一个父接口,即Iterable接口
  • Java平台没有提供这个接口的直接实现,而是提供了诸如Set、List、Queue、Deque等子接口。
  • 它包含各种抽象方法,这些方法由集合框架的几个类进一步实现。这些方法是:-
    • add(Object)- 用于向集合中添加一个对象
    • addAll(Collection c)- 将给定集合中的所有元素(参数中给出)添加到一个集合中。
    • clear()- 从一个集合中删除/移除所有的元素
    • contains(Object o)- 如果一个元素存在于集合中,返回真/假。
    • containsAll(Collection c)- 如果所有元素(存在于参数集合中)都存在于集合中,则返回真/假。
    • equals(Object o)- 在比较了给定对象和集合的值之后,返回真/假。
    • hashCode()- 返回集合的哈希代码值。
    • isEmpty()- 如果集合是空的,返回true/false。
    • iterator()- 返回一个指向集合中第一个元素的迭代器。
    • max()- 返回集合中存在的最大值。
    • parallelStream()- 返回一个以该集合为源的并行流。
    • remove(Object o)- 从集合中删除第一个出现的对象。
    • removeAll(Collection c)- 从集合中移除所有给定对象的出现次数。
    • removeIf(Predicate filter)- 删除这个集合中满足给定谓词的所有元素。
    • retainAll(Collection c)- 只保留该集合中属于参数集合'c'的元素。
    • size()- 返回集合中存在的元素数量。
    • spliterator()- 用于在这个集合中的元素上创建一个splitator。
    • stream()- 返回一个以这个集合为源的连续的Stream。
    • toArray()- 返回一个包含该集合中所有元素的数组。

集合接口

  • 它是一个不包含重复元素的集合
  • 我们可以执行数学中所有基本的集合操作,如并集、交集和差集。
  • Java平台包含三种Set的实现。HashSet, TreeSet, 和 LinkedHashSet
    • HashSet - 将其元素存储在一个哈希表中,它是所有实现中性能最好的,但这里不保持插入顺序。
    • TreeSet- 将其元素存储在红黑树中,根据其值对其元素进行排序;它比HashSet慢得多。
    • LinkedHashSet- 实现为一个哈希表,有一个链接列表贯穿其中,根据元素插入集合的顺序(插入顺序)对其进行排序。
  • 例如,Set接口的实现看起来像:
import java.util.*;
public class Demo
{
    public static void main(String args[])
    {
        int count[] = {1000,900,800,125,650};
        Set<Integer> set = new HashSet<Integer>();
        try {
            for(int i = 0; i < 5; i++) {
                set.add(count[i]);
            }
            System.out.println(set);

            TreeSet sortedSet = new TreeSet<Integer>(set);
            System.out.println("The sorted list is:");
            System.out.println(sortedSet);

            System.out.println("The First element of the set is: "+ (Integer)sortedSet.first());
            System.out.println("The last element of the set is: "+ (Integer)sortedSet.last());
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
} 

列表接口

  • 列表接口继承了集合接口,存在于java.util包中。
  • 它帮助我们存储有序的集合(按顺序/插入顺序)。
  • 与Set接口不同,List接口允许在集合中存在重复的元素,并在索引的基础上存储对象。
  • List接口包括以下的操作:
    • 位置访问--根据元素在列表中的数字位置来操作它们。这包括诸如get、set、add、addAll和remove等方法。
    • 搜索- 在列表中搜索指定的对象并返回其数字位置。搜索方法包括indexOf和lastIndexOf。
  • List接口一般有三种实现方式 -
    • 阵列列表
    • 链接列表
    • 矢量
  • 例如,List接口的实现看起来像:
import java.util.*;

class Demo {

    public static void main(String args[])
    {
        List<String> al = new ArrayList<>();

        al.add("item 1");
        al.add("item 2");
        al.add(1, "item 3");

        System.out.println(al);
    }
}

队列接口

  • 队列接口也继承了集合接口,并存在于java.util包中。
  • 这个接口使用FIFO(先进先出)原则来存储和检索对象,也就是说,先插入的对象就是先被删除/检索的对象。就像在电影院大厅前排队买票一样。
  • 它是一个有序的集合,集合中的元素在队列的末尾插入,从队列的开始删除。
  • Queue接口的方法有:-
    • boolean add(object)-用于向队列中插入一个元素,如果插入成功则返回true,否则抛出一个异常。
    • boolean offer(object)-用于在队列中插入一个元素,如果插入成功则返回true,否则返回false。
    • remove()-用于返回并从队列的头部/前端移除元素。
    • poll()-用于返回并从队列的头部移除元素,如果这个队列是空的,则返回null。
    • **element()-**用来检索但不删除这个队列的头部。
    • **peek()-**用于检索,但不删除这个队列的头部,如果这个队列是空的,则返回null。
  • 在java中,队列接口一般有两种实现。
    • 链接列表
    • 优先级队列(PriorityQueue
  • 例如,队列接口的实现看起来像。
import java.util.LinkedList;
import java.util.Queue;

class Demo {

    public static void main(String[] args)
    {
        Queue<Integer> q = new LinkedList<>();

        for (int i = 0; i < 5; i++)
            q.add(i);

        System.out.println("Elements of queue " + q);

        int removedele = q.remove();
        System.out.println("removed element-"+removedele);

        System.out.println(q);

        int head = q.peek();
        System.out.println("head of queue-" + head);

        int size = q.size();
        System.out.println("Size of queue-" + size);
    }
}

Dequeue接口

  • Dequeue接口支持从两端插入和删除对象,即从前面和后面。
  • 此外,Deque接口的一些方法包括:-
    • boolean add(object)
    • boolean offer(object)
    • remove()
    • poll()
    • element()
    • peek()
  • 一般来说,Deque接口有2种实现方式
    • ArrayDeque
    • 链接列表
  • 例如,Deque接口的实现看起来像。
import java.util.*;

public class Demo {
    public static void main(String[] args)
    {
        Deque<String> deque = new LinkedList<String>();

        deque.add("Element 1");

        deque.addFirst("Element 2");

        deque.addLast("Element 3");

        deque.push("Element 4");

        deque.offer("Element 5");

        deque.offerFirst("Element 6");

        System.out.println(deque + "\n");

    }
}

地图接口

  • 这个集合是用来存储键值对的,每个键值对一般被称为条目
  • 此外,Map接口不是Collection接口的子类:
    • HashMap
    • HashTable
    • 树状图
  • 例如,Map接口的实现看起来像:
import java.util.*;
class Demo {
    public static void main(String[] args) {
        Map map=new HashMap();
        //Adding elements to map  
        map.put(1,"value 1");
        map.put(5,"value 5");
        map.put(2,"value 2");
        map.put(6,"value 6");
        Set set=map.entrySet();
        
        Iterator itr=set.iterator();
        
        while(itr.hasNext()){
            Map.Entry entry=(Map.Entry)itr.next();
            System.out.println(entry.getKey()+" "+entry.getValue());
        }
    }
}  

集合框架中的重要类

阵列列表

  • ArrayList是List接口的一个实现,它是可调整大小的,可以存储多种数据类型,而不像array是固定大小的,只能存储单一类型的元素。

  • 当一个对象被创建时,ArrayList的默认大小是10。

  • ArrayList的新大小是由公式决定的,newCapacity
    = oldCapacity + (oldCapacity >> 1)

  • 假设oldCapacity是10,因此新的容量将被计算如下:-newCapacity
    = 10 + (10 >> 1)
    newCapacity= 10 + (5)
    newCapacity= 15

  • 总之,关于ArrayList的一些要点是:----

    • 允许重复的元素。
    • 保持插入/顺序。
    • 允许通过索引进行随机访问。
    • 如果ArrayList中的删除较少或没有删除,那么ArrayList比Linked List更受欢迎,因为它需要将元素移动一个位置,这是一种成本开销。
  • 例如,ArrayList的实现是这样的:

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        ArrayList<String> cars = new ArrayList<String>();
        cars.add("Maruti");
        cars.add("Hyundai");
        cars.add("Honda");
        cars.add("Ford");
        System.out.println(cars);
    }
}

链接表

  • LinkedList在内部使用一个双链表。
  • 它实现了List、Queue和Deque接口。
  • 在LinkedList类中,由于不需要像ArrayList那样对元素进行移位,所以对元素的操作更快。
  • 它不能被随机访问,它必须以顺序的方式从LinkedList的头部到尾部进行遍历。
  • LinkedList类可以包含重复的元素。
  • 它保持了插入的顺序。
  • LinkedList类通常可以作为一个列表、堆栈或者队列来使用。
  • LinkedList的实现看起来像:
import java.util.LinkedList;

public class Demo {
    public static void main(String[] args) {
        LinkedList<String> cars = new LinkedList<String>();
        cars.add("Maruti");
        cars.add("Hyundai");
        cars.add("Honda");
        cars.add("Ford");
        System.out.println(cars);
    }
}

HashSet

  • HashSet类实现了Set接口,由于它是一个HashMap实例,所以由一个哈希表支持。
  • HashSet只包含唯一的元素。
  • 不保证集合的迭代顺序,这意味着该类不保证元素的顺序随时间变化而不变。
  • HashSet的初始默认容量为16,负载系数为0.75。
  • 散列提供了最佳的搜索操作,其最差的时间复杂度为O(1),是恒定的。
  • HashSet中允许有NULL元素。
  • HashSet还实现了Serializable和Cloneable接口。
  • HashSet的实现看起来像:
import java.util.HashSet;

public class Demo {
    public static void main(String[] args) {
        HashSet<String> cars = new HashSet<String>();
        cars.add("Maruti");
        cars.add("Hyundai");
        cars.add("Honda");
        cars.add("Ford");
        System.out.println(cars);
    }
}

HashMap

  • 它以(Key, Value)对的形式存储数据,你可以通过另一种类型的索引(例如,整数)来访问它们。
  • Java HashMap只包含唯一的键。
  • 它可以有一个空键和多个空值。
  • 它是不同步的。
  • Java HashMap不保持顺序。
  • Java HashMap类的初始默认容量为16,负载因子为0.75。
  • HashMap的实现看起来像。
import java.util.HashMap;

public class Demo {
    public static void main(String[] args) {
        HashMap<String, String> capitalCities = new HashMap<String, String>();

        // Add keys and values (Country, City)
        capitalCities.put("India", "Delhi");
        capitalCities.put("Spain", "Madrid");
        capitalCities.put("USA", "Washington DC");
        System.out.println(capitalCities);
    }
}

堆栈

  • Java集合框架提供了一个Stack类,它模拟并实现了一个Stack数据结构。
  • 该类是基于后进先出的基本原则。
  • 除了基本的push和pop操作外,该类还提供了empty、search和peek三种功能。
  • 该类也可以说是对Vector的扩展,并将该类作为一个具有上述五个功能的堆栈。
  • 堆栈类的实现看起来像。
import java.util.Stack;

public class Demo {
    public static void main(String[] args) {
        Stack<Integer> stack=new Stack<Integer>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println(stack.peek());
        stack.pop();
        System.out.println(stack);
    }
}