JavaRush /จาวาบล็อก /Random-TH /การทำงานกับเมธอด hashCode() และเท่ากับ() ใน Java
Lenchik854
ระดับ
Chernihiv

การทำงานกับเมธอด hashCode() และเท่ากับ() ใน Java

เผยแพร่ในกลุ่ม
ในโพสต์นี้ ฉันจะสรุปความเข้าใจเกี่ยวกับวิธีการhashCode()และ equals()ฉันต้องการพูดคุยเกี่ยวกับการใช้งานเริ่มต้น รวมถึงวิธีการแทนที่อย่างถูกต้อง ฉันจะเขียนเกี่ยวกับการใช้วิธีการเหล่านี้โดยใช้คลาสตัวช่วยของแพ็คเกจ Apache Common การทำงานกับเมธอด hashCode() และเท่ากับ() ใน Java - 1เนื้อหาของโพสต์นี้:
  1. การใช้hashCode()และequals().
  2. แทนที่พฤติกรรมเริ่มต้น
  3. การเอาชนะhashCode()และequals()การใช้ Apache Commons Lang
  4. สิ่งที่สำคัญที่ต้องจำ
  5. ความสนใจเป็นพิเศษเมื่อใช้ ORM
hashCode()และเมธอดequals()ถูกกำหนดไว้ในคลาสObjectซึ่งเป็นคลาสพาเรนต์สำหรับอ็อบเจ็กต์ Java ดังนั้นวัตถุ Java ทั้งหมดสืบทอดการใช้งานเริ่มต้นจากวิธีการเหล่านี้

การใช้ hashCode() และเท่ากับ()

วิธีการนี้hashCode()ใช้เพื่อรับหมายเลขจำนวนเต็มเฉพาะสำหรับวัตถุที่กำหนด เมื่อจำเป็นต้องจัดเก็บออบเจ็กต์เป็นโครงสร้างข้อมูลในตารางแฮช (หรือที่เรียกว่าบัคเก็ต) หมายเลขนี้จะใช้เพื่อระบุตำแหน่งของวัตถุในตารางนั้น ตามค่าเริ่มต้น วิธีการhashCode()สำหรับวัตถุจะส่งกลับหมายเลขของตำแหน่งหน่วยความจำที่วัตถุถูกจัดเก็บ วิธีการequals()ตามชื่อของมันใช้เพื่อตรวจสอบความเท่าเทียมกันของวัตถุสองชิ้น การใช้งานเริ่มต้นของวิธีนี้เพียงตรวจสอบการอ้างอิงของสองวัตถุเพื่อดูว่าเทียบเท่ากันหรือไม่

การเอาชนะพฤติกรรมเริ่มต้น

ทุกอย่างทำงานได้ดีตราบใดที่คุณไม่แทนที่วิธีการเหล่านี้ในชั้นเรียนของคุณ แต่บางครั้งแอปพลิเคชันจำเป็นต้องเปลี่ยนพฤติกรรมเริ่มต้นของวัตถุบางอย่าง ลองมาตัวอย่างที่คุณมีEmployee. ลองเขียนโครงสร้างขั้นต่ำที่เป็นไปได้ของคลาสดังกล่าว
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;
    }
}
คลาสที่อธิบายไว้ข้างต้นEmployeeมีคุณสมบัติพื้นฐานและวิธีการเข้าถึง 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));
    }
}
ไม่จำเป็นต้องใช้ญาณทิพย์ในการเดาว่าวิธีการที่เขียนไว้ข้างต้นจะส่งกลับค่าเป็น "เท็จ" แต่นี่ถูกต้องจริงหรือไม่ เมื่อพิจารณาว่าวัตถุทั้งสองนี้เหมือนกัน? ในแอปพลิเคชันแบบเรียลไทม์ วิธีการจะต้องคืนค่าเป็นจริง เพื่อให้บรรลุพฤติกรรมที่ถูกต้อง เราจำเป็นต้องแทนที่วิธีการequals()ดังที่ทำด้านล่าง:
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());
}
เพิ่มวิธีนี้ในชั้นเรียนของคุณEmployeeและการตรวจสอบความเท่าเทียมกันจะส่งกลับเป็น "จริง" อย่างไรก็ตาม เราได้ทำทุกอย่างแล้วหรือยัง? ยัง. มาทดสอบคลาสที่ดัดแปลงของเราในอีกวิธีหนึ่ง
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);
    }
}
คำสั่งSystem.out.println(employee)จะพิมพ์วัตถุสองชิ้น หากวัตถุทั้งสองเทียบเท่ากัน และSetมีเพียงวัตถุที่ไม่ซ้ำกันเท่านั้นที่อยู่ภายใน ก็HashSetควรจะมีเพียงอินสแตนซ์เดียวภายใน นั่นคือ Employeeวัตถุทั้งสองอ้างถึงอินสแตนซ์ เดียวกันของคลาส เราพลาดอะไรไป? hashCode()เรา พลาดวิธีสำคัญที่สอง ตามที่เอกสาร Java กล่าวไว้ หากคุณแทนที่เมธอดequals()คุณจะต้องแทนที่เมธอดhashCode()นั้น ดังนั้นเรามาเพิ่มวิธีการอื่นให้กับชั้นเรียนของEmployeeเรา
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
 }
