Java集合Collection接口(超详解)

一、Collection

(日常学习笔记,不喜勿喷,欢迎纠错与探讨!)

什么是Collection接口?

Java中有一个集合这么一个大类,Collection是集合类中的单列集合。他是所有单列集合的父接口。Collection的子接口有List接口和Set接口。这意味着所有的单列集合类都是继承了这个接口。它定义了一些集合共有的基本方法,如添加、删除、查询和遍历元素等方法。

Java集合Collection接口(超详解)_第1张图片

Collection子接口的特点:

1.相同点:
  • 它们都是Collection集合的子接口,因此都继承了Collection接口,定义了Collection接口的所有方法。
  • 它们都是异步的,在多线程环境下,它们进行的操作不是原子的,所以它们被设计成并发类。
2.不同点:
  • List接口:
    • 元素存储有序,List存储元素和取出元素的顺序是一致的,即按照添加的顺序进行存储和取出。
    • 元素可重复,可以包含重复元素:List允许存储重复的元素。
    • 元素带索引:List接口中定义了一些带索引的方法,如get(int index)可以获取指定位置的元素,add(int index, E element)可以在指定位置添加元素等。
  • Set接口:
    • 元素存储无序Set存储元素和添加元素的顺序无关,即无法保证存储和取出的顺序。
    • 元素不可重复Set不允许存储重复的元素,相同的元素只会被存储一次。
    • 可以存储null元素:Set可以存储一个null元素,但只能存储一次。

Collection作为父类有那些方法:

Collection<String> c = new ArrayList<>();

//向集合中添加元素,如果添加成功返回true,如果集合因为添加元素而改变,其他集合也应该改变。
c.add(E e);

//从集合中删除元素,如果删除成功返回true,如果集合因为删除元素而改变,其他集合也应该改变。
c.remove(Object o);

// 检查集合中是否包含指定元素,如果包含返回true。
c.contains(Object o);

// 返回集合中元素的数量。
c.size();

//检查集合是否为空,如果为空返回true。
c.isEmpty();

//返回一个迭代器,用于遍历集合中的元素。
Iterator<String> it = c.iterator();
while (it.hasNext()) {//判断集合中还有没有没有被遍历 的元素
	String str = it.next();//获取下一个没有被遍历的元素
}

//返回一个包含集合中所有元素的数组。
c.toArray();

//移除集合中的所有元素,使集合为空。
c.clear();

Collection作为一个父接口,有以下几种实现类:

  1. ArrayList:基于数组实现,可以快速随机访问元素,但在插入或删除元素时需要将插入或删除位置的元素整体后移或前移,因此效率较低。
  2. LinkedList:基于链表实现,可以快速在列表的两端插入或删除元素,但在随机访问元素时效率较低。
  3. HashSet:基于哈希表实现,可以快速查找元素,但在处理重复元素时效率较低。
  4. TreeSet:基于红黑树实现,可以保持元素有序,但插入和删除元素的效率较低。
  5. LinkedHashSet:基于哈希表和链表实现,可以快速查找元素,保持元素有序,但在处理重复元素时效率较低。

此外,还有Vector和Stack等实现类,但它们已经被标记为过时或不建议使用。

                                 ----分割线----

二、List

实现类:ArrayList

ArrayList是Java集合框架中的一种实现类,基于动态数组实现,可以存储任意类型的数据,并且可以自动扩容。

特点概述
  1. 容量可动态扩展:ArrayList可以根据需要动态增长容量,当元素数量超过当前容量时,会自动分配更大的内部数组,并将原有元素复制到新数组中。
  2. 支持快速随机访问:由于基于动态数组实现,ArrayList支持快速的随机访问,可以通过索引直接访问元素,时间复杂度为O(1)。
  3. 支持批量操作:ArrayList提供了一系列的add()方法,可以一次性添加多个元素,提高了操作的效率。
  4. 非线程安全:ArrayList不是线程安全的,如果多个线程同时修改ArrayList,可能会导致数据不一致的问题。
ArrayList常见用法:
// 使用多态创建ArrayList对象,其父类为List,子类为ArrayList。
List<String> list = new ArrayList<>();

