JavaRush /Blog Java /Random-VI /Làm việc với các phương thức hashCode() và Equals() trong...
Lenchik854
Mức độ
Chernihiv

Làm việc với các phương thức hashCode() và Equals() trong Java

Xuất bản trong nhóm
Trong bài đăng này, tôi sẽ phác thảo sự hiểu biết của tôi về các phương pháp hashCode()equals(). Tôi muốn nói về cách triển khai mặc định của chúng, cũng như cách ghi đè chúng một cách chính xác. Tôi cũng sẽ viết về việc triển khai các phương thức này bằng cách sử dụng các lớp trợ giúp của gói Apache Common. Làm việc với các phương thức hashCode() và Equals() trong Java - 1Nội dung của bài viết này:
  1. Sử dụng hashCode()equals().
  2. Ghi đè hành vi mặc định.
  3. Ghi đè hashCode()equals()sử dụng Apache Commons Lang.
  4. Một cái gì đó quan trọng cần nhớ.
  5. Đặc biệt chú ý khi sử dụng ORM.
Các phương thức hashCode()equals()được định nghĩa trong lớp Object, là lớp cha của các đối tượng java. Do đó, tất cả các đối tượng java đều kế thừa cách triển khai mặc định từ các phương thức này.

Sử dụng hashCode() và bằng()

Phương thức này hashCode()được sử dụng để lấy một số nguyên duy nhất cho một đối tượng nhất định. Khi một đối tượng cần được lưu trữ dưới dạng cấu trúc dữ liệu trong bảng băm (còn gọi là nhóm), số này được sử dụng để xác định vị trí của nó trong bảng đó. Theo mặc định, phương thức hashCode()của một đối tượng trả về số vị trí bộ nhớ nơi đối tượng được lưu trữ. Phương thức này equals(), như tên gọi của nó, được sử dụng để kiểm tra sự bằng nhau của hai đối tượng. Việc triển khai mặc định của phương pháp này chỉ đơn giản là kiểm tra các tham chiếu của hai đối tượng để xem chúng có tương đương hay không.

Ghi đè hành vi mặc định

Mọi thứ đều hoạt động tốt miễn là bạn không ghi đè bất kỳ phương thức nào trong số này trong các lớp của mình. Nhưng đôi khi các ứng dụng cần thay đổi hành vi mặc định của một số đối tượng. Hãy lấy một ví dụ trong đó bạn có một tệp Employee. Hãy viết cấu trúc tối thiểu có thể có của một lớp như vậy.
public class Employee
{
    private Integer id;
    private String firstname;
    private String lastName;
    private String department;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getFirstname() {
        return firstname;
    }
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getDepartment() {
        return department;
    }
    public void setDepartment(String department) {
        this.department = department;
    }
}
Lớp được mô tả ở trên Employeecó một số thuộc tính và phương thức truy cập cơ bản. Bây giờ hãy xem một tình huống đơn giản khi chúng ta cần so sánh hai đối tượng của lớp Employee.
public class EqualsTest {
    public static void main(String[] args) {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);
        //Печатает false в консоли
        System.out.println(e1.equals(e2));
    }
}
Không cần phải là người có khả năng thấu thị cũng có thể đoán được rằng phương pháp trên sẽ trả về “false”. Nhưng điều này có thực sự đúng không, vì hai đối tượng này giống nhau? Trong ứng dụng thời gian thực, phương thức phải trả về true. Để đạt được hành vi đúng, chúng ta cần ghi đè phương thức này equals(), như thực hiện bên dưới:
public boolean equals(Object o) {
        if(o == null)
        {
            return false;
        }
        if (o == this)
        {
           return true;
        }
        if (getClass() != o.getClass())
        {
            return false;
        }
        Employee e = (Employee) o;
        return (this.getId() == e.getId());
}
Thêm phương thức này vào lớp của bạn Employeevà kiểm tra tính tương đương sẽ trả về “true”. Tuy nhiên, chúng ta đã làm được mọi thứ chưa? Chưa. Hãy kiểm tra lớp đã sửa đổi của chúng ta theo một cách nữa.
import java.util.HashSet;
import java.util.Set;

public class EqualsTest
{
    public static void main(String[] args)
    {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);

        //Печатает 'true'
        System.out.println(e1.equals(e2));

