นี่เป็นคำถามที่คลาสสิกมากใน Java และมักถูกถามในระหว่างการสัมภาษณ์ ในความเป็นจริงหนังสือหรือบทความหลายเล่มได้กล่าวว่าคุณต้องใช้วิธีการมากเกินไป HashCode () และ Equals () เพื่อตระหนักถึงการค้นหาคีย์ที่กำหนดเองใน HashMap อย่างไรก็ตามดูเหมือนว่าบทความสองสามข้อพูดถึงสาเหตุที่คุณต้องทำสิ่งนี้และผลที่ตามมาจะเกิดจากการไม่ทำเช่นนี้ดังนั้นฉันจะเขียนบทความนี้เพื่ออธิบาย
ก่อนอื่นจะเกิดอะไรขึ้นถ้าเราใช้คลาสบุคคลต่อไปนี้เป็นคีย์และเก็บไว้ใน HashMap
บุคคลชั้นเรียนสาธารณะ {รหัสสตริงส่วนตัว; บุคคลสาธารณะ (รหัสสตริง) {this.id = id; }} นำเข้า java.util.hashmap; คลาสสาธารณะหลัก {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {hashmap <person, string> map = new hashmap <person, string> (); map.put (บุคคลใหม่ ("001"), "FinomingSea"); map.put (คนใหม่ ("002"), "linyin"); map.put (คนใหม่ ("003"), "Henrylin"); map.put (บุคคลใหม่ ("003"), "Finomingalely"); System.out.println (map.toString ()); System.out.println (map.get (บุคคลใหม่ ("001"))); System.out.println (map.get (บุคคลใหม่ ("002"))); System.out.println (map.get (บุคคลใหม่ ("003"))); -ผลลัพธ์ผลลัพธ์คืออะไร?
{person@6e4d4d5e = henrylin, person@275cea3 = finomingsea, person@15128ee5 = finomingaly, person@4513098 = linyin} nullnullnullเราจะเห็นว่ามีสองปัญหาที่นี่:
1. ในระหว่างกระบวนการเพิ่มเราเพิ่มคู่คีย์คู่ของคีย์ = คนใหม่ ("003") สองครั้ง ในความคาดหวังควรมีเพียงคู่หนึ่งค่าคีย์ดังกล่าวใน HashMap เนื่องจากคีย์ (คาดหวัง) เหมือนกันจึงไม่ควรเพิ่มซ้ำ ๆ value = "fiffingSealy" เพิ่มครั้งที่สองควรแทนที่ค่าดั้งเดิม = "Henrylin" แต่ในอินพุตเราพบว่าสถานการณ์ที่คาดหวังไม่ได้เกิดขึ้น แต่มีคู่คีย์-ค่าสองคู่ของค่า = "fiffingsally" และ value = "Henrylin" ใน HASHMAP และค่าคีย์ของพวกเขายังแตกต่างกันซึ่งเห็นได้ชัดว่าผิด
2. เมื่อได้รับค่าเราใช้วัตถุสามคนในการค้นหา วัตถุทั้งสามนี้เหมือนกับค่าคีย์ทั้งสามที่เราเพิ่งเก็บไว้ (ตามความคาดหวัง) แต่การค้นหาเป็นค่าโมฆะสามค่าซึ่งเห็นได้ชัดว่าผิดเช่นกัน
ดังนั้นวิธีการที่ถูกต้องได้รับการอธิบายในหลาย ๆ ที่ คลาสบุคคลได้รับการแก้ไขโดยตรงมากเกินไปเท่ากับวิธีการและ hashcode และคลาสบุคคลที่ได้รับการแก้ไขมีดังนี้:
บุคคลชั้นเรียนสาธารณะ {รหัสสตริงส่วนตัว; บุคคลสาธารณะ (รหัสสตริง) {this.id = id; } @Override บูลีนสาธารณะเท่ากับ (Object O) {ถ้า (นี่ == o) ส่งคืนจริง; if (o == null || getClass ()! = o.getClass ()) ส่งคืน false; บุคคล = (บุคคล) o; ถ้า (id! = null?! id.equals (person.id): person.id! = null) return false; กลับมาจริง; } @Override public int hashCode () {return id! = null? id.hashCode (): 0; -จากนั้นเมื่อเราทำการตรวจสอบขั้นตอนการตรวจสอบข้างต้นอีกครั้งผลลัพธ์จะมีดังนี้:
{person@ba31 = findingSea, person@ba32 = linyin, person@ba33 = fifftseally} finomeLinyinyinfindingsalyดังที่เห็นได้ว่าไฮไลท์และข้อผิดพลาดทั้งหมดชี้ให้เห็นได้รับการแก้ไขแล้ว แล้วทำไมสิ่งนี้ถึงเกิดขึ้น?
ใน HashMap ลำดับการเปรียบเทียบคีย์ค้นหาคือ:
1. คำนวณรหัสแฮชของวัตถุเพื่อดูว่ามีอยู่ในตารางหรือไม่
2. ตรวจสอบว่าวัตถุในตำแหน่งรหัสแฮชที่สอดคล้องกันเท่ากับวัตถุปัจจุบันหรือไม่
เห็นได้ชัดว่าขั้นตอนแรกคือการใช้วิธี HashCode () และขั้นตอนที่สองคือการใช้วิธี Equals () เมื่อไม่ดำเนินการมากเกินไปวิธีการทั้งสองของคลาสวัตถุจะถูกเรียกโดยค่าเริ่มต้นในสองขั้นตอนนี้ ในวัตถุวิธีการคำนวณของรหัสแฮชถูกคำนวณตามที่อยู่วัตถุ ที่อยู่วัตถุของคนสองคน ("003") แตกต่างกันดังนั้นรหัสแฮชของพวกเขาก็แตกต่างกันเช่นกัน โดยธรรมชาติแล้ว HashMap จะไม่ถือว่าเป็นคีย์เดียวกัน ในเวลาเดียวกันในค่าเริ่มต้นเท่ากับ () ของวัตถุมันจะถูกเปรียบเทียบตามที่อยู่ของวัตถุ โดยธรรมชาติคนหนึ่ง ("003") และบุคคลอื่น ("003") ไม่เท่ากัน
หลังจากทำความเข้าใจกับสิ่งนี้มันเป็นเรื่องง่ายที่จะทราบว่าทำไมคุณต้องใช้วิธีการมากเกินไปทั้งสอง hashCode () และเท่ากับ
•การโอเวอร์โหลด HashCode () คือการได้รับรหัสแฮชเดียวกันสำหรับคีย์เดียวกันเพื่อให้ HASHMAP สามารถวางตำแหน่งบนคีย์ที่เราระบุ
•การโอเวอร์โหลดเท่ากับ () คือการแสดง hashmap ว่าวัตถุปัจจุบันและวัตถุที่บันทึกไว้ในคีย์นั้นเท่ากันเพื่อให้เราสามารถรับคู่คีย์ค่าที่สอดคล้องกับคีย์ได้อย่างแท้จริง
มีรายละเอียดอื่น ในชั้นเรียนบุคคลการเน้นวิธีการ hashcode () คือ:
@OverridePublic int hashCode () {return id! = null? id.hashCode (): 0;}จุดที่อาจทำให้งงที่นี่คือ: ทำไมรหัสแฮชของตัวแปรของสตริงประเภทจึงสามารถใช้เป็นค่ารหัสแฮชของคลาสบุคคลได้หรือไม่? รหัสแฮชของบุคคลใหม่ (สตริงใหม่ ("003")) และบุคคลใหม่ (สตริงใหม่ ("003")) เท่ากัน?
มาดูผลลัพธ์ของรหัสต่อไปนี้:
System.out.println ("FindingSea" .hashCode ()); System.out.println ("FindingSea" .hashCode ()); System.out.println (สตริงใหม่ ("FindingSea"). hashCode ()); String ("FindingSea"). HashCode ()); 728795174728795174728795174728795174คุณจะเห็นว่าเอาต์พุตของข้อความทั้งสี่นั้นเท่ากันทั้งหมด มันใช้งานง่ายและสมเหตุสมผลที่จะเดาว่าประเภทสตริงยังโอเวอร์โหลด HashCode () เพื่อส่งคืนค่ารหัสแฮชตามเนื้อหาของสตริงดังนั้นสตริงที่มีเนื้อหาเดียวกันมีรหัสแฮชเดียวกัน
ในเวลาเดียวกันสิ่งนี้ยังแสดงให้เห็นถึงคำถาม: ทำไมเราต้องใช้ Equals () สำหรับการเปรียบเทียบเมื่อเรารู้ว่า HashCode () เท่ากัน? เป็นเพราะมันหลีกเลี่ยงสถานการณ์ในตัวอย่างข้างต้นเนื่องจากตามการใช้งานการโอเวอร์โหลดของวิธีการ HashCode () ของคลาสบุคคลคลาสบุคคลจะใช้ค่ารหัสแฮชโดยตรงของรหัสสมาชิกประเภทสตริงเป็นค่ารหัสแฮช อย่างไรก็ตามเป็นที่ชัดเจนว่าบุคคล ("003") และสตริง ("003") ไม่เท่ากันดังนั้นเมื่อ HashCode () เท่ากันเท่ากับ () ก็จำเป็นต้องเปรียบเทียบ
ตัวอย่างต่อไปนี้สามารถใช้เป็นหลักฐานของคำอธิบายข้างต้น:
System.out.println (บุคคลใหม่ ("003"). hashcode ()); // 47667System.out.println (สตริงใหม่ ("003"). hashCode ()); // 47667System.out.println (บุคคลใหม่ ("003"). เท่ากับ (สตริงใหม่ ("003"))); // เท็จบทความข้างต้น Java ใช้คลาสที่กำหนดเองเป็นตัวอย่างคีย์ค่าของ HASHMAP นี่คือเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่ามันจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น