ในโพสต์นี้ ฉันจะสรุปความเข้าใจเกี่ยวกับวิธีการ
เนื้อหาของโพสต์นี้:
การเอาชนะ
Apache Commons มีคลาสตัวช่วยที่ยอดเยี่ยมสองคลาสสำหรับการเรียกวิธีการ
สิ่งที่สำคัญที่ต้องจำ
hashCode()
และ equals()
ฉันต้องการพูดคุยเกี่ยวกับการใช้งานเริ่มต้น รวมถึงวิธีการแทนที่อย่างถูกต้อง ฉันจะเขียนเกี่ยวกับการใช้วิธีการเหล่านี้โดยใช้คลาสตัวช่วยของแพ็คเกจ Apache Common - การใช้
hashCode()
และequals()
. - แทนที่พฤติกรรมเริ่มต้น
- การเอาชนะ
hashCode()
และequals()
การใช้ Apache Commons Lang - สิ่งที่สำคัญที่ต้องจำ
- ความสนใจเป็นพิเศษเมื่อใช้ 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()
และequals()
ในกรณีของเราเราใช้employee id
. - วิธีการ
equals()
จะต้องคงอยู่ (หากวัตถุไม่มีการเปลี่ยนแปลง วิธีการจะต้องส่งกลับค่าเดียวกัน) - เมื่อไหร่
a.equals(b)
ก็ตามนั้นจะa.hashCode()
ต้องเหมือนกับb.hashCode()
- หากคุณแทนที่วิธีหนึ่ง คุณต้องแทนที่วิธีที่สอง
ความสนใจเป็นพิเศษเมื่อใช้ 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()
หวังว่านี่จะช่วยใครซักคนได้ ขอให้โชคดีกับการเรียนนะ!! ป.ล. นี่เป็นความพยายามครั้งแรกของฉันในการแปล ฉันพยายามถ่ายทอดทุกสิ่งให้ใกล้เคียงกับสิ่งที่ผู้เขียนต้องการจะพูดมากที่สุด หากคุณมีความคิดเห็นใด ๆ โปรดเขียนในความคิดเห็น อย่าตัดสินอย่างเคร่งครัด :-))) บทความต้นฉบับ
GO TO FULL VERSION