JavaRush /จาวาบล็อก /Random-TH /เท่ากับและสัญญา hashCode หรืออะไรก็ตาม
Aleksandr Zimin
ระดับ
Санкт-Петербург

เท่ากับและสัญญา hashCode หรืออะไรก็ตาม

เผยแพร่ในกลุ่ม
แน่นอนว่าโปรแกรมเมอร์ Java ส่วนใหญ่รู้ว่าวิธีการต่างๆequalsมีhashCodeความเกี่ยวข้องกันอย่างใกล้ชิด และขอแนะนำให้แทนที่ทั้งสองวิธีในคลาสของตนอย่างสม่ำเสมอ จำนวนที่น้อยกว่าเล็กน้อยรู้ว่าเหตุใดจึงเป็นเช่นนั้น และผลที่ตามมาอันน่าเศร้าที่อาจเกิดขึ้นหากกฎนี้ละเมิด ฉันเสนอให้พิจารณาแนวคิดของวิธีการเหล่านี้ ทำซ้ำวัตถุประสงค์และทำความเข้าใจว่าทำไมจึงเชื่อมโยงกัน ฉันเขียนบทความนี้เช่นเดียวกับบทความก่อนหน้าเกี่ยวกับการโหลดคลาสเพื่อตัวฉันเองเพื่อที่จะเปิดเผยรายละเอียดทั้งหมดของปัญหาในที่สุดและจะไม่กลับไปยังแหล่งข้อมูลบุคคลที่สามอีกต่อไป ดังนั้นฉันยินดีที่จะวิจารณ์อย่างสร้างสรรค์เพราะหากมีช่องว่างที่ไหนสักแห่งก็ควรจะกำจัดออกไป อนิจจาบทความกลายเป็นเรื่องที่ค่อนข้างยาว

เท่ากับแทนที่กฎ

วิธีการequals()ที่จำเป็นใน Java เพื่อยืนยันหรือปฏิเสธความจริงที่ว่าสองวัตถุที่มีต้นกำเนิดเดียวกันมีความเท่าเทียมกันทางตรรกะ นั่นคือ เมื่อเปรียบเทียบวัตถุสองชิ้น โปรแกรมเมอร์จำเป็นต้องเข้าใจว่าสาขาที่มีนัยสำคัญ นั้นเทียบเท่ากันหรือ ไม่ ไม่จำเป็นว่าทุกฟิลด์จะต้องเหมือนกัน เนื่องจากวิธีการนี้แสดงequals()ถึงความเท่าเทียมกันทางตรรกะ แต่บางครั้งก็ไม่จำเป็นต้องใช้วิธีนี้เป็นพิเศษ อย่างที่พวกเขาพูดกันว่าวิธีที่ง่ายที่สุดในการหลีกเลี่ยงปัญหาโดยใช้กลไกเฉพาะคือการไม่ใช้มัน ควรสังเกตว่าเมื่อคุณผิดสัญญาequalsคุณจะสูญเสียการควบคุมในการทำความเข้าใจว่าวัตถุและโครงสร้างอื่นจะโต้ตอบกับวัตถุของคุณอย่างไร และการค้นหาสาเหตุของข้อผิดพลาดในภายหลังจะเป็นเรื่องยากมาก

เมื่อไม่แทนที่วิธีนี้

  • เมื่อแต่ละอินสแตนซ์ของคลาสไม่ซ้ำกัน
  • ในระดับที่มากขึ้น สิ่งนี้ใช้กับคลาสที่มีพฤติกรรมเฉพาะ แทนที่จะได้รับการออกแบบให้ทำงานกับข้อมูล เช่นเช่นในชั้นThreadเรียน สำหรับพวกเขาequalsการใช้วิธีการที่คลาสมีให้นั้นObjectก็เกินพอแล้ว อีกตัวอย่างหนึ่งคือคลาสแจงนับ ( Enum)
  • เมื่อในความเป็นจริงแล้ว คลาสไม่จำเป็นต้องกำหนดความเท่าเทียมกันของอินสแตนซ์
  • ตัวอย่างเช่น สำหรับคลาสหนึ่งๆjava.util.Randomไม่จำเป็นต้องเปรียบเทียบอินสแตนซ์ของคลาสด้วยกันเลย โดยพิจารณาว่าอินสแตนซ์เหล่านั้นสามารถส่งคืนตัวเลขสุ่มลำดับเดียวกันได้หรือไม่ เพียงเพราะธรรมชาติของชั้นเรียนนี้ไม่ได้หมายความถึงพฤติกรรมดังกล่าวด้วยซ้ำ
  • เมื่อคลาสที่คุณกำลังขยายมีการนำเมธอดไปใช้แล้วequalsและพฤติกรรมของการใช้งานนี้เหมาะสมกับคุณ
  • ตัวอย่างเช่น สำหรับคลาส, Setการใช้งานจะอยู่ในและตามลำดับ ListMapequalsAbstractSetAbstractListAbstractMap
  • และสุดท้าย ไม่จำเป็นต้องแทนที่equalsเมื่อขอบเขตของคลาสของคุณเป็นprivateหรือpackage-privateและคุณแน่ใจว่าเมธอดนี้จะไม่มีวันถูกเรียกใช้

เท่ากับสัญญา

เมื่อแทนที่เมธอดequalsนักพัฒนาจะต้องปฏิบัติตามกฎพื้นฐานที่กำหนดไว้ในข้อกำหนดภาษา Java
  • สะท้อนแสง
  • สำหรับค่าที่กำหนดใดๆxนิพจน์x.equals(x)จะต้องส่งtrueคืน
    ให้ - ความหมายเช่นนั้นx != null
  • สมมาตร
  • สำหรับค่าที่กำหนดใด ๆและxควรส่งคืนเฉพาะในกรณีที่ส่ง คืนyx.equals(y)truey.equals(x)true
  • การขนส่ง
  • สำหรับค่าที่กำหนดใดๆและ xหากyส่งคืนzและส่งคืนจะต้องส่งคืนค่านั้นx.equals(y)truey.equals(z)truex.equals(z)true
  • ความสม่ำเสมอ
  • สำหรับค่าที่กำหนดใดๆxและyการเรียกซ้ำx.equals(y)จะส่งกลับค่าของการเรียกครั้งก่อนเป็นเมธอดนี้ โดยมีเงื่อนไขว่าฟิลด์ที่ใช้ในการเปรียบเทียบทั้งสองอ็อบเจ็กต์ไม่เปลี่ยนแปลงระหว่างการโทร
  • การเปรียบเทียบเป็นโมฆะ
  • สำหรับมูลค่าที่กำหนดใด ๆxการโทรx.equals(null)จะต้องส่งfalseคืน

เท่ากับผิดสัญญา

