集合1(List和比较器)

一.集合的分类

java 中针对数组的缺陷,提供了一种比数组灵活、使用方便的接口和类,它们位于 java.util 包,称为集合框架。

Java 中集合体系:

本篇我们先学习collections下的List接口

image-20230904203101552

Iterable 接口,凡是实现了此接口的对象都能成为 for-each-loop 的目标。

       for(数据类型 变量名 : 循环对象){
       //循环体
        }
//变量是循环对对象的值,不是索引
for (Object score:vector
             ) {
            Student student = (Student) score;
            sum+=student.getScore();
        }

iterator() 方法返回一个类型的迭代器。

我们主要先研究java.util.Collection

java.util.Collection

public interface Collection<E>
extends Iterable<E>

从类的声明我们可以看到, Collection 接口继承了 Iterable 接口。也就意味着,实现了
Collection 接口的类也间接实现了 Iterable 接口,也就是说它们都能作为 for-each-loo
p 的循环对象

Collection 是集合层次结构中的根接口。集合表示一组对象,对象称为集合的元
素。有些集合允许重复元素,有些则不允许。 有些是有序的,有些是无序的(不保证
顺序)

方法名返回值描述
add(E e)boolean添加元素
addAll(Collection<? extends E> c)boolean将集合c中的所有元素添加到此集合中
clear()void清除所有元素
contains(Object o)boolean集合中是否包含此元素
containsAll(Collection<?> c)boolean集合中是否包含c集合中的所有元素
方法名返回值描述
isEmpty()boolean集合中是否有元素,如果没有返回true
iterator()Iterator继承自Iterable接口,返回集合的迭代器
remove(Object o)boolean删除集合中的某个元素
removeAll(Collection<?> c)boolean删除集合c中包含的所有元素
retainAll(Collection<?> c)boolean保留集合c中的元素
size()int返回此集合中的元素数
toArray()Object[]返回一个包含此集合中所有元素的数组

二.子接口

子接口很多,主要研究 List 、 Set 、 Queue

1.Queue(队列)

public interface Queue<E>
extends Collection<E>

2.方法

方法名返回值描述
add(E e)boolean如果可以在不违反容量限制的情况下立即将指定元素插入此队列,则在成功时返回 true. 当前没有可用空间抛出一个 IllegalStateException。
offer(E e)boolean如果可以在不违反容量限制的情况下立即插入,则将指定元素插入此队列。
element()E检索但不删除此队列的头部,此方法的不同之处peek仅在于如果此队列为空,它会引发异常。
peek()E检索不删除此队列的头,如果此队列为空,则返回 null ,如果不为空返回队列的头。
poll()E检索并删除此队列的头,如果此队列为空,则返回 null。
remove()E检索并删除此队列的头。 此方法与 poll 不同之处在于,如果此队列为空,它将抛出异常。

注意:QUEUE接口不允许插入NULL元素,也不允许包含重复的元素

2.Deque(双端队列)

public interface Deque<E>
extends Queue<E>

方法:

方法名返回值描述
addFirst(E e)void插入此双端队列的前面。
addLast(E e)void双端队列的末尾插入元素,和 add(E e) 类似。
getFirst()E检索,但不删除,第一个元素。
getLast()E检索,但不删除,最后一个元素。
pop()E删除并返回此deque的第一个元素。
push(E e)void相当于 addFirst(E)
removeFirstOccurrence(Object o)boolean从此双端队列中删除第一次出现的指定元素。如果双端队列不包含该元素,则它保持不变。
removeLastOccurrence(Object o)boolean从此双端队列中删除最后一次出现的指定元素。如果双端队列不包含该元素,则它保持不变。

需要注意的是,Deque接口不是线程安全的,如果在多线程中使用,需要采取适当的同步措施

Deque接口主要特点包括:

  1. 双向插入和删除Deque 允许在队列的两端进行元素的插入和删除操作。你可以在队列的头部(前面)和尾部(后面)添加和移除元素。
  2. 可以用作栈:由于可以在队列的头部和尾部进行元素操作,Deque 可以轻松地用作栈(先进后出,LIFO)的数据结构。pushpop 方法允许在队列的头部添加和删除元素,模拟栈的行为。
  3. 可以用作队列:与栈不同,Deque 也可以用作队列(先进先出,FIFO)的数据结构。offerpoll 方法允许在队列的尾部添加和删除元素,模拟队列的行为。
  4. 支持双端迭代Deque 提供了双端迭代的功能,你可以从队列的头部或尾部开始迭代元素,或者使用 iterator() 方法来获取一个标准的迭代器。
  5. 不允许空元素:通常情况下,Deque 不允许包含空(null)元素。
  6. 有实现类:Java 提供了多个实现 Deque 接口的类,包括 LinkedListArrayDeque 等。

3.Set

public interface Set<E>
extends Collection<E>

不包含重复元素的集合, 可以存 null 。

of 方法和 copyOf ,都是 static 方法返回一个不可修改的 Set 集合

  Collection set = Set.of("a", "b", "c");

//        Set set = Set.copyOf();

不可修改 Set 集合
它们是不可修改的。不能添加或删除元素。
不允许 null 元素。尝试使用 null 元素创建它们会导致 NullPointerException

需要注意的是这里的无法修改是指没有修改集合中值的操作,即使是覆盖原来的值也不可以

会出现UnsupportedOperationException报错

常用子类:HashSet 和 TreeSet

List

有序集合(也称为序列 )。 该集合用户可以精确控制列表中每个元素的插入位置。 用户
可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素

List 通常允许重复的元素、允许 null 元素

1.方法

方法名返回值描述
add(int index, E element)void将指定的元素插入此列表中的指定位置。
addAll(int index, Collection<? extends E> c)boolean将指定集合中的所有元素插入到此列表中的指定位置。
get(int index)E返回此列表中指定位置的元素。
indexOf(Object o)int返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回 -1。
lastIndexOf(Object o)int返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回 -1。
remove(int index)E删除该列表中指定位置的元素,返回被删除的元素。
set(int index, E element)E用指定的元素(可选操作)替换此列表中指定位置的元素,返回被替换的值。
subList(int fromIndex, int toIndex)List返回此列表中指定的 fromIndex (含)和 toIndex 之间的元素集合。
default sort(Comparator c)void按照 c 比较器进行自然排序。
static copyOf(Collection coll)List按照迭代顺序返回一个不可修改的 List。
static of()List返回包含任意数量元素的不可修改列表。

主要子类, ArrayList 、 LinkedList 、 Vector

Vector

  • Vector 类实现了可扩展的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是, Vector的大小可以变化。

  • Vector 是同步的,是线程安全的。

  • Vector 继承了 AbstractList 类,实现了 List 接口

  • 内部是使用数组存储数据,也就是说在内存中开辟一个连续的空间

  • 默认大小是10,当容量不足时,默认扩容方式是按倍增长( capacity * 2)可以自定义默认容量以及每次扩展多少容量

    子类

image-20230904211400309

Stack

Stack 类代表后进先出(LIFO)堆栈的对象, Stack 继承自 Vector 所以它有所有 Vecto
r 中的方法。
常用方法:

public class Stack<E> extends Vector<E>

方法

方法名返回值描述
empty()boolean此堆栈是否为空。
peek()E返回此堆栈顶部的对象,而不从堆栈中删除它。
pop()E返回并删除此堆栈顶部的对象。
push(E item)E将 item 添加到堆栈的顶部。
search(Object o)int返回对象在此堆栈上的位置(从1开始计数),如果对象不在堆栈中,则返回 -1。

三.比较器

问题:如何比较集合中两个对象的顺序(按照年龄)

通过集合自带的soft方法,

1.comparator

接口的实现比较器顺序

利用匿名类

sort(vector,new Comparator() {
         @Override
         public int compare(Object o1, Object o2) {
             if (o1 instanceof Student stu1 &&o2 instanceof Student stu2){
                 if (stu1.getAge()< stu2.getAge())return -1;
                 else if(stu1.getAge()> stu2.getAge())return 1;
                 else return 0;
             }throw new ClassCastException("类型不匹配");
         }
     });

简化lambda表达式

     vector.sort((o1,o2)->{
             if (o1 instanceof StudentList stu1 &&o2 instanceof StudentList stu2){
                 return stu1.getAge()- stu2.getAge();
             }throw new ClassCastException("类型不匹配");

    });

2.自然比较(comparable)

接口实现重写compareTo方法

 public int compareTo(Object o) throws RuntimeException {
        if (o instanceof Student stu) {
            //比较权重
            if (this.age > stu.age) {
                return 1;
            } else if (this.age < stu.age) {
                return -1;
            }
            if (this.score > stu.score) {
                return 1;
            } else if (this.score < stu.score) {
                return -1;
            }
            return this.name.compareTo(stu.name);
        }
      throw new CompareException("类型不匹配");
    }

自然比较

private static void sort(Student[] stus) {
        // 冒泡
        for (int i = 0; i < stus.length - 1; i++) {
            // 每次比较的次数
            for (int j = 0; j < stus.length - 1 - i; j++) {
                // 比较
                if (stus[j].compareTo(stus[j + 1]) > 0) {
                    // 交换
                    Student temp = stus[j];
                    stus[j] = stus[j + 1];
                    stus[j + 1] = temp;
                }
            }
        }
    }