JavaRush /จาวาบล็อก /Random-TH /คอฟฟี่เบรค #168. เหตุใดจึงแทนที่วิธีเท่ากับและ hashcode ใ...

คอฟฟี่เบรค #168. เหตุใดจึงแทนที่วิธีเท่ากับและ hashcode ใน Java

เผยแพร่ในกลุ่ม

เหตุใดจึงแทนที่วิธีเท่ากับและ hashcode ใน Java

ที่มา: Medium บทความนี้เน้นที่วิธีที่เกี่ยวข้องกันสองวิธี: เท่ากับ()และhashcode() คุณจะได้เรียนรู้วิธีที่พวกเขาโต้ตอบกัน และวิธีแทนที่พวกเขาอย่างถูกต้อง คอฟฟี่เบรค #168.  เหตุใดจึงแทนที่วิธีเท่ากับและ hashcode ใน Java  - 1

เหตุใดเราจึงแทนที่วิธีเท่ากับ ()

ใน Java เราไม่สามารถโอเวอร์โหลดพฤติกรรมของตัวดำเนินการเช่น== , += , - + พวกเขาทำงานตามกระบวนการที่กำหนด ตัวอย่างเช่น พิจารณาการทำงานของ ตัวดำเนิน การ ==

ตัวดำเนินการ == ทำงานอย่างไร

จะตรวจสอบว่าการอ้างอิงทั้งสองที่ถูกเปรียบเทียบชี้ไปที่อินสแตนซ์เดียวกันในหน่วยความจำหรือไม่ ตัวดำเนินการ==จะประเมินเป็นจริงก็ต่อเมื่อการอ้างอิงทั้งสองแสดงถึงอินสแตนซ์เดียวกันในหน่วยความจำ ลองมาดูโค้ดตัวอย่าง:
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
      }
สมมติว่าในโปรแกรมของคุณคุณได้สร้าง วัตถุบุคคล สองตัว ในตำแหน่งที่แตกต่างกันและต้องการเปรียบเทียบวัตถุเหล่านั้น
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println( person1 == person2 ); --> will print false!
จากมุมมองทางธุรกิจทั้งสองมีลักษณะเหมือนกันใช่ไหม? แต่สำหรับ JVM พวกเขาไม่เหมือนกัน เนื่องจากทั้งคู่ถูกสร้างขึ้นโดยใช้ คีย์เวิร์ด ใหม่ อินสแตน ซ์เหล่านี้จึงอยู่ในเซ็กเมนต์หน่วยความจำที่แตกต่างกัน ดังนั้น ตัวดำเนินการ ==จะคืนค่าfalse แต่ถ้าเราไม่สามารถแทนที่ ตัวดำเนินการ == ได้แล้วเราจะบอก JVM ได้อย่างไรว่าเราต้องการให้วัตถุทั้งสองนี้ได้รับการปฏิบัติเหมือนกัน นี่คือที่ มาของวิธีการ. equals() คุณสามารถแทนที่เท่ากับ()เพื่อตรวจสอบว่าวัตถุบางตัวมีค่าเหมือนกันสำหรับบางฟิลด์เพื่อพิจารณาว่าเท่ากันหรือไม่ คุณสามารถเลือกเขตข้อมูลที่จะเปรียบเทียบได้ หากเราบอกว่า วัตถุ บุคคล สองคน จะเหมือนกันก็ต่อเมื่อพวกเขามีอายุเท่ากันและมีชื่อเหมือนกัน IDE จะสร้างสิ่ง นี้เพื่อสร้างโดยอัตโนมัติ เท่ากับ() :
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
กลับไปที่ตัวอย่างก่อนหน้านี้ของเรา
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println ( person1 == person2 ); --> will print false!
System.out.println ( person1.equals(person2) ); --> will print true!
ใช่ เราไม่สามารถโอเวอร์โหลด ตัวดำเนินการ ==เพื่อเปรียบเทียบวัตถุในแบบที่เราต้องการได้ แต่ Java ให้วิธีอื่นแก่เรา - วิธีเท่ากับ ()ซึ่งเราสามารถแทนที่ได้ตามที่เราต้องการ โปรดทราบว่าหากเราไม่ได้จัดเตรียม.equals() เวอร์ชันที่กำหนดเอง (หรือที่เรียกว่าการแทนที่) ในคลาสของเรา ดังนั้น . equals() ที่กำหนดไว้ล่วงหน้า จาก คลาส Objectและ ตัวดำเนินการ ==จะทำงานเหมือนกัน วิธีการ เท่ากับ () เริ่มต้นซึ่งสืบทอดมาจากObjectจะตรวจสอบว่าทั้งสองอินสแตนซ์ที่ถูกเปรียบเทียบนั้นเหมือนกันในหน่วยความจำหรือไม่!