คลาสจำนวนมาก เช่น คลาสจาก Java Collections Framework ขึ้นอยู่กับการใช้งานเมธอดequals()ดังนั้นคุณจึงไม่ควรละเลยเพราะ การละเมิดสัญญาของวิธีการนี้อาจนำไปสู่การดำเนินการที่ไม่มีเหตุผลของแอปพลิเคชันและในกรณีนี้การค้นหาสาเหตุจะค่อนข้างยาก ตามหลักการสะท้อนกลับวัตถุทุกชิ้นจะต้องมีค่าเท่ากันกับตัวมันเอง หากหลักการนี้ถูกละเมิด เมื่อเราเพิ่มวัตถุเข้าไปในคอลเลกชันแล้วค้นหาโดยใช้วิธีการcontains()เราจะไม่สามารถค้นหาวัตถุที่เราเพิ่งเพิ่มเข้าไปในคอลเลกชันได้ เงื่อนไขสมมาตรระบุว่าวัตถุสองชิ้นใดๆ จะต้องเท่ากันโดยไม่คำนึงถึงลำดับการเปรียบเทียบ equalsตัวอย่างเช่น หากคุณมีคลาสที่มีฟิลด์ประเภทสตริงเพียงฟิลด์เดียว การเปรียบเทียบ ฟิลด์นี้กับสตริงในเมธอดจะไม่ถูกต้อง เพราะ ในกรณีที่มีการเปรียบเทียบแบบย้อนกลับ เมธอดจะส่งกลับค่าfalseเสมอ
// Нарушение симметричности
public class SomeStringify {
    private String s;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof SomeStringify) {
            return s.equals(((SomeStringify) o).s);
        }
        // нарушение симметричности, классы разного происхождения
        if (o instanceof String) {
            return s.equals(o);
        }
        return false;
    }
}
//Правильное определение метода equals
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    return o instanceof SomeStringify &&
            ((SomeStringify) o).s.equals(s);
}
จากเงื่อนไขของการเปลี่ยนแปลงสภาพจะเป็นไปตามว่าหากวัตถุสองในสามชิ้นมีค่าเท่ากัน ในกรณีนี้ทั้งสามจะต้องเท่ากัน หลักการนี้สามารถถูกละเมิดได้ง่ายเมื่อจำเป็นต้องขยายคลาสฐานบางคลาสโดยการเพิ่มองค์ประกอบที่มีความหมาย ลงไป ตัวอย่างเช่น ในชั้นเรียนPointที่มีพิกัดxและyคุณต้องเพิ่มสีของจุดโดยการขยาย ในการดำเนินการ นี้คุณจะต้องประกาศคลาสColorPointที่มีฟิลด์ที่เกี่ยวข้อง colorดังนั้น หากในคลาสขยายเราเรียกเมธอดequalsparent และในคลาสพาเรนต์เราถือว่ามีเพียงพิกัดxและ ถูกเปรียบเทียบ yดังนั้นจุดสองจุดที่มีสีต่างกันแต่มีพิกัดเดียวกันจะถือว่าเท่ากัน ซึ่งไม่ถูกต้อง ในกรณีนี้ จำเป็นต้องสอนคลาสที่ได้รับให้แยกแยะสีต่างๆ เมื่อต้องการทำเช่นนี้ คุณสามารถใช้สองวิธี แต่ใครจะฝ่าฝืนกฎของสมมาตรและประการที่สองคือการ เปลี่ยนแปลง
// Первый способ, нарушая симметричность
// Метод переопределен в классе ColorPoint
@Override
public boolean equals(Object o) {
    if (!(o instanceof ColorPoint)) return false;
    return super.equals(o) && ((ColorPoint) o).color == color;
}
ในกรณีนี้ การเรียกpoint.equals(colorPoint)จะส่งคืนค่าtrueและการเปรียบเทียบcolorPoint.equals(point)จะส่งคืนfalseเนื่องจาก คาดหวังวัตถุของคลาส "มัน" กฎแห่งความสมมาตรจึงถูกละเมิด วิธีที่สองเกี่ยวข้องกับการทำการตรวจสอบแบบ "ตาบอด" ในกรณีที่ไม่มีข้อมูลเกี่ยวกับสีของจุด เช่น เรามีPointคลาส ColorPointหรือตรวจสอบสีหากมี ข้อมูล เกี่ยวกับสีนั้น นั่นคือ เปรียบเทียบวัตถุของคลาส
// Метод переопределен в классе ColorPoint
@Override
public boolean equals(Object o) {
    if (!(o instanceof Point)) return false;

    // Слепая проверка
    if (!(o instanceof ColorPoint))
        return super.equals(o);

    // Полная проверка, включая цвет точки
    return super.equals(o) && ((ColorPoint) o).color == color;
}
หลักการของการขนส่งถูกละเมิดที่นี่ดังนี้ สมมติว่ามีคำจำกัดความของวัตถุต่อไปนี้:
ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
ดังนั้นแม้ว่าจะมีความเท่าเทียมกันและp1.equals(p2)พอใจp2.equals(p3)แต่p1.equals(p3)ก็จะส่งกลับค่า falseในขณะเดียวกันวิธีที่สองในความคิดของฉันดูน่าดึงดูดน้อยกว่าเพราะ ในบางกรณี อัลกอริธึมอาจมองไม่เห็นและทำการเปรียบเทียบได้ไม่เต็มที่ และคุณอาจไม่ทราบเรื่องนี้ บทกวีเล็กน้อย โดยทั่วไปแล้ว ตามที่ฉันเข้าใจ ไม่มีวิธีแก้ปัญหาที่เป็นรูปธรรมสำหรับปัญหานี้ มีความคิดเห็นจากผู้เขียนที่เชื่อถือได้คนหนึ่งชื่อ Kay Horstmann ที่คุณสามารถแทนที่การใช้ตัวดำเนินการinstanceofด้วยการเรียกเมธอดgetClass()ที่ส่งคืนคลาสของอ็อบเจ็กต์ และก่อนที่คุณจะเริ่มเปรียบเทียบอ็อบเจ็กต์ด้วยตนเอง ตรวจสอบให้แน่ใจว่าอ็อบเจ็กต์นั้นเป็นประเภทเดียวกัน และอย่าไปใส่ใจกับข้อเท็จจริงของต้นกำเนิดร่วมกัน ดังนั้นกฎของสมมาตรและการเปลี่ยนผ่านจะเป็นที่พอใจ แต่ในเวลาเดียวกัน Joshua Bloch นักเขียนอีกคนหนึ่งยืนอยู่อีกด้านหนึ่งของสิ่งกีดขวางซึ่งเชื่อว่าแนวทางนี้ละเมิดหลักการทดแทนของ Barbara Liskov หลักการนี้ระบุว่า“การเรียกโค้ดต้องปฏิบัติต่อคลาสฐานในลักษณะเดียวกับคลาสย่อยโดยไม่รู้ตัว ” และในแนวทางแก้ไขที่เสนอโดย Horstmann หลักการนี้ถูกละเมิดอย่างชัดเจน เนื่องจากขึ้นอยู่กับการนำไปปฏิบัติ สรุปชัดเจนว่าเรื่องนี้มืดมน ควรสังเกตว่า Horstmann ชี้แจงกฎสำหรับการใช้วิธีการของเขาและเขียนเป็นภาษาอังกฤษธรรมดาว่าคุณต้องตัดสินใจเกี่ยวกับกลยุทธ์เมื่อออกแบบคลาสและหากการทดสอบความเท่าเทียมกันจะดำเนินการโดยซูเปอร์คลาสเท่านั้น คุณสามารถทำได้โดยดำเนินการ การดำเนินinstanceofการ มิฉะนั้น เมื่อซีแมนทิกส์ของการตรวจสอบเปลี่ยนแปลงไปขึ้นอยู่กับคลาสที่ได้รับและการใช้งานเมธอดจำเป็นต้องย้ายลงตามลำดับชั้น คุณต้องใช้getClass()เมธอด ในทางกลับกัน Joshua Bloch เสนอที่จะละทิ้งมรดกและใช้องค์ประกอบของวัตถุโดยรวมColorPointคลาส ในคลาส Pointและจัดเตรียมวิธีการเข้าถึงasPoint()เพื่อรับข้อมูลเฉพาะเกี่ยวกับประเด็นนั้น วิธีนี้จะหลีกเลี่ยงการฝ่าฝืนกฎทั้งหมด แต่ในความคิดของฉัน มันจะทำให้โค้ดเข้าใจยากขึ้น ตัวเลือกที่สามคือการใช้การสร้างวิธีเท่ากับโดยอัตโนมัติโดยใช้ IDE อย่างไรก็ตาม Idea จะสร้างรุ่น Horstmann ขึ้นมาใหม่ ทำให้คุณสามารถเลือกกลยุทธ์สำหรับการนำวิธีการไปประยุกต์ใช้ในซูเปอร์คลาสหรือในรุ่นต่อๆ ไป ในที่สุด กฎ ความสอดคล้อง ถัดไป ระบุว่า แม้ว่าวัตถุ จะ xไม่yเปลี่ยนแปลง การเรียกวัตถุเหล่านั้นอีกครั้งx.equals(y)จะต้องส่งกลับค่าเดิมเหมือนเมื่อก่อน กฎข้อสุดท้ายคือไม่มีวัตถุใดควรจะnullเท่ากับ ทุกอย่างชัดเจนที่นี่null- นี่คือความไม่แน่นอน วัตถุเท่ากับความไม่แน่นอนหรือไม่? มันไม่ชัดเจนนั่นคือfalse.

อัลกอริธึมทั่วไปสำหรับการกำหนดความเท่าเทียมกัน

  1. ตรวจสอบความเท่าเทียมกันของการอ้างอิงวัตถุthisและพารามิเตอร์วิธีoการ
    if (this == o) return true;
  2. ตรวจสอบว่าลิงก์ถูกกำหนดไว้oหรือไม่ เช่น ไม่ว่าจะnullเป็น
    หากในอนาคต เมื่อเปรียบเทียบประเภทออบเจ็กต์ จะใช้ตัวดำเนินการinstanceofรายการนี้ก็สามารถข้ามได้ เนื่องจากพารามิเตอร์นี้จะส่งกลับในfalseกรณีนี้null instanceof Object
  3. เปรียบเทียบประเภทวัตถุthisโดยใช้oตัวดำเนินการinstanceofหรือวิธีการgetClass()ตามคำอธิบายข้างต้นและสัญชาตญาณของคุณเอง
  4. ถ้าเมธอดequalsถูกแทนที่ในคลาสย่อย อย่าลืมทำการโทรsuper.equals(o)
  5. แปลงประเภทพารามิเตอร์oเป็นคลาสที่ต้องการ
  6. ทำการเปรียบเทียบฟิลด์ออบเจ็กต์ที่มีนัยสำคัญทั้งหมด:
    • สำหรับประเภทดั้งเดิม (ยกเว้นfloatและdouble) โดยใช้ตัวดำเนินการ==
    • สำหรับฟิลด์อ้างอิง คุณต้องเรียกใช้เมธอดของมันequals
    • สำหรับอาร์เรย์ คุณสามารถใช้การวนซ้ำหรือวิธีการได้Arrays.equals()
    • สำหรับประเภทfloatและdoubleจำเป็นต้องใช้วิธีการเปรียบเทียบของคลาส wrapper ที่เกี่ยวข้องFloat.compare()และDouble.compare()
  7. และสุดท้าย ตอบคำถามสามข้อ: วิธีการนำไปใช้มีความสมมาตรหรือไม่ สกรรมกริยา ? ตกลงไหม? อีกสองหลักการ ( การสะท้อนกลับและความแน่นอน ) มักจะดำเนินการโดยอัตโนมัติ

