Java>> equals()、“==“与 compareTo() 详解以及区别

2 篇文章 0 订阅

准备工作

在 Java 中,比较两个对象或者数据大小的时候,我们会经常用到 equals()方法、"=="和 compareTo() 方法。对于这三种方法,它们到底是如何进行比较的,以下做一个简单分析。
为了防止类中对 equals() 方法重写的干扰,在这里,我们自己创建一个类,自己决定是否对 equals() 方法进行重写,并由此更好的区分 " == " 与 equals() 方法的区别。

实现自定义类

这里实现一个 student 类,类包含 name,age,score 这三个属性. 并实现 Comparable 接口(compareTo 就是该接口中的方法)

class Student implements Comparable<Student>{
    String name;
    int age;
    int score;

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

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

实现测试方法

此方法用于对以上三种方法进行测试.
方法实现的同时,先生成三个 student 对象,用于后面测试.

public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("wang",18,70);
        students[1] = new Student("wang",18,70);
        students[2] = new Student("hu",30,47);
}

“==”

请看代码:

    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("wang",18,70);
        students[1] = new Student("wang",18,70);
        students[2] = new Student("hu",30,47);
        
        System.out.println(students[0] == students[1]);
}

此时比较的是 两个地址不同值相同的 student 对象,结果如下:
在这里插入图片描述
那么,问题来了,值相同为什么结果还是 false 呢?
请看如下代码:

    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("wang",18,70);
        students[1] = new Student("wang",18,70);
        students[2] = new Student("hu",30,47);

        String a = "abc";  // 
        String b = "abc";  // 若不申请新的地址,对于相同字符串,它们的地址是一样的
		String c = new String("abc");   // 申请新的地址
		
        int a1 = 123;  
        int b1 = 123;

        System.out.println(students[0] == students[1]);
        System.out.println(a == b);   // a 和 b 同时指向存储 'abc' 这个字符串的地址
        System.out.println(a == c);   // c 申请新的地址
        System.out.println(a1 == b1);  // 基本数据类型

}

输出结果:
在这里插入图片描述
上述我们看到了, 当数据类型为整形,当变量的值相等的时候,结果就为 true ,否则为 false.
当为 student 类对象 或者 String 类型,当它们的地址一样的时候,返回值才为 true,否则为 false.
结论:

  • 对于基本数据类型(如 int、float等), " == " 比较的是值是否相等,即内容是否一样;
  • 对于引用数据类型(如类、数组等),"==" 比较的是引用是否相等

备注:此处对于 float、double、数组等类型就不一一列举了,感兴趣的可以测试下,结果都是相似的
Java基本数据类型和引用数据类如下:
在这里插入图片描述

equals()

重写 equals() 方法

在测试之前,我们先自己在 student 类中实现 equals() 方法,如下:

class Student implements Comparable<Student>{
    String name;
    int age;
    int score;

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
    /*
    * equals方法    
    * 在此,实现的是名字,年龄和分数都相同的情况返回ture
    * 还会生成一个hashcode方法,这俩总是成对存在
    * */
    @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 && score == student.score && Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age, score);
    }

}

进行测试:

    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("wang",18,70);
        students[1] = new Student("wang",18,70);
        students[2] = new Student("hu",30,47);

        System.out.println(students[0].equals(students[1]));   // 值一样
		System.out.println(students[0].equals(students[2]));   // 值不一样
    }

结果:
在这里插入图片描述

不重写 equals() 方法

只需要将上面重写的方法注释掉即可:

class Student implements Comparable<Student>{
    String name;
    int age;
    int score;

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

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


    /*
    * equals方法    比较的是名字,年龄和分数都相同的情况返回ture
    * 还会生成一个hashcode方法,这俩总是成对存在
    * */
    /*@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 && score == student.score && Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age, score);
    }*/

}

测试代码和上述一样,结果如下:
在这里插入图片描述

小结

重写 equals() 方法的时候,此时该方法只是比较值是否相等,也就是内容是否相等。当我们不重写 equals() 方法时,即使值一样也会返回 false,这是为什么呢? 这还得看看 equals() 方法的源码(即具体实现),如下:
在这里插入图片描述

在这里插入图片描述
当我们点击进来的时候,其实发现此时进入了 Object 类,其中的 equals() 方法其实还是通过 “==” 实现的。这样一来上述疑问就解决了,student 对象是引用类型(没有自己实现方法重写),进行比较的时候会自动调用 Object 类中的 equals() 方法,此时比较的是地址是否相等,显然 student[0] 与 student[1] 的地址是不相等的,所以返回 false。
当我们再来查看 String 类中 equals() 方法:
在这里插入图片描述
此时,先是比较的是地址是否一样,一样返回 true,不一样则进行值的比较,即内容相等就返回 true,否则为 false. 这显然是对 equals() 方法进行了重写.

总结(以及 equals() 与 " == " 的区别):

  • equals() 方法是判断两个对象是否相等,分为两种情况:
  1. 类没有重写 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于使用 “==” 比较对象,即 判断地址是否相等
  2. 类重写了 equals() 方法。一般类都会重写这个方法(例如 String 类,Integer等),此时是判断对象的值是否相等(内容是否相等),相等为 true,相反为 false;

即 equals() 方法默认情况下是地址比较,只是很多类重写了 equals() 方法,将 equals() 变为值比较,而一般类都会重写该方法,所以一般情况下,equals() 都是用值进行比较。

compareTo()

观察 compareTo() 方法的源码:
在这里插入图片描述
可以看出这里其实是获取两个字符串/对象的长度,然后做减法(根据ASCll码),compareTo() 方法就会返回一个 int 类型的数。若两个字符串相同,就会返回0,若前面的大于后面的,返回相差ASCll码(正数),反之,返回相差负数ASCll码。
看如下例子:

    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("wang",18,70);
        students[1] = new Student("wang",18,70);
        students[2] = new Student("hu",30,47);

        int ret = students[0].compareTo(students[1]);    //compareTO方法
        int r = students[0].compareTo(students[2]); 
        System.out.println(ret);          //输出大于0表示前面大于后面的
        System.out.println(r); 
    }

结果如下:
在这里插入图片描述
在这里,我自己重写了一个简易 compareTo() 方法(代码在下面),用 age 来进行比较,能够较好的说明了 compareTo() 方法的原理。

@Override
    public int compareTo(Student o) {             //用年龄进行比较
      /*if(this.age > o.age){
            return 1;
        }else if(this.age < o.age){
            return -1;
        }else
            return 0;  */         //第一种写法

        return this.age - o.age;   //第二中写法   前面对象是this 后面对象是o
    }

compareTo() 与 equals() 的区别:

  • 返回结果不同:compareTo() 就是返回两者的差值,返回值是一个 int 类型,而 equals() 只是返回 true 或者 false;
  • 比较方式不同:compareTo() 是差值比较,equals() 一般来说都是根据值是否相等进行比较;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值