        Set employees = new HashSet();
        employees.add(e1);
        employees.add(e2);
        //Печатает два an object
        System.out.println(employees);
    }
}
Lệnh System.out.println(employee)in hai đối tượng. Nếu cả hai đối tượng đều tương đương và Setchỉ chứa các đối tượng duy nhất thì HashSetchỉ có một phiên bản bên trong, tức là. cả hai đối tượng đều đề cập đến cùng một thể hiện của lớp Employee. Chúng ta đã bỏ lỡ điều gì? Chúng ta đã bỏ lỡ phương pháp quan trọng thứ hai hashCode(). Như tài liệu java nói, nếu bạn ghi đè phương thức này equals()thì bạn bắt buộc phải ghi đè phương thức đó hashCode(). Vì vậy, hãy thêm một phương thức khác vào lớp của chúng ta Employee.
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
 }
Chúng tôi đã thêm phương thức này một lần vào lớp của mình và chỉ một đối tượng sẽ được in và do đó, việc kiểm tra sự tương đương của e1 và e2 cho thấy đúng.

Ghi đè hashCode()equals()sử dụng Apache Commons Lang

Apache Commons cung cấp hai lớp trợ giúp tuyệt vời để gọi các phương thức hashCode()equals(). Dưới đây chúng ta thấy cách sử dụng:
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Employee
{
 private Integer id;
 private String firstname;
 private String lastName;
 private String department;
public Integer getId() {
    return id;
 }
 public void setId(Integer id) {
    this.id = id;
 }
 public String getFirstname() {
    return firstname;
 }
 public void setFirstname(String firstname) {
    this.firstname = firstname;
 }
 public String getLastName() {
    return lastName;
 }
 public void setLastName(String lastName) {
    this.lastName = lastName;
 }
 public String getDepartment() {
    return department;
 }
 public void setDepartment(String department) {
    this.department = department;
 }
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).
           toHashCode();
 }
@Override
 public boolean equals(Object o) {
    if (o == null)
       return false;
    if (o == this)
       return true;
    if (o.getClass() != getClass())
       return false;
    Employee e = (Employee) o;
       return new EqualsBuilder().
              append(getId(), e.getId()).
              isEquals();
    }
 }
Mặt khác, nếu bạn sử dụng một trong các trình soạn thảo mã, họ cũng có thể gọi ra một số cấu trúc đẹp cho bạn. Ví dụ: nếu trong Eclipse IDE bạn nhấp chuột phải vào lớp >> nguồn > Tạo mã băm() và bằng() ... nó sẽ tạo ra một triển khai rất hay cho bạn. Làm việc với các phương thức hashCode() và Equals() trong Java - 2Một cái gì đó quan trọng cần nhớ.
  1. Luôn sử dụng các thuộc tính đối tượng giống nhau để gọi cả hai và hashCode()equals(). Chỉ trong trường hợp của chúng tôi, chúng tôi đã sử dụng employee id.
  2. Phương thức equals()phải liên tục (nếu đối tượng không thay đổi, phương thức phải trả về cùng một giá trị).
  3. Bất cứ khi nào a.equals(b), thì a.hashCode()phải giống như b.hashCode().
  4. Nếu bạn ghi đè một phương thức, bạn phải ghi đè phương thức thứ hai.

Lưu ý đặc biệt khi sử dụng ORM

Nếu bạn đang xử lý ORM (ru.wikipedia.org/wiki/ORM), thì hãy luôn sử dụng getters và không bao giờ sử dụng tham chiếu trường hashCode(). equals()Điều này là do trong ORM, đôi khi các trường được tải bằng cách sử dụng tải chậm và không thể truy cập được cho đến khi getters của chúng được gọi. Ví dụ: trong lớp của chúng tôi Employee, chúng tôi sử dụng e1.id == e2.id. Hoàn toàn có khả năng các itrường d được tải bằng cách tải từng phần. Một trong các trường có thể là 0 hoặc null và chúng tôi sẽ có hành vi không chính xác. Tuy nhiên, nếu được sử dụng e1.getId() == e2.getId(), chúng tôi có thể chắc chắn ngay cả khi các trường được tải bằng cách tải chậm; gọi getter sẽ điền vào trường đầu tiên. Đó là tất cả những gì tôi biết về hashCode()and các phương thức equals(). Hy vọng điều này sẽ giúp được ai đó ở đâu đó. Chúc may mắn với các nghiên cứu của bạn!! ps Đây là nỗ lực dịch thuật đầu tiên của tôi. Tôi đã cố gắng truyền tải mọi thứ gần nhất có thể với những gì tác giả muốn nói. Nếu bạn có ý kiến ​​gì thì hãy viết vào phần bình luận nhé. Đừng phán xét khắt khe :-))) Bài viết gốc
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION