Phương thức equals() và hashCode() trong java

Bài viết này giúp bạn hiểu khái niệm 2 phương thức quan trọng: Phương thức equals() và hashCode() trong Java.

Phương thức equals() và hashCode() trong java

Khi sử dụng các collection, Để nhận được các hành vi mong muốn, chúng ta nên ghi đè các phương thức equals() và hashCode() trong các lớp của các phần tử được thêm vào collection.

Lớp Object (lớp cha của tất cả các lớp trong Java) định nghĩa hai phương thức equal() và hashCode(). Điều đó có nghĩa là tất cả các lớp trong Java (bao gồm cả các lớp bạn đã tạo) thừa kế các phương thức này. Về cơ bản, lớp Object thực hiện các phương thức này cho mục đích chung.

Tuy nhiên, bạn sẽ phải ghi đè chúng một cách cụ thể cho các lớp có đối tượng được thêm vào các collection, đặc biệt là các collection dựa trên bảng băm như HashSet và HashMap.


Nội dung chính:

 

Phương thức equals() trong Java

Khi so sánh hai đối tượng với nhau, Java gọi phương thức equals() của chúng trả về true nếu hai đối tượng bằng nhau hoặc false nếu hai đối tượng là khác nhau. Lưu ý rằng phép so sánh sử dụng phương thức equals() so với sử dụng toán tử == là khác nhau.

Đây là sự khác biệt:

Phương thức equals() được thiết kế để so sánh hai đối tượng về mặt ngữ nghĩa (bằng cách so sánh các thành viên dữ liệu của lớp), trong khi toán tử == so sánh hai đối tượng về mặt kỹ thuật (bằng cách so sánh các tham chiếu của chúng, nghĩa là địa chỉ bộ nhớ).

LƯU Ý: Việc cài đặt phương thức equals() trong lớp Object so sánh các tham chiếu của hai đối tượng. Điều đó có nghĩa là bạn nên ghi đè nó trong các lớp của bạn để so sánh ngữ nghĩa. Hầu hết các lớp trong JDK ghi đè phương thức equals() của riêng chúng, chẳng hạn như String, Date, Integer, Double, v.v.

Ví dụ phương thức equals() của đối tượng String

Ví dụ điển hình so sánh chuỗi trong Java, để thấy sự khác nhau giữa phương thức equal() và toán tử ==.

package vn.viettuts;
public class EqualExample1 {
    public static void main(String[] args) {
        String s1 = new String("This is a string");
        String s2 = new String("This is a string");
        System.out.println("s1 == s2: " + (s1 == s2));
        System.out.println("s1.equals(s2): " + (s1.equals(s2)));
    }
}

Kết quả:

s1 == s2: false
s1.equals(s2): true

So sánh tham chiếu (toán tử ==) trả về false vì s1 và s2 là hai đối tượng khác nhau được lưu trữ ở các vị trí khác nhau trong bộ nhớ. Trong khi so sánh ngữ nghĩa trả về true bởi vì s1 và s2 có cùng giá trị (“THis is a string”) có thể được coi là bằng nhau về mặt ngữ nghĩa.

Ví dụ ghi đè phương thức equals()

Tương tự như vậy, giả sử chúng ta có lớp Student và cài đặt phương thức equal() như sau:

Trong thực tế, chúng ta có thể xem xét hai đối tượng Student có ngữ nghĩa tương đương nhau nếu chúng có cùng thuộc tính (id, name, email và age). Bây giờ, hãy xem cách ghi đè phương thức equals() trong lớp này để xác nhận rằng hai đối tượng Student có các thuộc tính giống nhau được coi là bằng nhau:

public class Student {
    private String id;
    private String name;
    private String email;
    private int age;
    public Student(String id, String name, String email, int age) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.age = age;
    }
    public String toString() {
        String studentInfo = "Student " + id;
        studentInfo += ": " + name;
        studentInfo += " - " + email;
        studentInfo += " - " + age;
        return studentInfo;
    }
    
    public boolean equals(Object obj) {
        if (obj instanceof Student) {
            Student another = (Student) obj;
            if (this.id.equals(another.id) &&
                this.name.equals(another.name) &&
                this.email.equals(another.email) &&
                this.age == another.age) {
                    return true;
            }
        }
        return false;
    }
}