เราได้เพิ่มวิธีนี้หนึ่งครั้งในชั้นเรียนของเรา และจะมีการพิมพ์ออบเจ็กต์เพียงรายการเดียว ดังนั้นการตรวจสอบความเท่าเทียมกันของ e1 และ e2 จึงแสดงให้เห็นจริง

การเอาชนะhashCode()และequals()การใช้ Apache Commons Lang

Apache Commons มีคลาสตัวช่วยที่ยอดเยี่ยมสองคลาสสำหรับการเรียกวิธีการhashCode()และequals(). ด้านล่างเราเห็นการใช้งาน:
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();
    }
 }
ในทางกลับกัน หากคุณใช้โปรแกรมแก้ไขโค้ดตัวใดตัวหนึ่ง พวกเขาควรจะสามารถเรียกโครงสร้างที่ดีสำหรับคุณได้ ตัวอย่างเช่น หากใน Eclipse IDE คุณคลิกขวาที่คลาส >> แหล่งที่มา > กำลังสร้าง hashCode() และเท่ากับ() ...มันจะสร้างการใช้งานที่ดีมากสำหรับคุณ การทำงานกับเมธอด hashCode() และเท่ากับ() ใน Java - 2สิ่งที่สำคัญที่ต้องจำ
  1. ใช้แอตทริบิวต์ วัตถุเดียวกันเสมอเพื่อเรียกทั้ง และhashCode()และ equals()ในกรณีของเราเราใช้employee id.
  2. วิธีการequals()จะต้องคงอยู่ (หากวัตถุไม่มีการเปลี่ยนแปลง วิธีการจะต้องส่งกลับค่าเดียวกัน)
  3. เมื่อไหร่a.equals(b)ก็ตามนั้นจะa.hashCode()ต้องเหมือนกับb.hashCode()
  4. หากคุณแทนที่วิธีหนึ่ง คุณต้องแทนที่วิธีที่สอง

ความสนใจเป็นพิเศษเมื่อใช้ ORM

หากคุณกำลังจัดการกับ ORM (ru.wikipedia.org/wiki/ORM) ให้ใช้ getters เสมอและอย่าใช้การอ้างอิงhashCode()ฟิลด์ equals()เนื่องจากใน ORM ในบางครั้งฟิลด์จะถูกโหลดโดยใช้การโหลดแบบ Lazy Load และไม่สามารถเข้าถึงได้จนกว่าจะเรียก getters ตัวอย่างเช่น ในชั้นเรียนของเราEmployeeเราใช้e1.id == e2.id. เป็นไปได้ทั้งหมดว่าiฟิลด์ d ถูกโหลดโดยใช้การโหลดแบบ Lazy Loading ช่องใดช่องหนึ่งอาจเป็น 0 หรือ null และเราจะได้รับพฤติกรรมที่ไม่ถูกต้อง แต่หากใช้e1.getId() == e2.getId()เราจะมั่นใจได้แม้ว่าฟิลด์นั้นจะถูกโหลดโดยใช้การโหลดแบบ Lazy Loading ก็ตาม การเรียกทะเยอทะยานจะเติมข้อมูลในฟิลด์ก่อน นั่นคือทั้งหมดที่ ฉันรู้เกี่ยวกับ วิธีการ hashCode()และ equals()หวังว่านี่จะช่วยใครซักคนได้ ขอให้โชคดีกับการเรียนนะ!! ป.ล. นี่เป็นความพยายามครั้งแรกของฉันในการแปล ฉันพยายามถ่ายทอดทุกสิ่งให้ใกล้เคียงกับสิ่งที่ผู้เขียนต้องการจะพูดมากที่สุด หากคุณมีความคิดเห็นใด ๆ โปรดเขียนในความคิดเห็น อย่าตัดสินอย่างเคร่งครัด :-))) บทความต้นฉบับ
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION