Java元素的比较

文章详细介绍了Java中基本类型和对象的比较方式,包括Object的equals方法用于对象的相等性比较,Comparable接口的compareTo方法实现对象的自然排序,以及Comparator接口的compare方法用于自定义排序。此外,还讨论了Comparable与Comparator接口的区别和应用场景。

目录

1.基本类型的比较

2.对象的比较

2.1.Object.equals(基于Object类的equals方法的比较)

2.2.Comparable.compareTo(基于Comparable接口的compareTo方法的比较)

2.3.Comparator.compare(基于比较器的比较-基于Comparator接口实现的compare方法)

3.总结


1.基本类型的比较

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

public class TestCompare {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        System.out.println(a > b);
        System.out.println(a < b);
        System.out.println(a == b);

        char c1 = 'A';
        char c2 = 'B';
        System.out.println(c1 > c2);
        System.out.println(c1 < c2);
        System.out.println(c1 == c2);

        boolean b1 = true;
        boolean b2 = false;
        System.out.println(b1 == b2);
        System.out.println(b1 != b2);
    }
}

2.对象的比较

class Card{
    public int rank; //数值
    public String suit; //花色

    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }
}

public class TestPriorityQueue {
    public static void main(String[] args) {
       Card c1 = new Card(1, "♣");
       Card c2 = new Card(2, "♣");
       Card c3 = c1;
       //c1, c2, c3分别是Card类型的引用变量
//        System.out.println(c1 > c2); //编译报错
        System.out.println(c1 == c2); //编译成功,打印false,因为c1和c2指向不同对象
//        System.out.println(c1 < c2); //编译报错
        System.out.println(c1 == c3); //编译成功,打印true,因为c1和c3指向同一对象
    }
}

可知:

  • Java中引用类型的变量不能直接按照">"或者"<"方式进行比较,而"=="可以比较。
  • 因为对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equals方法。"=="默认调用equals方法。
  • equals方法的比较规则是:没有比较引用变量引用对象的内容,而是直接比较引用变量的地址。

2.1.Object.equals(基于Object类的equals方法的比较)

比较2个自定义的对象是否相等,默认比较2个对象的地址是否相等,覆写Object基类提供的equals方法。

  1. this == o
  2. o == null
  3. !(o instanceof Student)
  4. this.name.equals(stu.name) 按照类的实现目标完成比较
  5. 下调用其他引用类型的比较,也要用equals
public class Student {
    private String name;
    private int age;

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

    @Override //检查是否覆写正确,没报错,说明写对了
    public boolean equals(Object o) {
        //this表示当前对象,我自己和传进来的是一个东西,自己和自己比,为true
        if(this == o) {
            return true;
        }
        if(o == null || !(o instanceof  Student)) {
            //传入对象为空 或 不是Student类型对象(o不是披着Student外衣的Object)
            return false;
        }
        //此时o一定不是空,且是Student对象,脱掉o的小马甲
        //向下转型,还原回来
        Student stu = (Student) o;
        return this.name.equals(stu.name);
    }

    public static void main(String[] args) {
        Student stu1 = new Student("张三", 18);
        Student stu2 = new Student("李四", 20);
        Student stu3 = new Student("张三", 30);
        System.out.println(stu1.equals(stu2)); //false
        System.out.println(stu1.equals(stu3)); //true
    }
}

缺点:equals方法只能按照相等进行比较,不能按照大于,小于的方式进行比较。

2.2.Comparable.compareTo(基于Comparable接口的compareTo方法的比较)

  • 对用户自定义类型,如果想要按照大小方式进行比较,在定义类时,实现Comparable接口即可,然后重写类中的compareTo方法。
  • Comparable是JDK提供的泛型的比较接口类,是java.lang中的接口,可直接使用。
  • 当一个类覆写了Comparable接口(规范/能力),就表示该类具备了可比较的能力,就不需要equals方法。
  • 源码实现如下:

import java.util.Arrays;

public class Student2 implements Comparable<Student2> {
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Student2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student2 o) {
        if(this.age == o.age) {
            return 0;
        } else if(this.age < o.age) {
            return -1;
        } else {
            return 1;
        }
    }

    public static void main(String[] args) {
        Student2 stu1 = new Student2("张三", 18);
        Student2 stu3 = new Student2("张三", 30);
        Student2 stu2 = new Student2("李四", 20);
        System.out.println(stu1.compareTo(stu2)); //-1
        System.out.println(stu1.compareTo(stu3)); //-1
        Student2[] student2s = {stu1, stu3, stu2};
        Arrays.sort(student2s);
        System.out.println(Arrays.toString(student2s));
    }
}

2.3.Comparator.compare(基于比较器的比较-基于Comparator接口实现的compare方法)

  • Comparator是java.util包中的泛型接口类,使用时必须导入对应的包。
  • 有了这个接口后,需要怎么排序就创建一个新的实现了Comparator接口的子类即可,对原类无影响。
  • Comparator比Comparable接口灵活。例:假设之前是按照年龄升序排序,现在需要按照年龄降序排序:
  1. Comparable接口:得修改Student类的实现,修改CompareTo方法。原则上Comparable只能实现一种大小关系比较(绑定在Student中)
  2. Comparator比较器:可以不修改任何Student类的代码,实现不同的比较关系。Comparator可以实现无数种的比较(23种模式之一的策略模式)
  • 二者最大的用处在于排序,HashMap和HashSet要求自定义的类必须覆写equals或实现比较接口。
  • 用户自定义的比较器类,实现Comparator接口。源码实现如下:
public interface Comparator<T> {
    //返回值
    // <0 表示o1指向的对象小于o2指向的对象
    // >0 表示o1指向的对象大于o2指向的对象
    // ==0 表示o1指向的对象等于o2指向的对象

    int compare(T o1, T o2);

    //...
}
import java.util.Arrays;
import java.util.Comparator;

public class Student3 {
    private String name;
    private int age;

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student3{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //Student这个类还不具备可比较的能力,创建了一个新的类,就是比较Student对象大小关系
    //相当于把比较Student对象大小关系这个事外包了,Student类自己不干这些事

    /**
     * 升序
     */
    static class AgeSec implements Comparator<Student3> {
        @Override
        public int compare(Student3 o1, Student3 o2) {
            if(o1.getAge() == o2.getAge()) {
                return 0;
            } else if(o1.getAge() > o2.getAge()) {
                return 1;
            }
            return -1;
        }
    }

    //要将Student年龄按照降序排序,再创建一个比较器,不修改Student类的内容,称为无侵入编程

    /**
     * 降序
     */
    static class AgeDeSec implements Comparator<Student3> {
        @Override
        public int compare(Student3 o1, Student3 o2) {
            if(o1.getAge() == o2.getAge()) {
                return 0;
            } else if(o1.getAge() > o2.getAge()) {
                return -1;
            }
            return 1;
        }
    }

    public static void main(String[] args) {
        Student3 stu1 = new Student3("张三", 18);
        Student3 stu3 = new Student3("张三", 30);
        Student3 stu2 = new Student3("李四", 20);
        Student3[] student3s = {stu1, stu3, stu2};
        AgeSec ageSec = new AgeSec();
        Arrays.sort(student3s, ageSec);
        System.out.println(Arrays.toString(student3s)); //升序打印
        AgeDeSec ageDeSec = new AgeDeSec();
        Arrays.sort(student3s, ageDeSec);
        System.out.println(Arrays.toString(student3s)); //降序打印
    }
}

PS:

  • ctrl + Y 可将误删的所有内容一次性还原
  • ctrl + Z 撤销,可将误删的内容的最后一步还原

3.总结

覆写的方法

说明

位置,比较内容

Object.equals

Object类提供的equals方法,因为所有类都是继承自Object的,所以直接覆写即可。默认比较2个对象的地址是否相等,只能比较是否相等,不能比较大小关系。

类内

比=

Comparable.compareTo

java.lang中的接口,需要手动实现接口,侵入性较强,但一旦实现,每次用该类都有顺序,属于内部顺序。

类内

比=、>、<

Comparator.compare

java.util中的接口,需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性强。

类外

比=、>、<

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值