// 添加元素
list.add(1);
list.add(1, 2); // 在指定位置插入元素

// 获取元素
String apple = list.get(0); // 获取第一个元素

// 删除元素
list.remove(0); // 删除第一个元素

//替换指定位置的元素
list.set(0, 3);

//查询指定元素的索引
int index = list.indexOf(2);

//判断列表是否为空
boolean isEmpty = list.isEmpty();

//获取列表元素数量
int size = list.size();

//将列表转换为数组
Integer[] toArray = list.toArray(new Integer[0]);

// 查询元素是否存在
boolean containsApple = list.contains(1);

// 清空列表
list.clear();

实现类:LinkedList

LinkedList是Java集合框架的一种实现类,允许直接访问其元素。它是一个双向链表,可以快速在列表的头部和尾部进行插入和删除操作。

特点概述:
  1. 动态数组LinkedList在内部使用动态数组,因此在进行元素添加、删除和查询操作时,它比静态数组更快。
  2. 双向插入或删除:可以从头部和尾部进行插入和删除LinkedList支持在头部和尾部进行高效的插入和删除操作,因为它是双向链表。
  3. 不是线程安全的:LinkedList不是线程安全的,如果多个线程同时修改它,可能会导致数据不一致的问题。
LinkedList的常见用法:
// 使用多态创建LinkedList对象,其父类为List,子类为LinkedList。
List<String> list = new LinkedList<>();

// 在列表的末尾添加指定的元素。
add(E element);

//在指定位置插入指定的元素。
add(int index, E element); 

//移除列表中首次出现的指定元素。
remove(Object o);

//返回列表中包含指定元素的结果。
contains(Object o);

//返回首次出现的指定元素的索引。
indexOf(Object o);

//检查列表是否为空。
isEmpty();

//返回列表中的元素数量。
size();

//获取指定位置的元素。
get(int index);

//替换指定位置的元素。
set(int index, E element); 

                                 ----分割线----

三、Set

实现类HashSet

HashSet是Java中的一种数据结构,它实现了Set接口。Set是一种不允许存储重复元素的集合,且底层通常封装了哈希表。

特点概述
  1. 不允许存储重复元素:Set中的每个元素都是唯一的,不允许出现重复的元素。
  2. 无序的:HashSet是一种无序的集合,即存储的元素按照一定的顺序进行存储,但元素的存储顺序与元素的实际顺序无关。
  3. 底层封装了哈希表:HashSet是基于哈希表实现的,因此它的添加、删除和查询等操作的时间复杂度通常是O(1)。
  4. 线程不安全:由于HashSet没有同步机制,因此它是非线程安全的。在多线程环境下,如果多个线程同时修改HashSet,可能会导致数据不一致的问题。
  5. 允许存储null值:与List不同,Set允许存储null值。
HashSet常见用法:
//添加元素:使用`add(E e)`方法向Set中添加元素。如果元素已经存在,会被忽略,因为Set不允许重复元素。
HashSet<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
set.add("cherry");

//删除元素:使用remove(Object o)方法从Set中删除指定元素。如果元素不存在,删除操作会返回false。
set.remove("banana");

//查询元素:使用contains(Object o)方法查询Set中是否包含指定元素。
boolean containsApple = set.contains("apple");

//获取元素个数:使用size()方法获取Set中的元素个数。
int size = set.size();

//清空Set:使用clear()方法移除Set中的所有元素。
set.clear();

//迭代Set:使用iterator()方法返回一个迭代器,可以用来遍历Set中的所有元素。注意,返回元素的顺序并不是特定的。
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

实现类LinkedHashSet

LinkedHashSet是HashSet的子类,存在于java.util包下。它是一种特殊的HashSet。

特点概述
  1. 有序性:LinkedHashSet中的元素是有序的,它会按照元素被添加的顺序来维护元素的顺序。这是因为LinkedHashSet底层使用了哈希表和链表,其中链表用于保证元素的存储和取出顺序一致。

  2. 高效性能:LinkedHashSet底层使用了哈希表来存储元素,因此可以在O(1)的时间复杂度内执行插入、删除和查找操作。这使得LinkedHashSet在需要频繁插入、删除和查找操作的情况下,性能优于ArrayList。

  3. 不允许重复元素:与HashSet类似,LinkedHashSet也不允许集合中存在重复的元素。如果添加重复的元素,只会保留一个。

  4. 线程不安全:与HashSet类似,LinkedHashSet是线程不安全的。

