Java数据结构-List-栈-队列-二叉树-堆

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • [1. 前置知识](#1. 前置知识)
    • [1.1 yield关键字](#1.1 yield关键字)
    • [1.2 var关键字](#1.2 var关键字)
    • [1.3 密封类](#1.3 密封类)
    • [1.4 接口中的私有方法](#1.4 接口中的私有方法)
    • [1.5 instance](#1.5 instance)
    • [1.5 包装类](#1.5 包装类)
    • [1.6 装箱和拆箱](#1.6 装箱和拆箱)
    • [1.7 泛型](#1.7 泛型)
  • [2. List](#2. List)
    • [2.1 ArrayList顺序表](#2.1 ArrayList顺序表)
      • [2.1.1 ArrayList遍历](#2.1.1 ArrayList遍历)
    • [2.2 链表](#2.2 链表)
      • [2.2.1 LinkedList的使用](#2.2.1 LinkedList的使用)
  • [3. 栈](#3. 栈)
  • [4. 队列](#4. 队列)
  • [5. 二叉树](#5. 二叉树)
  • [6. PriorityQueue优先级队列(堆)](#6. PriorityQueue优先级队列(堆))
    • [6.1 覆写基类的equals](#6.1 覆写基类的equals)
    • [6.2 基于Comparble接口类的比较](#6.2 基于Comparble接口类的比较)
    • [6.3 基于比较器比较](#6.3 基于比较器比较)
  • 总结

前言

1. 前置知识

1.1 yield关键字

java 复制代码
    public static void main(String[] args) {
        String data = "one";
        int result = switch (data){
            case "one": yield 1;
            case "two": yield 2;
            default: yield 3;
        };
        System.out.println(result);
    }

    public static void main2(String[] args) {
        String data = "one";
        int result = switch (data){
            case "one"->1;
            case "two"->2;
            default -> 3;
        };
        System.out.println(result);
    }

    public static void main3(String[] args) {
        String data = "one";
        int result = 1;
        switch (data){
            case "one": result=1;break;
            case "two":result=1;break;
            default : result=1;break;
        };
        System.out.println(result);
    }

1.2 var关键字

java 复制代码
    public static void main(String[] args) {
        var age =10;
        var salary ="hello";
    }

自动推导类型

但是var不能用于声明类的字段

声明变量必须要初始化,不能初始化为null

var不能作为返回值类型

1.3 密封类

java 复制代码
final class Person {}

Person 这个类不能被继承:密封类

java 复制代码
sealed class Person permits GB{}

non-sealed class GB extends Person{}

表示Person是一个密封类,不能被继承,但是可以被GB继承

non-sealed 表示这不是一个密封类,可以被继承

继承了密封类,那么自己这个类就要说明一下到底是不是密封类

sealed修饰的类,必须要有子类,这个子类可以为sealed可以为non-seald,但是不能为什么都不说

只有被允许的类,才可以被继承

1.4 接口中的私有方法

java 复制代码
interface A{
    void test();
    default void test2(){}
    static void test3(){}
    private  void test4(){}
}

后面三种方法,实现接口是不用重写这三种方法的,这三种方法也是可以有方法体的

只有第一个不能有方法体

1.5 instance

java 复制代码
        if (obj instanceof String){
            String string = (String) obj;
        }
        
        if(obj instanceof String str){
            
        }

这两个是一样的效果

1.5 包装类

指的是基本数据类型对应的类类型

byte Byte

short Short

int Integer

long Long

float Float

double Double

char Character

boolean Boolean

1.6 装箱和拆箱

java 复制代码
        int a = 10;
        Integer ii = a;//装箱,显示装箱
        Integer iii = Integer.valueOf(a);//自动装箱
        int b = ii;//自动拆箱
        int bi = ii.intValue();//手动拆箱
java 复制代码
        double c = ii.doubleValue();
java 复制代码
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);
        Integer c = 200;
        Integer d = 200;
        System.out.println(c == d);

首先这两个都是装箱

都调用了方法valueOf

可以看出,如果i在一定范围之内,直接返回这个已经创建好的Integer-----》

已经创建好了一个Integer的数组cache

low是-128

high是127

所以i在-128到127之内,就会在cache这个数组里面取到Integer的值

如果不在的话,就创建一个新的Integer返回---》每个类的地址都不一样

java 复制代码
        Integer a = 127;
        Integer b = 127;
        System.out.println(a == b);
        Integer c = 128;
        Integer d = 128;
        System.out.println(c == d);

1.7 泛型

泛型:就是适用于许多许多类型

把类型(int,byte)参数化

java 复制代码
class MyArray<T>{
    public Object[] array= new Object[10];
    public void setValue(int pos, T value){
        array[pos] = value;
    }
    public T getValue(int pos){
        return (T)array[pos];
    }
}
java 复制代码
        MyArray<Integer> a = new MyArray<Integer>();
        a.setValue(1,1);
        a.setValue(2,2);
        a.setValue(3,3);
        Integer value = a.getValue(1);
        System.out.println(value);
java 复制代码
class MyArray<T>{
    public T[] array= (T[]) new Object[10];
    public void setValue(int pos, T value){
        array[pos] = value;
    }
    public T getValue(int pos){
        return (T)array[pos];
    }
}

也可以这样

java 复制代码
T[] ts = new T[5];//是不对的
java 复制代码
        MyArray<Integer> a = new MyArray<>();

第二个Integer可以不写,可以推导出实例化需要的类型实参为 Integer

注意:泛型只能接受类,所有的基本数据类型必须使用包装类!

尖括号里面只能写类,不能写简单类型

泛型到底是怎么编译的?

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。

Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。

那为什么,T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new Object[5]吗?

因为java规定的就是,在new数组的时候,就必须是一个确定类型的数组,所以写new T[5]从语法上来说就已经出错了,因为你写new T(),你知道这个类型的构造方法是不带参数的吗

java 复制代码
class MyArray<T>{
    public T[] array= (T[]) new Object[10];
    public void setValue(int pos, T value){
        array[pos] = value;
    }
    public T getValue(int pos){
        return (T)array[pos];
    }

    public T[] getArray(){
        return array;
    }
}
java 复制代码
        MyArray<String> myArray = new MyArray<>();
        String[] strings = myArray.getArray();

这样直接就报错了,为什么呢,以前可以转换,那是因为,Object是所有类的父类

但是Object[]不会所有数组的父类

所以Object[]不是String[]的父类,是不能进行强转的

泛型的上界:在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束

java 复制代码
public class MyArray<E extends Number> {
...
}

只接受 Number 的子类型或者number自己作为 E 的类型实参

java 复制代码
public class MyArray<E extends Comparable<E>> {
...
}

E必须是实现了Comparable接口的----》意思就是这个类型E是可以进行比较的

就是E类型对应的对象可以来比较的,一般类型是不能比较的

java 复制代码
class ALg<T extends Comparable<T>> {
    public T findMax(T[] array){
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}

我们看到MyArray没有实现接口Comparable,所以不能泛型

泛型方法

java 复制代码
class ALg2 {
    public<T extends Comparable<T>> T findMax(T[] array){
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}
java 复制代码
        ALg2 aLg2 = new ALg2();
        Integer[] arr = {1,2,3,4,5,6,7,8,9};
        Integer max = aLg2.findMax(arr);
        System.out.println(max);

这里不用指定泛型,因为会自动推导的

java 复制代码
class ALg3 {
    public static <T extends Comparable<T>> T findMax(T[] array){
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}
java 复制代码
        Integer max1 = ALg3.findMax(arr);
java 复制代码
        Integer max1 = ALg3.<Integer>findMax(arr);

也可以这样

2. List

2.1 ArrayList顺序表

List是一个接口,继承自Collection。

Collection也是一个接口

继承Iterable

java 复制代码
        List<Integer> list = new ArrayList<>();

因为ArrayList实现了ArrayList,所以可以这样定义

ArrayList就是顺序表

List是个接口,并不能直接用来实例化。

如果要使用,必须去实例化List的实现类。在集合框架中,ArrayList和LinkedList都实现了List接口。

顺序表其实就是一个数组

java 复制代码
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    System.out.println(list);
java 复制代码
    ArrayList<Integer> arrayList = new ArrayList<>();
    List<Integer> list = new ArrayList<>();

List是一个接口

ArrayList是一个类

list 只能访问list里面的方法

而ArrayList只能访问ArrayList里面的方法,相比来说,ArrayList里面的防范更多

java 复制代码
    List<Integer> list = new ArrayList<>();
    List<Integer> list2 = new ArrayList<>(list);
    List<Integer> list3 = new ArrayList<>(3);

这是三种不同的构造方法

容量达到3就进行扩容

boolean add(E e) 尾插 e

void add(int index, E element) 将 e 插入到 index 位置

boolean addAll(Collection<? extends E> c) 尾插 c 中的元素

E remove(int index) 删除 index 位置元素

boolean remove(Object o) 删除遇到的第一个 o

E get(int index) 获取下标 index 位置元素

E set(int index, E element) 将下标 index 位置元素设置为 element

void clear() 清空

boolean contains(Object o) 判断 o 是否在线性表中

int indexOf(Object o) 返回第一个 o 所在下标

int lastIndexOf(Object o) 返回最后一个 o 的下标

List subList(int fromIndex, int toIndex) 截取部分 list,没有重新生成一个新的,意思是subList返回的数组和原数组是同一个部分的内容

因为list是Collection的子类,所以可以直接传入list类型的

java 复制代码
    list2.addAll(list3);

如果删除10下标元素

remove(10)

如果删除10这个元素

remove(new Integer(10))

remove(Integer.valueOf(10))

2.1.1 ArrayList遍历

第一种就是直接打印

java 复制代码
    list3.add(1);
    list3.add(2);
    list3.add(3);
    for (int i = 0; i < list3.size(); i++) {
        System.out.println(list3.get(i));
    }
java 复制代码
    for (Integer integer : list2) {
        System.out.println(integer);
    }

最后一种就是使用迭代器

java 复制代码
    Iterator<Integer> it = list2.iterator();
    while (it.hasNext()) {
        System.out.println(it.next());
    }

it迭代器指向的位置是第一位置的前一个位置,也就是-1的位置

只要实现了Iterable,就可以使用迭代器,就是使用foreach

java 复制代码
    Iterator<Integer> it2 = list2.listIterator();
    while (it2.hasNext()) {
        System.out.println(it.next());
    }

这个是专门用于list的Iterator

Iterator是listIterator的父类

java 复制代码
    ListIterator<Integer> it3 = list2.listIterator(list2.size());
    while (it3.hasPrevious()) {
        System.out.println(it3.previous());
    }

这个就是倒着遍历,传入整型参数表示从哪个迭代器开始

但是只有ListIterator有previous,Iterator是没有这个方法的,所以用ListIterator接收呢

iterator()不能传入整型参数,默认从0开始

  1. ArrayList底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。---》链表

这个比较适合查找,根据下标进行查找

链表适合插入和删除

2.2 链表

java 复制代码
class ListNode{
    public int val;
    public ListNode next;
    ListNode(int x){
        val = x;
    }
}

对象名存储的就是地址

java 复制代码
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(2);
        listNode1.next = listNode2;

new对象的时候,next默认是null的

java 复制代码
        ListNode head = listNode1 ;

可以弄一个head

java 复制代码
head = head.next();

这样就可以行走了,就可以从第一个遍历到第二个节点了

java 复制代码
        ListNode cur= head;
        while (cur!=null){
            System.out.println(cur.val);
            cur= cur.next;
        }

2.2.1 LinkedList的使用

LinkedList是java库中的链表,是双向链表

java 复制代码
        LinkedList<Integer> list = new LinkedList<>();
        List<Integer> list2 = new LinkedList<>();
  1. LinkedList实现了List接口
  2. LinkedList的底层使用了双向链表
  3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
  4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
  5. LinkedList比较适合任意位置插入的场景
java 复制代码
LinkedList() 无参构造
public LinkedList(Collection<? extends E> c) 使用其他集合容器中元素构造List
java 复制代码
            List<Integer> list2 = new LinkedList<>();
            list2.add(1);
            list2.add(2);
            List<Integer> list3 = new LinkedList<>(list2);

extends E表示E或者E的子类,E在这里指的就是Integer

所以构造方法可以传入参数

java 复制代码
Collection<Integer>

E就是

java 复制代码
            List<Integer> list3 = new LinkedList<>(list2);

中的Integer

而?是

java 复制代码
            List<Integer> list2 = new LinkedList<>();

中的Integer

所以可以传,可以这样构造

java 复制代码
            ArrayList<Integer> list4 = new ArrayList<>();
            list4.add(1);
            List<Integer> ret = new LinkedList<>(list4);

这样也可以,是因为ArrayList也实现了Collection接口,所以可以传

而且ArrayList的?也是Integer所以可以传

boolean add(E e) 尾插 e

void add(int index, E element) 将 e 插入到 index 位置

boolean addAll(Collection<? extends E> c) 尾插 c 中的元素

E remove(int index) 删除 index 位置元素

boolean remove(Object o) 删除遇到的第一个 o

E get(int index) 获取下标 index 位置元素

E set(int index, E element) 将下标 index 位置元素设置为 element

void clear() 清空

boolean contains(Object o) 判断 o 是否在线性表中

int indexOf(Object o) 返回第一个 o 所在下标

int lastIndexOf(Object o) 返回最后一个 o 的下标

List subList(int fromIndex, int toIndex) 截取部分 list

java 复制代码
        LinkedList<Integer> list = new LinkedList<>();
        List<Integer> list2 = new LinkedList<>();
        list2.add(1);
        list2.add(2);
        list2.add(1,3);
        System.out.println(list2);


clear就是清空了

java 复制代码
        for (Integer integer : list2) {
            System.out.println(integer);
        }
java 复制代码
        for (int i = 0; i < list2.size(); i++) {
            System.out.println(list2.get(i));
        }
java 复制代码
        Iterator<Integer> iterator = list2.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
java 复制代码
        Iterator<Integer> iterator2 = list2.listIterator();
        while (iterator2.hasNext()) {
            System.out.println(iterator2.next());
        }

反正和前面的ArrayLis是一样的

3. 栈

java 复制代码
        Stack<Integer> stack = new Stack<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);//入栈,返回值就是入栈元素3
        stack.pop();//出栈,返回值就是出栈元素3
        Integer peek = stack.peek();//获取栈顶元素,不删除
java 复制代码
        boolean empty = stack.isEmpty();

手动实现的话,就用数组---》顺序栈

用链表实现的话---》链式栈

4. 队列

Queue是个接口,底层是通过链表实现的

Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。

java 复制代码
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);//放入队列元素
        System.out.println(queue.poll());//取出对头元素,
        System.out.println(queue.peek());//获取对头元素,不删除
        System.out.println(queue.peek());
java 复制代码
        queue.isEmpty();

offer就是尾插

手动实现的话,就用LinkedList就可以实现了

或者自己定义节点也可以

两个队列来实现栈

两个栈来实现队列

java 复制代码
        ArrayDeque<Integer> arrayDeque = new ArrayDeque<>();

这是一个双端队列

Deque也是双端队列,只不过这个是接口

java 复制代码
        Deque<Integer> deque = new ArrayDeque<>();
java 复制代码
Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现
Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现

双端队列,就是两边都可以进出

java 复制代码
        Deque<Integer> deque = new LinkedList<>();//链式
        deque.offerFirst(1);
        Deque<Integer> deque2 = new ArrayDeque<>();//顺序

LinkedList和ArrayDeque都可以当做栈和队列使用

5. 二叉树

java 复制代码
class TreeNode{
    int val;
    public TreeNode left;
    public TreeNode right;
    TreeNode(int x){
        val = x;
    }
}

还有前序遍历(根左右),中序遍历(左根右),后序遍历(左右根)

层序遍历

6. PriorityQueue优先级队列(堆)

队列是一种先进先出(FIFO)的数据结构

操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列

PriorityQueue底层使用了堆这种数据结构

如果有一个关键码的集合K = {k0,k1, k2,...,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2...,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆

堆的性质:

堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

小根堆:根节点的大小,小于孩子节点

根节点大于左右孩子---》大根堆

将元素存储到数组中后,可以根据二叉树章节的性质对树进行还原。假设i为节点在数组中的下标,则有:

如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2

如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子

如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子

Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,多线程的情况下使用这个

java 复制代码
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(1);
        priorityQueue.offer(34);
        priorityQueue.offer(3);
        System.out.println(priorityQueue.peek());//获取第一个元素
        System.out.println(priorityQueue.poll());//删掉第一个元素
        System.out.println(priorityQueue.poll());//删掉第一个元素

PriorityQueue默认是一个小根堆

传入比较器就可以控制是大根,还是小根了

. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出ClassCastException异常

不能插入null对象,否则会抛出NullPointerException

  1. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容

  2. 插入和删除元素的时间复杂度为

  3. PriorityQueue底层使用了堆数据结构

. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素

java 复制代码
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(list);
        priorityQueue.offer(5);
        priorityQueue.offer(34);
        priorityQueue.offer(6);
        System.out.println(priorityQueue.peek());//获取第一个元素
        System.out.println(priorityQueue.poll());//删掉第一个元素
        System.out.println(priorityQueue.poll());//删掉第一个元素

boolean offer(E e)

插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时

间复杂度 ,注意:空间不够时候会进行扩容

E peek() 获取优先级最高的元素,如果优先级队列为空,返回null

E poll() 移除优先级最高的元素并返回,如果优先级队列为空,返回null

int size() 获取有效元素的个数

void clear() 清空

boolean isEmpty()检测优先级队列是否为空,空返回true

我们自己传入一个Comparator,就可以实现大根堆了

默认的Integer实现了Comparator,

但是它的Comparator是小根的形式

所以我们要搞一个大根堆的Comparator

java 复制代码
class IntCmp implements Comparator<Integer>{

    @Override
    public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
    }
}

这个就是原来的小根

java 复制代码
class IntCmp implements Comparator<Integer>{

    @Override
    public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
    }
}

这样就是大根了

java 复制代码
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new IntCmp());
        priorityQueue.offer(5);
        priorityQueue.offer(34);
        priorityQueue.offer(6);
        System.out.println(priorityQueue.peek());//获取第一个元素
        System.out.println(priorityQueue.poll());//删掉第一个元素
        System.out.println(priorityQueue.poll());//删掉第一个元素

这样就成功了


我们发现,堆的扩容是,如果原来容量小于64,就扩大两倍+2

如果大于64,就是扩大50%,就变为原来的150%

优先级队列的扩容说明:

如果容量小于64时,是按照oldCapacity的2倍方式扩容的

如果容量大于等于64,是按照oldCapacity的1.5倍方式扩容的

如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容

优先级队列在插入元素时有个要求:插入的元素不能是null或者元素之间必须要能够

进行比较,为了简单起见,我们只是插入了Integer类型,那优先级队列中能否插入自定义类型对象呢?

在Java中,基本类型的对象可以直接比较大小。

Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较。 那为什么==可以比较?

:对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equal方法,而==默认情况下调用的就是equal方法,但是该方法的比较规则是:没有比较引用变量引用对象的内容,而是直接比较引用变量的地址,但有些情况下该种比较就不符合题意。

有些情况下,需要比较的是对象中的内容,比如:向优先级队列中插入某个对象时,需要对按照对象中内容来调整堆,那该如何处理呢?

6.1 覆写基类的equals

java 复制代码
class Card{
    public int rank;

    @Override
    public boolean equals(Object o) {
        if(this == o) return true;//自己和自己比较返回true
        if(o==null||!(o instanceof Card)){
            return false;
        }
        Card card = (Card) o;
        return rank == card.rank;
    }

}

覆写基类equal的方式虽然可以比较,但缺陷是:equal只能按照相等进行比较,不能按照大于、小于的方式进行比较。

6.2 基于Comparble接口类的比较

java 复制代码
class Card implements Comparable<Card>{
    public int rank;

    @Override
    public boolean equals(Object o) {
        if(this == o) return true;//自己和自己比较返回true
        if(o==null||!(o instanceof Card)){
            return false;
        }
        Card card = (Card) o;
        return rank == card.rank;
    }

    @Override
    public int compareTo(@NotNull Card o) {
        return this.rank - o.rank;
    }
}

这个是从小到大的排序

这样就可以了

java 复制代码
        Card card = new Card(1);
        Card card2 = new Card(2);
        System.out.println(card.compareTo(card2));

6.3 基于比较器比较

java 复制代码
class RankComparator implements Comparator<Card>{

    @Override
    public int compare(Card o1, Card o2) {
        return o2.rank-o1.rank;
    }
}
java 复制代码
        RankComparator rankComparator = new RankComparator();
        System.out.println(rankComparator.compare(card, card2));

Object.equals 因为所有类都是继承自 Object 的,所以直接覆写即可,不过只能比较相等与否

Comparable.compareTo

需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于

内部顺序----》可以调用Arrays.sort()方法来对数组进行排序了

Comparator.compare

需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性

java 复制代码
        Card[] cards = new Card[]{card, card2};
        Arrays.sort(cards);
        Arrays.sort(cards, rankComparator);

这两个都是可以的

总结

相关推荐
爬山算法1 小时前
Redis(128)Redis的跳表(Skip List)是如何实现的?
数据库·redis·list
Moe4882 小时前
合并Pdf、excel、图片、word为单个Pdf文件的工具类(技术点的选择与深度解析)
java·后端
Moe4882 小时前
合并Pdf、excel、图片、word为单个Pdf文件的工具类(拿来即用版)
java·后端
oliveira-time2 小时前
原型模式中的深浅拷贝
java·开发语言·原型模式
进阶的猿猴2 小时前
easyExcel实现单元格合并
java·excel
小许学java3 小时前
MySQL-触发器
java·数据库·mysql·存储过程·触发器
JEECG低代码平台3 小时前
【2025/11】GitHub本月热度排名前十的开源Java项目
java·开源·github
百***86053 小时前
Spring BOOT 启动参数
java·spring boot·后端
跟着珅聪学java3 小时前
Spring Boot 中整合 MySQL 并打印 SQL 日志
java·spring boot