Tạo ra lớp EqualStudent.java để kiểm tran phương thức equal() trong lớp Student.

package vn.viettuts;
public class EqualStudent {
    public static void main(String[] args) {
        Student student1 = new Student("123", "Cong", "cong@gmail.com", 22);
        Student student2 = new Student("123", "Cong", "cong@gmail.com", 22);
        Student student3 = new Student("456", "Dung", "dung@gmail.com", 18);
        System.out.println("student1 == student2: " + (student1 == student2));
        System.out.println("student1.equals(student2): "
                + (student1.equals(student2)));
        System.out.println("student2.equals(student3): "
                + (student2.equals(student3)));
    }
}

Kết quả:

student1 == student2: false
student1.equals(student2): true
student2.equals(student3): false

Ví dụ ghi đè phương thức equals() của phần tử của collection

Ta có lớp Student.java có nội dung như sau:

package vn.viettuts;
public class Student {
    private String id;
    private String name;
    private String email;
    private int age;
    public Student(String id) {
        this.id = id;
    }
    public Student(String id, String name, String email, int age) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.age = age;
    }
    public String toString() {
        String studentInfo = "Student " + id;
        studentInfo += ": " + name;
        studentInfo += " - " + email;
        studentInfo += " - " + age;
        return studentInfo;
    }
    public boolean equals(Object obj) {
        if (obj instanceof Student) {
            Student another = (Student) obj;
            if (this.id.equals(another.id)) {
                return true;
            }
        }
        return false;
    }
}

Ở đây, phương thức equals() này chỉ so sánh thuộc tính ID của hai đối tượng Student.

Chúng ta sẽ coi mỗi đối tượng Student có một ID duy nhất, và xem hai đối tượng sinh viên là bằng nhau nếu chúng có ID giống nhau.

Phương thức contains(Object) của interface List trong java có thể được sử dụng để kiểm tra nếu đối tượng được chỉ định tồn tại trong danh sách. Về bản chất, phương thức equal() được gọi bên trong phương thức contains(Object).

package vn.viettuts;
import java.util.ArrayList;
import java.util.List;
public class EqualStudent2 {
    public static void main(String[] args) {
        Student student1 = new Student("123", "Cong", "cong@gmail.com", 22);
        Student student2 = new Student("123", "Cong", "cong@gmail.com", 22);
        Student student3 = new Student("456", "Dung", "dung@gmail.com", 18);
        // tạo danh sách student
        List<Student> listStudents = new ArrayList<>();
        // thêm các đối tượng student vào listStudents
        listStudents.add(student1);
        listStudents.add(student2);
        listStudents.add(student3);
        
        // tạo các đối tượng student chỉ có thuộc tính ID
        Student searchStudent1 = new Student("123");
        Student searchStudent4 = new Student("789");
         
        // tìm kiếm student trong danh sách
        System.out.println("Search student1: "
                + listStudents.contains(searchStudent1));
        System.out.println("Search student4: "
                + listStudents.contains(searchStudent4));
    }
}

Kết quả:

Search student1: true
Search student4: false

Phương thức hashCode() trong Java

Định nghĩa phương thức hashCode() trong lớp Object:

Bạn có thể thấy phương thức này trả về một số nguyên. Vậy nó được sử dụng ở đâu?

Đây là bí mật:

Số băm này được sử dụng bởi các collection dựa trên bảng băm như Hashtable , HashSet và HashMap để lưu trữ các đối tượng trong các container nhỏ được gọi là “nhóm”. Mỗi nhóm được liên kết với mã băm và mỗi nhóm chỉ chứa các đối tượng có mã băm giống hệt nhau.

Nói cách khác, một bảng băm nhóm các phần tử của nó bằng các giá trị mã băm của chúng. Sự sắp xếp này giúp cho bảng băm định vị một phần tử một cách nhanh chóng và hiệu quả bằng cách tìm kiếm trên các phần nhỏ của collection thay vì toàn bộ collection.