เหตุใดเราจึงเอาชนะวิธี hashCode()

โครงสร้างข้อมูลบางอย่างใน Java เช่นHashSetและHashMapจัดเก็บองค์ประกอบตามฟังก์ชันแฮชที่ใช้กับองค์ประกอบเหล่านั้น ฟังก์ชันแฮชคือhashCode( ) หากเรามีตัวเลือกในการเอาชนะเมธอด .equals()เราก็ควรมีตัวเลือกในการเอาชนะเมธอด hashCode() ด้วย มีเหตุผลสำหรับเรื่องนี้ ท้ายที่สุด การใช้งานเริ่มต้นของ hashCode()ซึ่งสืบทอดมาจากObjectจะถือว่าวัตถุทั้งหมดในหน่วยความจำไม่ซ้ำกัน! แต่กลับไปที่โครงสร้างข้อมูลแฮชเหล่านี้กันดีกว่า มีกฎสำหรับโครงสร้างข้อมูลเหล่านี้ HashSetไม่สามารถมีค่าที่ซ้ำกันและHashMapไม่สามารถมีคีย์ที่ซ้ำกัน HashSetถูกนำไปใช้โดยใช้HashMapในลักษณะที่ ค่า HashSet แต่ละค่าจะ ถูกจัดเก็บเป็นคีย์ในHashMap HashMapทำงานอย่างไร HashMapเป็นอาร์เรย์ดั้งเดิมที่มีหลายส่วน แต่ละส่วนมีรายการที่เชื่อมโยง ( linkedList ) รายการที่เชื่อมโยงนี้เก็บกุญแจของเรา HashMapค้นหา linkedList ที่ถูกต้องสำหรับแต่ละคีย์โดยใช้ เมธอด hashCode()จากนั้นวนซ้ำองค์ประกอบทั้งหมดของlinkedList นั้น และใช้ เมธอด เท่ากับ ()กับแต่ละองค์ประกอบเหล่านั้นเพื่อตรวจสอบว่าองค์ประกอบนั้นมีอยู่ที่นั่นหรือไม่ ไม่อนุญาตให้ใช้คีย์ซ้ำกัน คอฟฟี่เบรค #168.  เหตุใดจึงแทนที่วิธีเท่ากับและ hashcode ใน Java  - 2เมื่อเราใส่บางสิ่งไว้ในHashMapคีย์จะถูกจัดเก็บไว้ในรายการที่เชื่อมโยงรายการใดรายการหนึ่งเหล่านี้ รายการลิงก์ใดที่คีย์นี้จะถูกจัดเก็บจะแสดงโดยผลลัพธ์ของ เมธอด hashCode()สำหรับคีย์นั้น นั่นคือหากkey1.hashCode()ผลลัพธ์เป็น 4 ดังนั้นkey1 นั้น จะถูกจัดเก็บไว้ในส่วนที่ 4 ของอาร์เรย์ในLinkedList ที่มีอยู่อยู่ที่ นั่น ตามค่าเริ่มต้น เมธอดhashCode()จะส่งกลับผลลัพธ์ที่แตกต่างกันสำหรับแต่ละอินสแตนซ์ หากเรามีค่าเริ่มต้นเท่ากับ()ที่ทำงานเหมือน==โดยถือว่าอินสแตนซ์ทั้งหมดในหน่วยความจำเป็นวัตถุที่แตกต่างกัน ก็จะไม่มีปัญหา ดังที่คุณอาจจำได้ ในตัวอย่างก่อนหน้านี้ เราได้กล่าวว่าเราต้องการให้ อินสแตนซ์ Personได้รับการพิจารณาเท่ากัน หากอายุและชื่อเท่ากัน
Person person1 = new Person("Mike", 34);
    Person person2 = new Person("Mike", 34);
    System.out.println ( person1.equals(person2) );  --> will print true!
ตอนนี้เรามาสร้างแผนที่เพื่อจัดเก็บอินสแตนซ์เหล่านี้เป็นคีย์โดยมีสตริงเฉพาะเป็นคู่ของค่า
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
ในคลาสPersonเราไม่ได้แทนที่เมธอดhashCodeแต่เรามีเมธอดเท่ากับที่ ถูกแทนที่ เนื่องจากhashCode เริ่มต้น ให้ผลลัพธ์ที่แตกต่างกันสำหรับอินสแตนซ์ Java ที่แตกต่างกันของ person1.hashCode()และperson2.hashCode()จึงมีโอกาสสูงที่จะได้รับผลลัพธ์ที่แตกต่างกัน แผนที่ของเราสามารถลงท้ายด้วยบุคคล ต่างๆ ในรายการลิงก์ที่แตกต่างกัน สิ่ง นี้คอฟฟี่เบรค #168.  เหตุใดจึงแทนที่วิธีเท่ากับและ hashcode ใน Java  - 3ขัดแย้งกับตรรกะของ HashMap ท้ายที่สุดHashMapไม่สามารถมีคีย์ที่เหมือนกันหลายคีย์ได้! ประเด็นก็คือค่าเริ่มต้นhashCode()ที่สืบทอดมาจาก คลาส Objectนั้นไม่เพียงพอ แม้ว่าเราจะแทนที่เมธอดเท่ากับ () ของ คลาสPersonแล้ว นั่นเป็นสาเหตุที่เราต้องแทนที่เมธอดhashCode()หลังจากที่เราแทนที่ เมธอด เท่ากับ ตอนนี้เรามาแก้ไขปัญหานี้กัน เราจำเป็นต้องแทนที่เมธอดhashCode() ของเรา เพื่อที่จะคำนึงถึงฟิลด์เดียวกันกับ เท่ากับ ( )นั่นคืออายุและชื่อ
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
@Override
public int hashCode() {
        int prime = 31;
        return prime*Objects.hash(name, age);
    }
ใน เมธอด hashCode()เราใช้ค่าธรรมดา (คุณสามารถใช้ค่าอื่นก็ได้) แต่แนะนำให้ใช้จำนวนเฉพาะเพื่อสร้างปัญหาให้น้อยลง ลองเก็บคีย์เหล่านี้ไว้ใน HashMap ของเรา อีกครั้ง:
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
person1.hashCode()และperson2.hashCode()จะเหมือนกัน สมมติว่าเป็น 0 HashMapจะไปที่เซ็กเมนต์ 0 และในนั้นLinkedListจะบันทึกperson1เป็นคีย์ที่มีค่า “1” ในกรณีที่สอง เมื่อHashMapไปที่บัคเก็ต 0 อีกครั้งเพื่อจัดเก็บคีย์person2ที่มีค่า "2" ก็จะเห็นว่ามีคีย์อื่นที่เท่ากับมีอยู่แล้วที่นั่น วิธีนี้จะเขียนทับคีย์ก่อนหน้า และ มีเพียง บุคคล สำคัญ 2 เท่านั้น ที่จะอยู่ ใน HashMap ของเรา นี่คือวิธีที่เราเรียนรู้วิธี การทำงานของกฎ HashMapซึ่งระบุว่าคุณไม่สามารถใช้คีย์ที่เหมือนกันหลายคีย์ได้! อย่างไรก็ตาม โปรดทราบว่าอินสแตนซ์ที่ไม่เท่ากันสามารถมีแฮชโค้ดเดียวกันได้ และอินสแตนซ์ที่เท่ากันจะต้องส่งคืนแฮชโค้ดเดียวกันคอฟฟี่เบรค #168.  เหตุใดจึงแทนที่วิธีเท่ากับและ hashcode ใน Java  - 4
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION