Comparison of reference type variables (objects) in Java

Article directory

  • 1. == and equals() methods
    • Compare non-custom classes
    • Compare custom classes
  • 2. Comparable interface
    • Use of Comparable interface
    • Advantages and Disadvantages of Using Comparable to Compare Custom Classes
  • 3. Comparator interface
    • Use of Comparator interface
    • Advantages of using Comparator to compare custom classes

1. == and equals() methods

== compares whether the addresses of the two objects are the same (that is, whether the two references point to the same object).
The equals() method compares whether the contents in the object are the same. (equals() is a method in the Object class, and all classes inherit the Object class by default)

Compare non-custom classes

Take the String class as an example:

 public static void main(String[] args) {<!-- -->
        String s1 = new String("hello");
        String s2 = new String("hello");
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }

Program running results:
false;
true;

The reason is as shown below: (The objects pointed to by s1 and s2 references are different, but the content of value is the same)

Through the running results of the above code, we already have a certain understanding of the comparison methods of == and equals() methods. So what is the result of running the following code? (You can pause and think about it first)

 public static void main(String[] args) {<!-- -->
        String s1 = new String("hello");
        String s2 = "hello";
        String s3 = "hello";
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
        System.out.println(s2 == s3);
        System.out.println(s2.equals(s3));
    }

Program running results:
false
true
true
true

I believe that the results of running the code may be unexpected by some people, so what is the reason?
Regarding the second and fourth results, everyone should have no doubts. After all, the content in each String object is “hello”, and the result printed by the program is undoubtedly true.

The reason why the result of the third comparison is true is that there is a String constant pool in the heap area. All String objects non-new will be stored in the constant pool. When using another When there are String objects with the same content and not new, their references will point to the same object in the constant pool, that is, the constant pool only saves one String object with the same value.
According to the above description, we can know that the object pointed to by s1 is an object instantiated through new, and its storage location in memory is different from that of s2 and s3, so their addresses must also be different.

The specific memory distribution is as follows:

Compare custom classes

Suppose there is a custom class as follows and two instantiated objects of the corresponding class. When they are compared using the == and equals() methods, what will the result be?

public class Demo {<!-- -->

    public static void main(String[] args) {<!-- -->
        Student s1 = new Student("lisi",12);
        Student s2 = new Student("lisi",12);
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }

}

class Student {<!-- -->
    String name;
    int age;

    public Student(String name, int age) {<!-- -->
        this.name = name;
        this.age = age;
    }

    public void func() {<!-- -->}
}

Program running results:
false
false

The result of running the code here is actually not difficult to understand. == compares the address of the referenced object. s1 and s2 are two different objects, so the addresses must be different; and the equals() method compares the addresses in the objects. Content, because the Student class has multiple attributes, it will not directly go to the attributes in the class, but will still compare the addresses of the two objects.
From this we can easily infer that the String class actually has multiple attributes. The reason why String objects can be compared using the equals() method is because the String class has overridden the equals() method.

Therefore, when we use the equals() method to compare custom classes, we must rewrite this method and compare the member variables in the class in sequence.
Rewrite the equals() method code as follows:

 @Override
    public boolean equals(Object obj) {<!-- -->
        // Check if it is the same object
        if(this == obj) return true;
        // Check whether the compared object is null
        if(obj == null) return false;
        // Check whether the comparison objects are of the same type
        if(this.getClass() != obj.getClass()) return false;

        // Compare all properties in both classes
        Student student = (Student) obj;
        if(this.age != student.age) return false;
        if(this.name == null & amp; & amp; student.name == null) {<!-- -->
            return true;
        }else if(this.name == null || student.name == null) {<!-- -->
            return false;
        } else {<!-- -->
            return this.name.equals(student.name);
        }
    }

The running result of the program after rewriting equals():
false
true

2. Comparable interface

Usage of Comparable interface

Different from the equals() method, the parameter returned by the equals() comparison result is of boolean type. This method can only know whether the contents of the two objects are the same.
Implement the Comparable interface and override the compareTo() method. The parameter returned by the comparison result is of type int. It can compare the sizes of two objects by comparing a specific attribute in the object.

The template implemented by Comparable is as follows:

class Student implments Comparable<E> {<!-- -->
\t//Attributes
\t//method
\t
// return value:
// < 0: Indicates that the object pointed to by this is smaller than the object pointed to by o
// == 0: Indicates that the object pointed to by this is equal to the object pointed to by o
// > 0: Indicates that the object pointed to by this is greater than the object pointed to by o
int compareTo(E o) {<!-- -->
\t
}
}

The more specific implementation code of the Student object is as follows:

public class Demo {<!-- -->

    public static void main(String[] args) {<!-- -->
        Student s1 = new Student("zhangsan",12);
        Student s2 = new Student("lisi",18);
        System.out.println(s1.compareTo(s2));
    }

}

class Student implements Comparable<Student>{<!-- -->
    String name;
    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 void func() {<!-- -->}
}

Implement the Comrable interface and rewrite the compareTo() method. The running result of the program is:
-6

If you want to distinguish the size of Student objects by comparing names, you need to compare the size of each character in the string. You can implement this yourself.

The advantages and disadvantages of using Comparable to compare custom classes

advantage:
1. For arrays of custom class objects, if there is a need to sort elements, you can directly call the Arrays.sort() method to sort the array.
2. If you need to build a custom object into a heap, you only need to implement the Comrable interface in the class and override the compareTo() method.

shortcoming:
Once the attributes to be compared are determined, if the comparison requirements change later, the code for attribute comparison in the class needs to be re-modified. Once the class has been widely used, arbitrarily modifying the compraeTo() method in the class may cause others to mistakenly Using this method may cause logical errors in some codes.

3. Comparator interface

Usage of Comparator interface

To use the Comparator interface to compare custom objects, we need to customize a comparator class, implement the Comparator interface, rewrite the compare() method, and compare the attributes in the required classes to get the size relationship between the two objects. (You can customize multiple different comparator classes as needed to compare different attributes in the class)

The comparator template is as follows:

class cmp implements Comparator<T>{<!-- -->
// return value:
// < 0: means that the object pointed by o1 is smaller than the object pointed by o2
// == 0: Indicates that the object pointed by o1 is equal to the object pointed by o2
// > 0: Indicates that the object pointed by o1 is equal to the object pointed by o2
int compare(T o1, T o2) {<!-- -->
// method body
}

The more specific implementation code of the Student object is as follows:

public class Demo {<!-- -->

    public static void main(String[] args) {<!-- -->
        Cmp_age cmp = new Cmp_age();
        Student s1 = new Student("zhangsan",15);
        Student s2 = new Student("lisi",18);

        System.out.println(cmp.compare(s1, s2));
    }

}

class Cmp_age implements Comparator<Student> {<!-- -->
    @Override
    public int compare(Student o1, Student o2) {<!-- -->
        return o1.age - o2.age;
    }
}

Code running results:
-3

Advantages of using Comparator to compare custom classes

1. The comparison is highly flexible, and the corresponding comparator can be constructed as needed without affecting the custom class.
2. If you need to build a custom object into a heap, you only need to pass in the custom comparator class as a parameter when instantiating the PriorityQueue class.