กฎการแทนที่ HashCode

แฮชคือตัวเลขที่สร้างขึ้นจากออบเจ็กต์ที่อธิบายสถานะ ณ จุดใดจุดหนึ่ง หมายเลขนี้ใช้ใน Java เป็นหลักในตารางแฮช เช่นHashMap. ในกรณีนี้ ต้องใช้ฟังก์ชันแฮชในการรับตัวเลขตามออบเจ็กต์เพื่อให้แน่ใจว่ามีการกระจายองค์ประกอบในตารางแฮชค่อนข้างสม่ำเสมอ และเพื่อลดโอกาสที่จะเกิดการชนกันเมื่อฟังก์ชันส่งคืนค่าเดียวกันสำหรับคีย์ที่ต่างกัน

แฮชโค้ดของสัญญา

หากต้องการใช้ฟังก์ชันแฮช ข้อกำหนดภาษาจะกำหนดกฎต่อไปนี้:
  • การเรียกเมธอดhashCodeหนึ่งครั้งขึ้นไปบนออบเจ็กต์เดียวกันจะต้องส่งคืนค่าแฮชเดียวกัน โดยมีเงื่อนไขว่าฟิลด์ของออบเจ็กต์ที่เกี่ยวข้องกับการคำนวณค่าไม่เปลี่ยนแปลง
  • การเรียกเมธอดhashCodeบนอ็อบเจ็กต์ทั้งสองควรส่งคืนหมายเลขเดียวกันเสมอหากอ็อบเจ็กต์มีค่าเท่ากัน (การเรียกเมธอดequalsบนอ็อบเจ็กต์เหล่านี้จะส่งกลับtrue)
  • การเรียกเมธอดhashCodeบนอ็อบเจ็กต์ที่ไม่เท่ากันสองตัวจะต้องส่งคืนค่าแฮชที่แตกต่างกัน แม้ว่าข้อกำหนดนี้จะไม่ได้บังคับ แต่ก็ควรพิจารณาว่าการใช้งานจะมีผลเชิงบวกต่อประสิทธิภาพของตารางแฮช

วิธีการเท่ากับและ hashCode จะต้องถูกแทนที่ร่วมกัน

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

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

    Map<Point, String> m = new HashMap<>();
    m.put(new Point(1, 1),Point A);
    // pointName == null
    String pointName = m.get(new Point(1, 1));

    แน่นอนว่าวัตถุที่ถูกวางและวัตถุที่กำลังค้นหานั้นเป็นวัตถุสองชิ้นที่แตกต่างกัน แม้ว่าพวกมันจะเท่ากันในเชิงตรรกะก็ตาม แต่เพราะว่า พวกเขามีค่าแฮชที่แตกต่างกันเนื่องจากเราละเมิดสัญญา เราสามารถพูดได้ว่าเราสูญเสียวัตถุของเราไปที่ไหนสักแห่งในลำไส้ของตารางแฮช

  2. hashCodeใช่equalsไม่ใช่.

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

    ดังนั้นในทางทฤษฎีควรยกตัวอย่างจากย่อหน้าก่อนหน้า แต่เรายังไม่สามารถค้นหาวัตถุของเราในตารางแฮชได้ แม้ว่าเราจะอยู่ใกล้สิ่งนี้ แต่อย่างน้อยที่สุดเราจะพบตะกร้าตารางแฮชที่วัตถุจะวางอยู่

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

อัลกอริทึมทั่วไปสำหรับการกำหนด hashCode

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

แทนที่จะได้ข้อสรุป

ดังนั้นเราจะเห็นว่าวิธีการequalsมีhashCodeบทบาทที่ชัดเจนในภาษา Java และได้รับการออกแบบมาเพื่อให้ได้คุณลักษณะความเท่าเทียมกันเชิงตรรกะของวัตถุทั้งสอง ในกรณีของวิธีการequalsนี้มีความสัมพันธ์โดยตรงกับการเปรียบเทียบวัตถุ ในกรณีของhashCodeทางอ้อม สมมติว่าจำเป็น เพื่อกำหนดตำแหน่งโดยประมาณของวัตถุในตารางแฮชหรือโครงสร้างข้อมูลที่คล้ายกันเพื่อที่จะ เพิ่มความเร็วในการค้นหาวัตถุ นอกจากสัญญาแล้วequalsยังhashCodeมีข้อกำหนดอื่นที่เกี่ยวข้องกับการเปรียบเทียบวัตถุอีกด้วย นี่คือความสอดคล้องของ วิธี compareToอินเทอร์เฟComparableซกับไฟล์equals. ข้อกำหนดนี้กำหนดให้นักพัฒนาต้องกลับมาเสมอx.equals(y) == trueเมื่อ x.compareTo(y) == 0นั่นคือ เราเห็นว่าการเปรียบเทียบเชิงตรรกะของสองวัตถุไม่ควรขัดแย้งกันที่ใดก็ได้ในแอปพลิเคชัน และควรสอดคล้องกันเสมอ

แหล่งที่มา

Java ที่มีประสิทธิภาพ รุ่นที่สอง โจชัว บลอช. แปลหนังสือดีมากฟรี Java ห้องสมุดของมืออาชีพ เล่มที่ 1 พื้นฐาน เคย์ ฮอร์สต์มันน์. ทฤษฎีน้อยลงและการปฏิบัติมากขึ้น แต่ทุกอย่างไม่ได้รับการวิเคราะห์อย่างละเอียดเท่าของ Bloch แม้ว่าจะมีมุมมองเดียวกันเท่ากับ () โครงสร้างข้อมูลในภาพ HashMap บทความที่มีประโยชน์อย่างยิ่งเกี่ยวกับอุปกรณ์ HashMap ใน Java แทนที่จะดูแหล่งที่มา
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION