Collection集合(单列集合)

前言

Java中有许多类型的集合,我们比较常用的ArrayList也是集合的一种。

Java中集合的体系结构分为Collection单列集合以及Map双列集合。
在这里插入图片描述

下面介绍单列集合。

一、Collection集合

红色的是接口,蓝色的代表接口的实现类。
在这里插入图片描述

List系列集合:添加的元素是有序、可重复、有索引。
Set系列集合:添加的元素是无序、不重复、无索引。

1.常用方法

Collection是单列集合的祖宗接口,它的功能所有的单列集合都可以继承使用。下面这些方法List系列和Set系列的集合都可以使用。
在这里插入图片描述
对于contains方法,我们需要注意,它在底层是以来equals方法进行判断是否存在的。所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在Javabean类中,必须重写euqals方法。

2.Collection的遍历方法

因为Collection中有Set系列的集合,所以我们不能直接用索引来遍历Collection集合。所以一共有三种方法来进行遍历,分别是迭代器遍历、增强for遍历、Lambda表达式遍历。List集合和Set集合都可以用这三种方法来进行遍历。

a.迭代器遍历

迭代器在Java中的类是Iterator,迭代器是集合专用的遍历方式。
在这里插入图片描述

当我们创建了一个迭代器对象时,指针会指向第一个元素。执行完next方法后,指针会向后移,直到遍历完集合。当指针不再指向集合元素时,再执行next方法,就会报错NoSuchElementException异常。迭代器遍历完毕之后,指针不会复位。同时,迭代器遍历时,不能用集合的方式进行增加或者删除。如果非要删除的话,只能用迭代器提供的remove方法进行删除。

public class CollectDemo1 {
    public static void main(String[] args) {
        // 创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("A");
        coll.add("B");
        coll.add("C");
        coll.add("D");

        //1. 获取迭代器对象
        Iterator<String> it = coll.iterator();

        //2. 判断当前指针是否有元素,并打印
        // 在遍历过程中,不能用集合的方法增加或者删除元素
        while (it.hasNext()) {
            String str = it.next();
            System.out.println(str);
            if (str.equals("B")) {
            	// 迭代器类中提供的remove方法
                it.remove();
            }
        }
        // 遍历结束后,我们就可以用Collection提供的方法来对集合进行操作
        System.out.println(coll);
    }
}

b.增强for遍历

增强for的底层就是迭代器,为了简化迭代器的书写。所有的单列集合以及数组才能使用增强for进行遍历。
在这里插入图片描述

public class CollectDemo1 {
    public static void main(String[] args) {
        // 创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("A");
        coll.add("B");
        coll.add("C");
        coll.add("D");

        // 增强for遍历
        for (String s : coll) {
            System.out.println(s);
        }
    }
}

细节:修改增强for中的变量,不会改变集合中原本的数据。增强for中的s就是一个第三方变量,改变它的值,不会影响原集合。

c.Lambda表达式

利用该方法对集合进行遍历。Consumer在底层源码中是一个接口,所以我们传入的参数应该是Consumer的实现类对象。
在这里插入图片描述

public class CollectionDemo2 {
    public static void main(String[] args) {
        /*
            default void forEach(Consumer<? super T> action):
         */

        // 1. 创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("zhansgan");
        coll.add("liss");
        coll.add("wangwu");

        //2. 使用匿名内部类的形式
        // 底层原理:
        // 其实也会自己遍历集合,依次得到每一个元素
        // 把得到的每一个元素(s就是得到的每一个元素),传递给下面的accept方法
        coll.forEach(new Consumer<String>() {
            @Override
            // s依次表示集合中的每一个数据
            public void accept(String s) {
                System.out.println(s);
            }
        });

        //3. 利用Lambda表达式
        coll.forEach(s -> System.out.println(s));
    }
}

二、List集合

1.List中特有的方法

List中存在索引,所以多了许多索引操作的方法。
在这里插入图片描述

public class ListDemo1 {
    public static void main(String[] args) {
        // 1.创建一个集合
        List<String> list = new ArrayList<>();

        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        // add方法
        list.add(1, "QQQ");

        // remove方法
        String s = list.remove(2);
        System.out.println(s);

        System.out.println(list);

    }
}

2.List集合的遍历方式

除了在Collection集合中所提及的三种遍历方式,List集合还有两种自己独有的遍历方式-------列表迭代器遍历以及普通for循环。

a.普通for循环遍历

利用get方法获取指定索引处的元素。

public class ListDemo2 {
    public static void main(String[] args) {
        // 1.创建一个集合
        List<String> list = new ArrayList<>();

        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        // 普通for循环,
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }
    }
}

b.列表迭代器遍历

列表迭代器与Collection的迭代器类似。只不过后者创建的是Iterator对象,前者创建的是ListIterator对象。相比于迭代器,列表迭代器可以在遍历的时候添加元素,但是只能使用ListIterator自身的add方法进行添加。

public class ListDemo2 {
    public static void main(String[] args) {
        // 1.创建一个集合
        List<String> list = new ArrayList<>();

        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        // 列表迭代器ListIterator,跟迭代器Iterator相似
        // 额外添加了一个方法:在遍历过程中,可以添加元素
        ListIterator<String> lit = list.listIterator();
        while (lit.hasNext()) {
            String str = lit.next();
            if ("bbb".equals(str)) {
            	// 在遍历过程中向集合中添加元素
                lit.add("QQQ");
            }
        }

        System.out.println(list);
    }
}

c.五种遍历方式对比

  1. 迭代器遍历:在遍历过程中需要删除元素,使用迭代器。
  2. 列表迭代器:在遍历过程中需要添加元素,使用列表迭代器。
  3. 增强for、Lambda表达式:仅仅想要遍历,使用这两种方式。
  4. 普通for:如果遍历的时候想要操作索引,可以使用普通for遍历。

三、ArrayList集合

ArrayList可以使用Collection和List的所有方法,所以这里不在额外说其他的方法。说一下ArrayList集合的底层原理。ArrayList底层利用的是数组这个数据结构。

  1. 利用空参创建集合,在底层会创建一个默认长度为0的数组,这个数组的名字是elementData,并且会创建一个变量size,用来记录数组中的元素个数。
  2. 添加第一个元素时,底层会创建一个新的长度为10的数组。
  3. 当数组存满时,会扩容1.5倍。
  4. 如果一次添加多个元素,1.5倍还放不下,则新创建的数组的长度以实际长度为准。例如我一次添加100个元素,则新创建的数组长度为110.

在这里插入图片描述

四、LinkedList集合

LinkedList集合底层数据结构是双向链表,查询慢、增删快。但是如果操作的是首尾元素,速度也很快。所以多了许多首尾操作特有的API。
在这里插入图片描述

下图表示底层源码和结构,在创建LinkedList对象的时候,会直接创建一个头结点和尾结点:

在这里插入图片描述

五、泛型

泛型是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。

泛型的格式:<数据类型>,只支持引用数据类型。如果不写泛型,类型默认是Object。

Java之中的泛型是伪泛型,例如此时我们有一个集合, ArrayList arr = new ArrayList<>();,指定的泛型只会检查加入集合的数据是不是String类型的,但等到真正加入到集合中时,集合还是会把这些数据当做是Object类型,只不过取出来的时候,集合的底层会吧Object类型重新转换为String类型。

如下图所示,Java代码在编译的时候,就会消除泛型,叫做泛型的擦除。
在这里插入图片描述

1.泛型类

使用场景:当一个类中,某个变量的数据类型不确定的时候,就可以定义带有泛型的类。

此处的E可以理解为一个变量,但是不是用来记录数据的,而是记录数据的类型,可以写成T、E、K、V等。

在这里插入图片描述
下面的代码中,我们定义了一个泛型类。

public class MyArrayList<E>{

	// 因为不确定类型,所以我们统一用Object数组还存数据,运用了多态的原理
    Object[] obj = new Object[10];
    int size;

	// 不确定要添加元素的类型,所以使用泛型
    public boolean add(E e) {
        obj[size] = e;
        size++;
        return true;
    }
	
	// 泛型方法
    public E get(int index) {
        return (E)obj[index];
    }

    @Override
    public String toString() {
        return Arrays.toString(obj);
    }
}

下面是测试类

public class GenericsDemo1 {
    public static void main(String[] args) {
    	// 创建所定义泛型的对象,然后添加元素。
        MyArrayList<String> arr = new MyArrayList<>();
        arr.add("abd");
        arr.add("abc");
        arr.add("ae");

        String str = arr.get(1);

        System.out.println(str);
        System.out.println(arr);
    }
}

2.泛型方法

当方法中形参类型不确定时,我们就可以在方法上声明泛型。
在这里插入图片描述
定义一个工具类,下面的addAll方法我们不知道形参传入什么类型,所以定义泛型:

public class ListUtil {

    private ListUtil() {}


    // 泛型方法,不知道形参需要传入什么类型的数据
    // T...t表示我们可以传入任意个T类型的元素
    public static <T> void addAll(ArrayList<T> arr, T...t) {
        for (T element: t) {
            arr.add(element);
        }
    }

}

这是测试类:

public class GenericsDemo2 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        ArrayList<String> list2 = new ArrayList<>();

        ListUtil.addAll(list, 1, 2, 3, 4);
        ListUtil.addAll(list2, "123", "zhansgan");

        System.out.println(list);
        System.out.println(list2);
    }
}

在这里插入图片描述

3.泛型的通配符

泛型不具备继承性,数据具备继承性。

在下面的代码中,我们可以发现Fu继承Ye,Zi继承Fu,但是Fu类型和Zi类型的集合都不能传入method方法中。此时我们就需要用到泛型的通配符““?”。

在这里插入图片描述
? 也可以表示不确定的类型,进行类型的限定
? extends E: 表示可以传递E或者E所有子类类型
? super E: 表示可以传递E或者E所有的父类类型

public class GenericsDemo3 {
    public static void main(String[] args) {
        ArrayList<Ye> list1 = new ArrayList<>();
        ArrayList<Fu> list2 = new ArrayList<>();
        ArrayList<Zi> list3 = new ArrayList<>();
        ArrayList<Student> list4 = new ArrayList<>();


        method(list1);
        method(list2);
        method(list3);

        // 这里传递学生类型就会报错
        method(list4);

    }

    // 本方法虽然不确定类型,但是我希望只能传递Ye,Fu,Zi
    // 此时就可以使用泛型的通配符:
    //      ?也可以表示不确定的类型,进行类型的限定
    //      ? extends E: 表示可以传递E或者E所有子类类型
    //      ? super E: 表示可以传递E或者E所有的父类类型
    // 这里表明,形参可以传递Ye以及它的多有子类类型
    public static void method(ArrayList<? extends Ye> arr){

    }
}

class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
class Student{}

六、Set集合

Set系列集合是无序、不重复、无索引的。同时Set集合没有什么额外的方法,基本上与Collection的API一致。

无序:存取顺序不一致
无重复:可以去除重复
无索引:没有带索引的方法,所以不能使用普通for循环进行遍历,也不能通过索引来获取元素。

在了解Set集合之前,我们要先知道二叉树这种数据结构,以及二叉排序树、平衡二叉树、红黑树等等。这里只讲解红黑树。

1.红黑树

红黑树是一种特殊的二叉查找树,红黑树的每一个节点上都有存储位表示节点的颜色。每一个节点可以是红或者黑,红黑树不是高度平衡的,它的平衡是通过“红黑规则”实现的。

在这里插入图片描述
下图就是一个标准的红黑树,最下面的Nil就代表的是叶子结点。
在这里插入图片描述

红黑树在添加节点的时候,添加的结点默认是红色的。 有如下的规则。

在这里插入图片描述

我们通过20、18、23、22、17、24、19、15、14来创建红黑树,过程如下:
在这里插入图片描述
在这里插入图片描述
通过上面添加节点规则,就可以创建出一个红黑树。