Dưới đây là các bước để định vị một phần tử trong một bảng băm:

  • Nhận giá trị mã băm của phần tử được chỉ định bằng cách gọi phương thức hashCode().
  • Tìm nhóm thích hợp được liên kết với mã băm đó.
  • Bên trong nhóm, tìm phần tử chính xác bằng cách so sánh phần tử được chỉ định với tất cả các phần tử trong nhóm. Bằng phương thức equals() của phần tử đã chỉ định được gọi.

Có nói rằng, khi chúng ta thêm các đối tượng của một lớp vào một collection dựa trên bảng băm (HashSet, HashMap ), phương thức hashCode() của lớp được gọi để tạo ra một số nguyên (có thể là một giá trị tùy ý). Con số này được sử dụng bởi bộ sưu tập để lưu trữ và định vị các đối tượng một cách nhanh chóng và hiệu quả, vì collection dựa trên bảng băm không duy trì thứ tự các phần tử của nó.

LƯU Ý: Việc thực thi phương thức mặc định hashCode() trong lớp Object trả về một số nguyên là địa chỉ bộ nhớ của đối tượng. Bạn nên ghi đè phương thức trong các lớp của bạn. Hầu hết các lớp trong JDK ghi đè phương thức hashCode() của riêng chúng, chẳng hạn như String , Date , Integer , Double , v.v.

Các quy tắc cho phương thức equals() và hashCode() trong Java

Như đã giải thích ở trên, collection dựa trên bảng băm xác định một phần tử bằng cách gọi phương thức hashCode() và equals() của nó, vì vậy khi ghi đè các phương thức này chúng ta phải tuân theo các quy tắc sau:

  • Khi phương thức equals() được ghi đè, phương thức hashCode() cũng phải được ghi đè.
  • Nếu hai đối tượng bằng nhau, mã băm của chúng phải bằng nhau.
  • Nếu hai đối tượng không bằng nhau, không có ràng buộc về mã băm của chúng (mã băm của chúng có thể bằng nhau hay không).
  • Nếu hai đối tượng có mã băm giống nhau, thì không có ràng buộc nào về sự bình nhau của chúng (chúng có thể bằng nhau hay không).
  • Nếu hai đối tượng có mã băm khác nhau, chúng không được bằng nhau.

Nếu chúng ta vi phạm các quy tắc này, các collection sẽ hoạt động có thể không đúng như các đối tượng không thể tìm thấy, hoặc các đối tượng sai được trả về thay vì các đối tượng chính xác.

Ví dụ ghi đề phương thức equals(), không ghi đè hashCode()

Hãy xem phương thức hashCode() và equals() ảnh hưởng như thế nào đến hành vi của một đối tượng Set.

Xem thêm:   sự khác nhau giữa include và extend trong UML

Lớp Student.java

package vn.viettuts;
public class Student {
    private String id;
    private String name;
    private String email;
    private int age;
    public Student(String id) {
        this.id = id;
    }
    public Student(String id, String name, String email, int age) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.age = age;
    }
    public String toString() {
        String studentInfo = "Student " + id;
        studentInfo += ": " + name;
        studentInfo += " - " + email;
        studentInfo += " - " + age;
        return studentInfo;
    }
    public boolean equals(Object obj) {
        if (obj instanceof Student) {
            Student another = (Student) obj;
            if (this.id.equals(another.id)) {
                return true;
            }
        }
        return false;
    }
}

Lớp EqualStudent3 .java

package vn.viettuts;
import java.util.HashSet;
import java.util.Set;
public class EqualStudent3 {
    public static void main(String[] args) {
        Student student1 = new Student("123", "Cong", "cong@gmail.com", 22);
        Student student2 = new Student("123", "Cong", "cong@gmail.com", 22);
        Student student3 = new Student("456", "Dung", "dung@gmail.com", 18);
        Set<Student> setStudents = new HashSet<Student>();
        setStudents.add(student1);
        setStudents.add(student2);
        setStudents.add(student3);
        // in các phần tử của set ra màn hình
        for (Student student : setStudents) {
            System.out.println(student);
        }
    }
}

Kết quả:

Student 456: Dung - dung@gmail.com - 18
Student 123: Cong - cong@gmail.com - 22
Student 123: Cong - cong@gmail.com - 22

Hãy nhìn xem, bạn có nhận thấy rằng có 2 sinh viên trùng lặp (ID: 123), phải không?

Đây là lý do:

Tập Set gọi các phương thức equals() và hashCode() trên mỗi đối tượng được thêm vào để đảm bảo không có sự trùng lặp. Trong trường hợp của chúng ta, lớp Student chỉ ghi đè phương thức equals(). Và phương thức hashCode() thừa kế từ lớp Object trả về các địa chỉ bộ nhớ của mỗi đối tượng không nhất quán với phương thức equals(). Do đó, đối tượng Set xử lý đối tượng student1 và student2 thành hai phần tử khác nhau.

Bây giờ, chúng ta hãy ghi đè phương thức hashCode() trong lớp Student như sau:

public int hashCode() {
    return 31 + id.hashCode();
}

Kết quả:

Student 123: Cong - cong@gmail.com - 22
Student 456: Dung - dung@gmail.com - 18

Good! Phần tử trùng lặp hiện đã bị xóa. Đó chính là điều chúng tôi muốn.

Với các phương thức equals() và hashCode() được ghi đè đúng cách, chúng ta cũng có thể thực hiện tìm kiếm trên tập hợp như sau:

Student searchStudent = new Student("456");
boolean found = setStudents.contains(searchStudent);
System.out.println("Search student: " + found);

Kết quả:

Search student: true

Để tự mình thử nghiệm nhiều hơn, hãy thử loại bỏ phương thức equals() hoặc hashCode() và quan sát kết quả.

Hy vọng bài này giúp bạn hiểu cách sử dụng các phương thức equals() và hashCode(). Và áp dụng chúng cho các collection.

 

Hãy chia sẻ cho mọi người nếu thấy thú vị nhé!

NẾU BẠN THÍCH TRỒNG CÂY, TÌM HIỀU CÂY THUỐC, CÂY ĂN QUẢ, CÂY CẢNH, CÂY RAU, CÂY GỖ... HÃY XEM NGAY Blogcaycoi.com

Link tải tài liệu Học Tiếng Trung Hoa