LinkedHashSet的常见用法
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();  
  
// 添加元素  
linkedHashSet.add("apple");  
linkedHashSet.add("banana");  
linkedHashSet.add("cherry");  
linkedHashSet.add("apple"); // 重复元素,会被忽略  
  
// 输出LinkedHashSet中的元素  
for (String element : linkedHashSet) {  
	System.out.println(element);  
}  
//输出结果,其中LinkedHashSet是有序的,因此输出的元素顺序将与添加的顺序一致。
apple
banana
cherry

实现类TreeSet

TreeSet是Java中的一个类,它属于java.util包,是Set集合的一个子类,它实现了SortedSet接口,因此 TreeSet 中的元素总是按升序排列。。TreeSet是基于二叉树实现的

特点概述
  1. 有序性:TreeSet中的元素是按照一定的顺序排列的,这个顺序取决于创建TreeSet时提供的比较器或者元素本身的自然排序。如果没有提供比较器,那么元素本身的自然排序就会起作用。
  2. 唯一性:TreeSet不允许存储重复元素。
  3. 线程不安全:TreeSet没有提供任何线程安全的机制,因此在多线程环境下使用时需要额外的同步措施。
  4. 底层数据结构:TreeSet底层使用的是红黑树数据结构。红黑树是一种自平衡的二叉查找树,能够在O(log n)的时间复杂度内完成插入、删除和查找操作。

TreeSet在遍历时是按照元素的自然顺序或者创建TreeSet时提供的比较器定义的顺序进行遍历。TreeSet可以用来做排序,但效率比ArrayList低,因为每次插入元素时都需要进行二分查找,时间复杂度是O(log n)。

TreeSet的常见用法
//添加元素:使用add()方法向TreeSet中添加元素。
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(1);
treeSet.add(2);
treeSet.add(3);

//删除元素:使用remove()方法从TreeSet中删除元素。
treeSet.remove(2); // 从TreeSet中删除2

//查找元素:使用contains()方法查找TreeSet中是否包含指定元素。
boolean contains = treeSet.contains(1); // 返回true

//获取元素:使用first()方法获取TreeSet中的最小元素,使用last()方法获取TreeSet中的最大元素。

int first = treeSet.first(); // 返回TreeSet中的最小元素
int last = treeSet.last(); // 返回TreeSet中的最大元素

//清空TreeSet:使用clear()方法清空TreeSet中的所有元素。
treeSet.clear(); // 清空TreeSet

//遍历TreeSet:for-each循环遍历TreeSet中的所有元素。
for (Integer num : treeSet) {
    System.out.println(num);
}
//遍历TreeSet:迭代器遍历TreeSet中的所有元素。
Iterator<Integer> iterator = treeSet.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
import java.util.Set;
import java.util.TreeSet;

/**
 * TreeSet进行排序需要实现两个步骤:
 * 	1.实现Comparable接口
 * 	2.重写该接口中的compareTo方法,就是重写排序规则
 */
public class TreeSet {
    public static void main(String[] args) {

        Set<Dog> set = new TreeSet<>();
        set.add(new Dog("nn",10));
        set.add(new Dog("bb",9));
        set.add(new Dog("hh",7));
        set.add(new Dog("pd",8));

        set.toString();
        System.out.println(set);
    }

}
//实现Comparable接口
class Dog implements Comparable<Dog>{
    String name;
    int age ;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Dog() {
    }

    //重写排序规则
    @Override
    public int compareTo(Dog o) {
        return this.age - o.age;
    }

    @Override
    public String toString() {
        return "Dog{" + name + "," + age + "}";
    }
}


//输出:[Dog{hh,7}, Dog{pd,8}, Dog{bb,9}, Dog{nn,10}]
                                 ----分割线----

四、Queue

Queue(队列)是一个特殊的数据结构,遵循着先入先出(FIFO)的原则。Queue接口在Java的java.util包中,它是Collection接口的子接口。

Java集合Collection接口(超详解)_第2张图片

队列(Queue)特点概述
  1. 队列是线性结构,它遵循先进先出(FIFO)的原则,即最先进入队列的元素将最先被删除
  2. 队列只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。这保证了队列的顺序性,即队列中元素的位置不会发生改变。
  3. 队列可以进行高效的插入和删除操作,因为它使用了动态分配的策略,可以根据需要进行扩容和缩容
  4. 队列可以用于实现一些特定的任务,例如处理打印任务、实现消息队列、用于进程间通信等。
队列的常见用法
import java.util.LinkedList;  
import java.util.Queue;  
  
public class Main {  
    public static void main(String[] args) {  
        // 创建一个队列  
        Queue<String> queue = new LinkedList<>();  
  
        // 入队操作  
        queue.add("Apple");  
        queue.add("Banana");  
        queue.add("Cherry");  
  
        // 输出队列的大小  
        System.out.println(queue.size());  // 输出:3  
  
        // 出队操作  
        System.out.println(queue.poll());  // 输出:Apple  
        System.out.println(queue.poll());  // 输出:Banana  
        System.out.println(queue.poll());  // 输出:Cherry  
  
        // 检查队列是否为空  
        System.out.println(queue.isEmpty());  // 输出:true  
    }  
}
队列的遍历

在队列这种数据结构中,我们不能直接遍历队列的元素。这是因为队列是一种先进先出(FIFO)的数据结构,元素在队列中的位置是动态变化的。当元素被取出时,它就从队列中移除,而不会保留任何后续元素的位置信息。

然而,可以通过以下方法间接遍历队列的元素:

  1. 使用foreach循环遍历
public class Main {
    public static void main(String[] args) {
        Deque<String> queue = new LinkedList<>();
        queue.add("Apple");
        queue.add("Banana");
        queue.add("Cherry");

        for (String item : queue) {
            System.out.println(item);
        }
    }
}
  1. 使用迭代器(Iterator)循环遍历
public class Main {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.add("Apple");
        queue.add("Banana");
        queue.add("Cherry");

        Iterator<String> iterator = queue.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}
Queue的子接口:Deque(双端队列)

Deque(双端队列)是一种数据结构,它允许我们在队列的前端和后端进行插入和删除操作。Deque(双端队列)支持FIFO原则,最早添加的元素首先被移除。

import java.util.Deque;
import java.util.LinkedList;

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

        // 在后端添加元素
        deque.addLast("Apple");
        deque.addLast("Banana");
        deque.addLast("Cherry");

        // 在前端添加元素
        deque.addFirst("Orange");

        // 打印 deque 的内容
        System.out.println(deque); // 输出:["Orange", "Apple", "Banana", "Cherry"]

        // 移除前端元素并打印其值
        System.out.println(deque.removeFirst()); // 输出:Orange
        System.out.println(deque); // 输出:["Apple", "Banana", "Cherry"]

        // 移除后端元素并打印其值
        System.out.println(deque.removeLast()); // 输出:Cherry
        System.out.println(deque); // 输出:["Apple", "Banana"]
    }
}
                                 ----分割线----

五、注意事项:

以上介绍了Collection的一些常见用法,包括添加、删除、查找、获取元素以及遍历等操作。使用Collection时需要注意以下几点:

  1. 注意集合的类型:每种集合类型有其特定的用途和限制,应根据需要选择合适的集合类型。例如,使用ArrayList时需要注意其容量不足的问题,使用LinkedHashSet时需要注意其不能保证元素的顺序。
  2. 避免NullPointerException:在使用集合存储元素时,应避免存储空值对象,以免引发NullPointerException。
  3. 遍历集合时避免修改:在遍历集合的过程中修改集合元素,可能会引发ConcurrentModificationException。如果需要在遍历过程中修改集合元素,可以使用Iterator的remove()方法。
  4. 注意集合的容量:在使用ArrayList等动态数组类型的集合时,应注意其容量不足的问题。当数组的容量不足以容纳更多元素时,需要使用扩容方法增大容量。

你可能感兴趣的:(Java教程,java,开发语言,数据结构,课程设计,算法,链表)