2.HashSet

HashSet集合无序、不重复、无索引。

a.底层原理

HashSet集合底层采取哈希表存储数据。JDK8以前哈希表由数组+链表组成,JDK8以后哈希表由数组+链表+红黑树组成。

对于一个数据在哈希表中的索引,是通过哈希值进行计算的。如下图所示,我们通过公式计算出该元素在哈希表中的索引是4。
在这里插入图片描述
自定义对象时,一定要重写hashcode方法,否则将对象加入到Set集合时会直接报错。

在这里插入图片描述

加载因子为0.75,当哈希表中存满16x0.75 = 12个元素时,这个数组就会扩容为原来的两倍。

在这里插入图片描述
同时当链表的长度大于8而且数组长度大于64的时候,挂在哈希表上的链表就会自动转换成红黑树。

在这里插入图片描述

b.LinkedHashSet

LinkedHashSet继承于HashSet,但是它是有序的。可以保证存储和取出的元素顺序一致。

底层数据结构依然是哈希表,只是每个元素额外多了一个双链表的机制记录存储的顺序。

public class HashSetDemo1 {
    public static void main(String[] args) {
        /*
            存储多个学生对象,如果学生对象属性值相同,则认为是同一个对象
         */

        HashSet<Student> hs = new HashSet<>();
        LinkedHashSet<Student> lhs = new LinkedHashSet<>();

        lhs.add(new Student("lisi", 23));
        lhs.add(new Student("zhansgan", 23));
        lhs.add(new Student("zhansgan", 23));
        lhs.add(new Student("wangwu", 23));
        lhs.add(new Student("zhansgan", 23));

        for (Student h : lhs) {
            System.out.println(h.toString());
        }
    }
}


class Student {
    private String name;
    private int age;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    // 重写的hashCode方法
    public int hashCode() {
        return Objects.hash(name, age);
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

使用LinkedHashSet,最终结果是有序的。
在这里插入图片描述

3.TreeSet

TreeSet的特点是不重复、无索引、可排序。可排序指的是按照元素的默认规则(由小倒大)进行排序。

TreeSet的集合底层是基于红黑树的数据结构进行排序的,增删改查性能都比较良好。

a. 第一种排序方式

默认排序:Javabean类实现Comparable接口指定排序规则。

public class TreeSetDemo1 {
    public static void main(String[] args) {
        /*
            TreeSet会将数据进行自动排序
         */
        TreeSet<Integer> ts = new TreeSet<>();
        TreeSet<Teacher> ts2 = new TreeSet<>();

        // 如果添加自定义对象,我们要对排序方法进行重写
        ts2.add(new Teacher("zhansgan", 24));
        ts2.add(new Teacher("lisu", 23));

        System.out.println(ts2);
    }
}


// 需要实现Comparable这个接口,然后重写compareTo方法,才能对自定义对象进行排序
class Teacher implements Comparable<Teacher>{
    private String name;
    private int age;

    public String toString() {
        return "Teacher{name = " + name + ", age = " + age + "}";
    }

    @Override
    // this:表示要添加的元素
    // o:表示红黑树中已经存在的元素
    // 这里是按年龄进行排序
    public int compareTo(Teacher o) {
        return this.getAge() - o.getAge();
    }
}

在这里插入图片描述

b. 第二种排序方式

第二种排序方式是利用比较器进行比较。创建TreeSet对象时候,传递比较器Comparator指定规则。

我们默认使用第一种,如果第一种不能满足当前需求,那么我们就使用第二种。

public class TreeSetDemo2 {
    public static void main(String[] args) {
        /*
            使用比较器进行排序
            存入四个字符串,"c", "ab", "df", "qwer"
            按照长度排序,如果一样长按照首字母进行排序
         */

//        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                // 按照长度排序
//                int i = o1.length() - o2.length();
//                // 如果长度相同
//                i = i == 0 ? o1.compareTo(o2) : i;
//                return i;
//            }
//        });

		// Lambda表达式
        TreeSet<String> ts = new TreeSet<>((o1, o2) -> {
                // 按照长度排序
                int i = o1.length() - o2.length();
                // 如果长度相同
                i = i == 0 ? o1.compareTo(o2) : i;
                return i;
        });

        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("gwer");

        System.out.println(ts);

    }
}

4.Set特有的方法

a. 求两个set集合的交集

在这里插入图片描述

七、ArrayDeque双端队列

在 Java 中,ArrayDeque 是一个基于动态循环数组实现的双端队列(Double-Ended Queue),它既可以用作队列(FIFO),也可以用作栈(LIFO)。相较于 LinkedList,ArrayDeque 在大多数操作中具有更高的性能(时间复杂度更低且内存占用更紧凑)。

ArrayDeque可以作为双端队列、队列以及栈进行使用。

栈也可以使用Stack类来实现,但是Stack继承于Vector, 不推荐使用。

在这里插入图片描述

ArrayDeque<Integer> deque = new ArrayDeque<>();
deque.addFirst(10);  // 头部插入
deque.addLast(20);   // 尾部插入
System.out.println(deque.removeFirst());  // 输出 10
System.out.println(deque.removeLast());   // 输出 20

在这里插入图片描述

Deque<Integer> queue = new ArrayDeque<>();
queue.offer(1);  // 入队
queue.offer(2);
System.out.println(queue.poll());  // 出队,输出 1

在这里插入图片描述

Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);  // 压栈
stack.push(2);
System.out.println(stack.pop());  // 弹栈,输出 2

八、PriorityQueue堆类

PriorityQueue 是 Java 中基于优先级堆(通常是最小堆)实现的队列,继承自 AbstractQueue 类。

PriorityQueue默认为小根堆,若要创建大根堆,需要利用比较器。

在这里插入图片描述

import java.util.PriorityQueue;
import java.util.Collections;

public class MaxHeapExample {
    public static void main(String[] args) {
        // 方法1:使用 Collections.reverseOrder()
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());

        // 方法2:自定义比较器 (o2 - o1)
        PriorityQueue<Integer> maxHeap2 = new PriorityQueue<>((a, b) -> b - a);

        // 添加元素
        maxHeap.add(3);
        maxHeap.add(1);
        maxHeap.add(5);

        // 输出堆顶(最大值)
        System.out.println(maxHeap.peek()); // 输出: 5
    }
}

在这里插入图片描述
在这里插入图片描述

核心方法如下:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

PriorityQueue底层使用动态数组存储元素,表现为完全二叉树。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<think>嗯,用户问的是Java中的Collection单列集合。首先,我需要回忆一下Java集合框架的基础知识。记得Java集合框架主要分为Collection和Map两大类,而Collection单列集合,Map是双列的键值对。用户可能想了解Collection的体系结构、常用接口和实现类,以及它们的使用场景。 首先,应该从Collection的顶层接口开始介绍,说明它继承了Iterable接口,所以所有Collection的实现类都支持迭代。然后,Collection分为List、Set和Queue三个子接口,每个子接口有不同的特性。 List部分,需要提到有序、可重复的特点,常用的实现类有ArrayList、LinkedList和Vector。要比较它们的底层实现,比如ArrayList基于数组,查询快,增删慢;LinkedList基于链表,增删快,查询慢;Vector是线程安全的,但性能较差,现在可能不常用了。 接下来是Set,强调元素唯一且无序。常用的实现类有HashSet、LinkedHashSet和TreeSet。HashSet基于哈希表,LinkedHashSet维护插入顺序,TreeSet可以排序。可能需要提到TreeSet是基于红黑树实现的,自然排序或者通过Comparator定制排序。 然后是Queue,队列,常用的有LinkedList、PriorityQueue,还有线程安全的ArrayBlockingQueue等。需要说明队列的先进先出特性,以及优先级队列的特殊之处。 用户可能还想知道如何选择不同的集合类,比如需要快速访问用ArrayList,需要频繁插入删除用LinkedList,需要唯一性用HashSet,需要排序用TreeSet,需要线程安全的话考虑使用Collections工具类或者并发包下的类。 另外,可能需要提到集合的遍历方式,比如for-each循环、迭代器、Java8的Stream API等。还要注意集合的线程安全问题,比如ArrayList不是线程安全的,多线程环境下应该用CopyOnWriteArrayList或者同步包装类。 用户可能的疑问还包括如何正确实现对象的equals和hashCode方法,特别是当使用HashSet或HashMap的时候。这也是确保集合正确行为的关键点。 最后,总结一下Collection的层次结构,以及各个实现类的适用场景,帮助用户在实际开发中做出合适的选择。可能还需要提醒一些常见错误,比如在遍历集合时修改导致的ConcurrentModificationException异常,以及如何避免。</think>Java中的Collection单列集合是存储一组对象的容器,属于Java集合框架的核心部分。以下从体系结构、常用接口和实现类进行分步解析: 1. **Collection顶层接口** - 继承自`Iterable`接口,支持迭代遍历 - 核心方法: ```java boolean add(E e); // 添加元素 boolean remove(Object o); // 删除元素 int size(); // 元素数量 boolean contains(Object o); // 判断包含 Iterator<E> iterator(); // 获取迭代器 ``` 2. **三大子接口** $$\begin{array}{|c|c|c|} \hline \text{接口} & \text{特点} & \text{常用实现类} \\ \hline \text{List} & \text{有序、可重复} & ArrayList, LinkedList, Vector \\ \text{Set} & \text{无序、唯一} & HashSet, LinkedHashSet, TreeSet \\ \text{Queue} & \text{队列结构} & LinkedList, PriorityQueue \\ \hline \end{array}$$ 3. **List接口详解** - **ArrayList**(数组实现): - 查询效率高($O(1)$随机访问) - 增删效率较低(需要移动元素) - **LinkedList**(双向链表实现): - 增删效率高($O(1)$头尾操作) - 查询效率低($O(n)$顺序访问) - **Vector**(线程安全数组): - 已被`Collections.synchronizedList()`取代 4. **Set接口详解** - **HashSet**(哈希表实现): - 基于`HashMap`实现 - 要求元素正确实现`hashCode()`和`equals()` - **LinkedHashSet**: - 维护插入顺序的HashSet - **TreeSet**(红黑树实现): - 支持自然排序或`Comparator`定制排序 - 元素必须实现`Comparable`接口 5. **Queue接口特性** - **PriorityQueue**: - 基于堆结构实现优先级队列 - 元素按自然顺序或Comparator排序 - **LinkedList**: - 可同时作为List和Deque使用 6. **使用示例** ```java // ArrayList示例 List<String> list = new ArrayList<>(); list.add("Java"); list.add("Python"); System.out.println(list.get(0)); // 输出:Java // HashSet示例 Set<Integer> set = new HashSet<>(); set.add(1); set.add(1); // 重复元素不会添加 System.out.println(set.size()); // 输出:1 // TreeSet排序示例 Set<String> sortedSet = new TreeSet<>(); sortedSet.add("Banana"); sortedSet.add("Apple"); System.out.println(sortedSet); // 输出:[Apple, Banana] ``` 7. **选择策略** - 需要快速随机访问 → ArrayList - 频繁插入删除 → LinkedList - 元素唯一性 → HashSet - 需要排序 → TreeSet - 线程安全需求 → 使用`Collections.synchronizedCollection()`包装或改用并发集合 8. **遍历方式** - 传统for循环(仅List) - 增强for循环 - Iterator迭代器 - Java8 Stream API: ```java list.stream().forEach(System.out::println); ``` 理解Collection体系需要掌握: 1. 各实现类的底层数据结构 2. 时间空间复杂度差异 3. 特定场景下的最佳实践 4. 线程安全问题的处理方式 建议通过实际编码练习加深理解,特别注意不同集合对元素相等性的判断机制,以及排序集合对元素可比性的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值