Tên Tài Liệu Link tải về
BEST Kho TIẾNG TRUNG SIÊU KHỦNG (sưu tầm từ nhiều nguồn) Link nhanh - nhấn để tải (gồm giáo trình, audio, ebook...)
HOT Khóa học Tiếng Trung sơ cấp (đầy đủ phần 1 và phần 2) Link nhanh - nhấn để tải (link fshare tải nhanh)
HOT Tiếng Trung ứng dụng thực hành cấp tốc (3 Mức độ: Sơ cấp, Trung cấp, Cao cấp) Link nhanh - nhấn để tải (link fshare tải nhanh)
HOT Kho nhạc Trung Hoa Link nhanh - nhấn để tải
1 30 bài khẩu ngữ Link nhanh - nhấn để tải
2 300 câu giao tiếp Việt Trung Link nhanh - nhấn để tải
3 1000 câu khẩu ngữ Link nhanh - nhấn để tải
4 3000 câu đàm thoại hàng ngày Link nhanh - nhấn để tải
5 3000 câu giao tiếp hàng ngày Link nhanh - nhấn để tải
6 Bài giảng và bài tập dịch Việt Trung Link nhanh - nhấn để tải
7 Đề thi chứng chỉ A, B Link nhanh - nhấn để tải
8 Đề thi thử HSK 2010 Link nhanh - nhấn để tải
9 Fun with Chinese character Full 3, 2, 1 Link nhanh - nhấn để tải (pass giải nén là: zhoyi.net)
10 Giáo trình BOYA trọn bộ (NEW) Link nhanh - nhấn để tải
11 Giáo trình con đường LU Link nhanh - nhấn để tải
12 Giáo trình đọc hiểu Hán ngữ Link nhanh - nhấn để tải
13 Giáo trình Hán ngữ 6 quyển (mới) Link nhanh - nhấn để tải
14 Giáo trình Hán ngữ Newstep Link nhanh - nhấn để tải
15 Giáo trình khẩu ngữ Link nhanh - nhấn để tải
16 Giáo trình luyện nói cấp tốc Link nhanh - nhấn để tải
17 Giáo trình nghe nói Hán ngữ trung cấp Link nhanh - nhấn để tải
18 Giáo trình nghe Link nhanh - nhấn để tải
19 HSK tổng hợp Link nhanh - nhấn để tải
20 Người Đài loan học tiếng Việt Link nhanh - nhấn để tải
21 Nhìn tranh kể chuyện Link nhanh - nhấn để tải
22 Phồn thể Link nhanh - nhấn để tải
23 Sổ tay từ mới tiếng Trung Link nhanh - nhấn để tải
24 Tài liệu HSK level 1, 2, 3 Link nhanh - nhấn để tải
25 Tài liệu tiếng Trung tổng hợp Link nhanh - nhấn để tải
26 Thi lái xe máy Taiwan Link nhanh - nhấn để tải
27 Tiếng Hoa thương mại (bài giảng + bài tập) Link nhanh - nhấn để tải
28 Từ phản nghĩa Link nhanh - nhấn để tải
29 21 ngày chinh phục HSK cấp 6 Link nhanh - nhấn để tải
30 21 ngày chinh phục ngữ pháp HSK cao cấp Link nhanh - nhấn để tải
31 30 ngày bức phá HSK Link nhanh - nhấn để tải
32 30 ngày học tiếng Hoa – Trung cấp Link nhanh - nhấn để tải
33 500 chủ đề tiếng Anh – Trung Link nhanh - nhấn để tải
34 900 câu tiếng Việt – Trung Link nhanh - nhấn để tải
35 1500 Hanzi – GianThePinYin – A0 Link nhanh - nhấn để tải
36 1501 Hanzi – PhonThePinYin ZhuYin – A0 Link nhanh - nhấn để tải
37 1000 câu tiếng Anh – Trung thông dụng Link nhanh - nhấn để tải
38 Bảng qui tắc chữ chuẩn và đối chiếu Phon-gian Link nhanh - nhấn để tải
39 Cấu trúc câu Link nhanh - nhấn để tải
40 Chinese Mandarin Vocabulary AC Link nhanh - nhấn để tải
41 Chinh phục ngữ pháp HSK Link nhanh - nhấn để tải
42 Dịch văn bản Trung quốc từ hình ảnh Link nhanh - nhấn để tải
43 Giải thích cách dùng từ trong thi HSK Link nhanh - nhấn để tải
44 Giáo trình đọc báo Hán ngữ – Sơ cấp Link nhanh - nhấn để tải
45 Giáo trình học tiếng Trung Link nhanh - nhấn để tải
46 Giáo trình tiếng Việt – Trung Link nhanh - nhấn để tải
47 Hướng dẫn ôn tập ngữ pháp HSK Link nhanh - nhấn để tải
48 Liên từ trong HSK Link nhanh - nhấn để tải
49 Mandarin grammar chart Link nhanh - nhấn để tải
50 Mẫu câu dịch Việt – Hoa Link nhanh - nhấn để tải
51 Ngữ pháp tiếng Trung Link nhanh - nhấn để tải
52 Ôn luyện từ vựng HSK Link nhanh - nhấn để tải
53 Phó từ trong HSK Link nhanh - nhấn để tải
54 Tiếng Anh trong văn phòng – Trung Anh Link nhanh - nhấn để tải
55 Toàn thư tự học chữ Hán Link nhanh - nhấn để tải
56 Từ điển Trung quốc bằng hình ảnh Link nhanh - nhấn để tải
57 Từ đồng nghĩa, phản nghĩa Hoa Việt Link nhanh - nhấn để tải
58 Từ này thì ra nghĩa là như này Link nhanh - nhấn để tải
59 Từ vựng chuyên ngành xây dựng Link nhanh - nhấn để tải
60 Vượt qua ngữ pháp HSK Link nhanh - nhấn để tải
61 Cấu trúc câu JPG to PDF Link nhanh - nhấn để tải
62 Xiandai Hanyu Gaoji Jiaocheng Link nhanh - nhấn để tải

Trả lời