Java对象的比较——equals方法,Comparable接口,Comparator接口

2024-06-01 1227阅读

Java对象的比较——equals方法,Comparable接口,Comparator接口

  • 1. equals方法
  • 2. Comparable接口
  • 3. Comparator接口

    1. equals方法

    在判断两个整数是否相同时,我们可以使用以下方式:

    System.out.println(1 == 2);

    System.out.println(1 == 1);

    如果输出true,则说明这两个整数相同;如果输出false,则说明这两个整数不相同

    那么,如果将==用于判断两个对象,又会是怎样的情况呢?我们直接敲代码来看看!

    public class Dog {
        private String name;
        private int age;
        public Dog(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
    public class Test1 {
        public static void main(String[] args) {
            Dog dog1 = new Dog("zhangsan",1);
            Dog dog2 = new Dog("zhangsan",1);
            System.out.println(dog1 == dog2);
        }
    }
    

    运行结果:

    Java对象的比较——equals方法,Comparable接口,Comparator接口

    当运行这段代码时,我们发现输出的是false。明明dog1和dog2的属性都一模一样,为什么输出false呢?莫慌,且听我慢慢道来!

    Java对象的比较——equals方法,Comparable接口,Comparator接口

    画图来分析,dog1和dog2中存放的值并不相同,因此dog1 != dog2。而你之所以认为输出的应该是true,是因为你认为,两个对象的属性完全一致,所以dog1 == dog2.其实,并不是这样的,==判断的并不是对象的属性是否一致,而是判断两个引用指向的是否是同一个对象!

    在Java中,一切皆对象。而dog1和dog2是对象的引用。==判断的并不是对象的属性是否一致,而是判断两个引用指向的是否是同一个对象!

    因此,只有当两个引用指向同一对象才返回true;而如果两个引用指向不同的对象,即使两个对象的属性完全相同,返回依旧是false!

    总结:

    • 如果==左右两边是基本数据类型变量,比较的是变量中的值是否相同
    • 如果==左右两边是引用数据类型变量,比较的是引用变量中的值是否相同,而引用变量中存放的是对象的地址,所以比较的就是引用变量中存放的地址是否相同(即判断两个引用指向的是否是同一个对象!)

      理解了这一点,学习equals方法就简单多了!我们先来看看equals方法的原型,equals方法在Object类中

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      有没有发现,equals方法,返回正是刚刚所讲的内容,说明equals方法默认就是判断两个引用指向的是否是同一个对象!

      注意: equals方法的返回值是boolean类型!

      再来尝试运行这段代码:

      public class Test1 {
          public static void main(String[] args) {
              Dog dog1 = new Dog("zhangsan",1);
              Dog dog2 = new Dog("zhangsan",1);
              System.out.println(dog1.equals(dog2));
          }
      }
      

      运行结果依旧是false


      那么,问题来了,如果我们想通过比较两个对象的属性是否相等,如果相等,从逻辑上就说明他们就是相等的,该怎么办呢?

      我们知道Object类是一切类的父类,而equals方法在Object类中,是不是就通过可以重写equals方法,从而达到自定义比较方式的目的!

      下面就演示重写equals方法,规则:如果两个对象的属性完全一致,则返回true;否则放回false

      public class Dog {
          private String name;
          private int age;
          public Dog(String name, int age) {
              this.name = name;
              this.age = age;
          }
          public boolean equals(Object obj) {
              Dog tmp = (Dog)obj;
              return this.name.equals(tmp.name) && this.age == tmp.age;
          }
      }
      
      public class Test1 {
          public static void main(String[] args) {
              Dog dog1 = new Dog("zhangsan",1);
              Dog dog2 = new Dog("zhangsan",1);
              System.out.println(dog1.equals(dog2));
          }
      }
      

      这时运行代码,输出的就是true!

      这时,有人可能就有疑问了,为什么名字比较要用equals方法,其实这里的equals方法并非Dog类中的equals方法,而是String类中的equals方法,用来判断两个字符串是否相等

      String类中的equals方法原型:

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      另外,编译器可以帮我们自动生成equals方法,第一步按住alt+insert

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      一路点下去,就可以生成equals方法,除此之外,还生成了hashCode方法

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      2. Comparable接口

      通过重写equals方法,我们可以从逻辑上去判断两个对象是否相同。但是如果要去比较两个对象的大小,又该怎么去比较呢?对象的属性那么多,通过什么属性去比较呢?这时就需要讲到Comparable接口!

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      当我们在Student类后加上Comparable接口时,发现会报错,这是为什么呢?我们按住CTRL键,再鼠标左击Comparable,进入源码

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      我们发现,Comparable接口中还有个compareTo抽象方法,因此当我们在Student类要实现这个方法,除此之外,Comparable接口后还有个,这是泛型,我们需要比较什么类型的对象,就在实现接口时把T改成什么

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      由编译器自动生成实现compareTo方法的代码后:

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      我们就需要书写compareTo的方法体,那怎么书写呢?你想根据哪个对象的属性进行比较,就怎么书写。


      比如,我现在想根据对象的年龄进行比较

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      下面进行测试:

      public class Student implements Comparable{
          private String name;
          private int age;
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
          }
          @Override
          public int compareTo(Student o) {
              return this.age-o.age;
          }
      }
      
      public class Test {
          public static void main(String[] args) {
              Student student1 = new Student("zhangsan", 18);
              Student student2 = new Student("lisi", 10);
              System.out.println(student1.compareTo(student2));
          }
      }
      

      运行结果:

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      返回的是一个正数,说明根据年龄比较,student1大于student2


      再比如,我不想根据年龄比较了,我想根据姓名比较,这时就不能用简单的this.name-o.name了,因为name是一个String类型,不能通过这样的方式进行比较

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      方法里的compareTo指并不是在Student类中具体实现的这个compareTo,而是String类中的conpareTo,用于字符串的比较,它的底层是和C语言的strcmp是一样的,返回的是两个字母的ASCII 码的差值

      Java对象的比较——equals方法,Comparable接口,Comparator接口


      那么,问题来了,前面我们比较的只有两个对象,如果需要比较多个对象呢,改怎么办呢?这时候就需要用到数组来存放对象,用Arrays里的排序方法进行排序

      当我们写下以下代码:

      public class Student {
          private String name;
          private int age;
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
          }
          @Override
          public String toString() {
              return "Student{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      
      public class Test {
          public static void main(String[] args) {
              Student[] students = new Student[]{
                      new Student("zhangsan",18),
                      new Student("lisi", 10),
                      new Student("wangwu", 20)};
              System.out.println("排序前:" + Arrays.toString(students));
              Arrays.sort(students);
              System.out.println("排序后:" + Arrays.toString(students));
          }
      }
      

      当我们运行代码后,发现会出现异常

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      这里需要用到强转,而Student类并没有去实现Comparable接口,因此会导致强转失败!这就是异常所在!所以,我们需要在Student类中实现Comparable接口

      public class Student implements Comparable{
          private String name;
          private int age;
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
          }
          @Override
          public String toString() {
              return "Student{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
          @Override
          public int compareTo(Student o) {
              return this.age-o.age;
          }
      }
      

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      当我们再次去运行代码时,会发现排序后是根据年龄从小到大排序的,这和Student类中实现的compareTo难道有关系?答案是正确的

      假如我们想按照年龄从大到小去排序,就做出如下更改

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      调换顺序即可,再次运行代码:

      Java对象的比较——equals方法,Comparable接口,Comparator接口


      假如想根据年龄去比呢?

      public class Student implements Comparable{
          private String name;
          private int age;
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
          }
          @Override
          public String toString() {
              return "Student{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
          @Override
          public int compareTo(Student o) {
              return this.name.compareTo(o.name);
          }
      }
      
      public class Test1 {
          public static void main(String[] args) {
              Student[] students = new Student[]{
                      new Student("zhangsan",10),
                      new Student("lisi", 18),
                      new Student("wangwu", 9)};
              System.out.println("排序前:" + Arrays.toString(students));
              Arrays.sort(students);
              System.out.println("排序后:" + Arrays.toString(students));
          }
      }
      

      3. Comparator接口

      在前面使用Comparable接口来实现对象的比较时,我们不难发现,这个比较方法并不灵活,只能固定地通过一种方式去比较,那么如果我们有的时候想通过年龄比较,有的时候想通过姓名比较,这个接口就无法实现了,这时地解决办法就是,换一个接口,用Comparator接口来实现!

      这时,我们分别写两个类——NameComparator和AgeComparator,代表分别通过姓名比较和通过年龄比较。并且这两个类都要实现Comparator接口!

      import java.util.Comparator;
      public class NameComparator implements Comparator {
          @Override
          public int compare(Student o1, Student o2) {
              return o1.getName().compareTo(o2.getName());//姓名通过compareTo方法进行比较
          }
      }
      
      import java.util.Comparator;
      public class AgeComparator implements Comparator {
          @Override
          public int compare(Student o1, Student o2) {
              return o1.getAge() - o2.getAge();
          }
      }
      

      注意: 实现Comparator接口需要重写的时compare方法,不是compareTo方法!实现Comparable接口重写的才是compareTo方法!

      学生类如下:

      public class Student {
          private String name;
          private int age;
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
          }
          public String getName() {
              return name;
          }
          public int getAge() {
              return age;
          }
          @Override
          public String toString() {
              return "Student{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      

      测试一下代码:

      import java.util.Arrays;
      public class Test {
          public static void main(String[] args) {
              //两个对象的比较
              AgeComparator ageComparator = new AgeComparator();
              NameComparator nameComparator = new NameComparator();
              Student student1 = new Student("zhangsan", 20);
              Student student2 = new Student("lisi", 30);
              System.out.println("根据年龄比:" + ageComparator.compare(student1, student2));
              System.out.println("根据姓名比:" + nameComparator.compare(student1, student2));
              //一组对象的比较
              Student[] students = new Student[]{
                      new Student("zhangsan", 10),
                      new Student("lisi", 18),
                      new Student("wangwu", 9)};
              System.out.println("排序前:" + Arrays.toString(students));
              Arrays.sort(students, ageComparator);
              System.out.println("根据年龄排序后:" + Arrays.toString(students));
              Arrays.sort(students, nameComparator);
              System.out.println("根据姓名排序后:" + Arrays.toString(students));
          }
      }
      

      分析两个对象的比较:

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      这里,我们创建了一个AgeComparator和一个NameComparator对象,用来表示是通过年龄比较还是通过姓名比较。注意最后两个Student类对象的比较方法

      分析一组对象的比较:

      Java对象的比较——equals方法,Comparable接口,Comparator接口

      我们发现,在用Arrays.sort排序时,里面还加上了一个ageComparator对象(或NameComparator对象),通过这个对象,可以控制通过什么方式去比较,当使用Arrays对数组进行排序时,就会调用ageComparator(或NameComparator)里的compare方法依次将数组里的对象进行比较

      最后,运行结果:

      Java对象的比较——equals方法,Comparable接口,Comparator接口


      Java对象的比较——equals方法,Comparable接口,Comparator接口

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]