เกี่ยวกับ HashCode ใน Wikipedia:
ในภาษาการเขียนโปรแกรม Java ทุกชั้นเรียนโดยปริยายหรืออย่างชัดเจนให้วิธี HashCode () ซึ่งย่อยข้อมูลที่เก็บไว้ในอินสแตนซ์ของคลาสเป็นค่าแฮชเดี่ยว (จำนวนเต็มที่ลงนาม 32 บิต)
HashCode แยกจำนวนเต็ม 32 บิตตามข้อมูลทั้งหมดที่เก็บไว้ในอินสแตนซ์ของวัตถุ จุดประสงค์ของจำนวนเต็มนี้คือการระบุเอกลักษณ์ของอินสแตนซ์ มันค่อนข้างคล้ายกับรหัส MD5 และแต่ละไฟล์สามารถสร้างรหัส MD5 ที่ไม่ซ้ำกันผ่านอัลกอริทึม MD5 อย่างไรก็ตาม HashCode ใน Java ไม่ได้ใช้ HashCode เพื่อสร้าง hashCode ที่ไม่ซ้ำกันสำหรับแต่ละวัตถุและยังมีโอกาสที่จะทำซ้ำ
มาดูคลาสวัตถุก่อน เรารู้ว่าคลาสวัตถุเป็นคลาสแม่แบบโดยตรงหรือโดยอ้อมของคลาสทั้งหมดในโปรแกรม Java และอยู่ในจุดสูงสุดของระดับคลาส วิธีการทั่วไปหลายอย่างถูกกำหนดไว้ในคลาสวัตถุรวมถึงวิธี hashcode ที่เราต้องการพูดคุยเกี่ยวกับดังนี้
ระดับชนพื้นเมืองสุดท้ายของสาธารณะ <?> getClass (); hashcode int สาธารณะ (); บูลีนสาธารณะเท่ากับ (Object obj) {return (this == obj); } public String toString () {return getClass (). getName () + "@" + integer.toHexstring (hashCode ()); -โปรดทราบว่ามีตัวดัดแปลงดั้งเดิมอยู่ด้านหน้าของวิธี HashCode ซึ่งหมายความว่าวิธีการ HashCode นั้นถูกนำไปใช้ในภาษาที่ไม่ใช่ Java วิธีการเฉพาะถูกนำไปใช้ภายนอกและส่งคืนที่อยู่ของวัตถุหน่วยความจำ
ในหลายคลาส Java มีการเขียนวิธีการเท่ากับและ hashcode ใหม่ ทำไมถึงเป็นเช่นนี้? คลาสสตริงที่พบมากที่สุดเช่นถ้าฉันกำหนดสองสตริงที่มีอักขระเดียวกันจากนั้นเมื่อเปรียบเทียบพวกเขาผลลัพธ์ที่ฉันต้องการควรจะเท่ากัน หากคุณไม่ได้แทนที่วิธีการเท่ากับและ hashcode พวกเขาจะไม่เท่ากันอย่างแน่นอนเนื่องจากที่อยู่หน่วยความจำของวัตถุทั้งสองนั้นแตกต่างกัน
public int hashCode () {int h = hash; if (h == 0) {int ปิด = ออฟเซ็ต; ถ่าน val [] = ค่า; int len = นับ; สำหรับ (int i = 0; i <len; i ++) {h = 31*h+val [ปิด ++]; } hash = h; } return h; -ในความเป็นจริงรหัสนี้เป็นการใช้งานนิพจน์ทางคณิตศาสตร์นี้
S [0]*31^(N-1) + S [1]*31^(N-2) + … + S [N-1]
s [i] เป็นอักขระ i-th ของสตริงและ n คือความยาวของสตริง แล้วทำไมต้องใช้ 31 ที่นี่แทนตัวเลขอื่น ๆ ? Java ที่มีประสิทธิภาพพูดสิ่งนี้: เหตุผลที่เลือก 31 เพราะมันเป็นจำนวนที่สำคัญ หากตัวคูณเป็นตัวเลขที่สม่ำเสมอและการคูณล้นข้อมูลจะหายไปเนื่องจากการคูณด้วย 2 เทียบเท่ากับการดำเนินการเปลี่ยน ประโยชน์ของการใช้ตัวเลขที่สำคัญไม่ชัดเจน แต่ผลลัพธ์แฮชถูกใช้ตามอัตภาพเพื่อคำนวณผลลัพธ์แฮช 31 มีคุณสมบัติที่ดีซึ่งก็คือการใช้การเปลี่ยนแปลงและการลบแทนการคูณเพื่อให้ได้ประสิทธิภาพที่ดีขึ้น: 31*i == (i << 5) -i VMS สามารถปรับการเพิ่มประสิทธิภาพนี้ให้เสร็จสมบูรณ์โดยอัตโนมัติ
อย่างที่คุณเห็นคลาสสตริงใช้ค่าของมันเป็นพารามิเตอร์ในการคำนวณ hashcode นั่นคือค่าเดียวกันจะมีค่าแฮชโฟตอนเดียวกันแน่นอน นี่เป็นเรื่องง่ายที่จะเข้าใจเนื่องจากค่าค่าเท่ากันดังนั้นหากการเปรียบเทียบเท่ากับเท่ากับวิธีการเท่ากับเท่ากับ HashCode จะต้องเท่ากับ อีกวิธีหนึ่งไม่จำเป็นต้องเป็นจริง ไม่รับประกันว่า hashcode เดียวกันจะต้องมีวัตถุเดียวกัน
ฟังก์ชั่นแฮชที่ดีควรมีลักษณะเช่นนี้: ผลิตแฮชโค้ดที่ไม่เท่ากันสำหรับวัตถุต่าง ๆ
ในกรณีในอุดมคติฟังก์ชั่นแฮชควรแจกจ่ายอินสแตนซ์ที่ไม่เท่าเทียมกันอย่างสม่ำเสมอในการตั้งค่าให้กับแฮชโค้ดที่เป็นไปได้ทั้งหมด มันยากมากที่จะบรรลุสถานการณ์ในอุดมคตินี้อย่างน้อย Java ก็ไม่ประสบความสำเร็จ เพราะเราสามารถเห็นได้ว่า HashCode นั้นไม่ได้ถูกสุ่มและมีกฎบางอย่างซึ่งเป็นสมการทางคณิตศาสตร์ด้านบน เราสามารถสร้างบางส่วนที่มี hashcode เดียวกัน แต่ค่าที่แตกต่างกันตัวอย่างเช่น: hashcode ของ AA และ BB เหมือนกัน
รหัสต่อไปนี้:
คลาสสาธารณะหลัก {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {main m = new main (); System.out.println (M); System.out.println (Integer.tohexstring (M.HashCode ())); สตริง a = "aa"; สตริง b = "bb"; System.out.println (A.HashCode ()); System.out.println (B.HashCode ()); -ผลลัพธ์ผลลัพธ์:
Main@2A139A55 2A139A55 2112 2112
โดยทั่วไปเมื่อเขียนฟังก์ชั่นที่เท่าเทียมกันอีกครั้งคุณจะต้องเขียนฟังก์ชัน HashCode ใหม่ ทำไมถึงเป็นเช่นนี้?
มาดูตัวอย่างนี้กันเถอะสร้างพนักงานชั้นเรียนที่เรียบง่าย
พนักงานชั้นเรียนสาธารณะ {ID จำนวนเต็มส่วนตัว; สตริงส่วนตัวชื่อแรก; สตริงส่วนตัวนามสกุล; แผนกสตริงส่วนตัว; จำนวนเต็มสาธารณะ getId () {return id; } โมฆะสาธารณะ setId (ID จำนวนเต็ม) {this.id = id; } สตริงสาธารณะ getFirstName () {return firstName; } โมฆะสาธารณะ setFirstName (String firstName) {this.firstName = firstName; } สตริงสาธารณะ getLaStName () {return lastName; } โมฆะสาธารณะ setLastName (สตริงนามสกุล) {this.lastName = LastName; } สตริงสาธารณะ getDepartment () {แผนกส่งคืน; } โมฆะสาธารณะ setDepartment (แผนกสตริง) {this.department = แผนก; -ชั้นเรียนของพนักงานด้านบนมีคุณสมบัติพื้นฐานและผู้ตั้งถิ่นฐานและตัวตั้งค่าเท่านั้น ตอนนี้พิจารณาสถานการณ์ที่คุณต้องเปรียบเทียบพนักงานสองคน
ระดับสาธารณะที่เท่าเทียมกัน {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {พนักงาน e1 = พนักงานใหม่ (); พนักงาน E2 = พนักงานใหม่ (); e1.setid (100); e2.setId (100); // พิมพ์เท็จในคอนโซล System.out.println (e1.equals (E2)); -ไม่ต้องสงสัยเลยว่าโปรแกรมข้างต้นจะส่งออกเท็จ แต่ในความเป็นจริงวัตถุสองชิ้นข้างต้นเป็นตัวแทนผ่านพนักงาน ตรรกะทางธุรกิจที่แท้จริงหวังว่าเราจะกลับมาเป็นจริง
เพื่อให้บรรลุเป้าหมายนี้เราจำเป็นต้องเขียนวิธีการเท่ากับ
บูลีนสาธารณะเท่ากับ (วัตถุ o) {ถ้า (o == null) {return false; } if (o == สิ่งนี้) {return true; } if (getClass ()! = o.getClass ()) {return false; } พนักงาน e = (พนักงาน) o; return (this.getId () == e.getId ());} เพิ่มวิธีนี้ในคลาสข้างต้นและ Eauqlstest จะส่งออกจริง
เราทำเสร็จแล้ว? ไม่ลองเปลี่ยนวิธีทดสอบและดู
นำเข้า java.util.hashset; นำเข้า java.util.set; คลาสสาธารณะที่เท่าเทียมกัน {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {พนักงาน e1 = พนักงานใหม่ (); พนักงาน e2 = พนักงานใหม่ (); e1.setid (100); e2.setid (100); // = new hashset <พนักงาน> (); พนักงาน. add (e1); พนักงาน. add (e2); // พิมพ์สอง objectssystem.out.println (พนักงาน);}โปรแกรมข้างต้นส่งผลสองผลลัพธ์ หากวัตถุของพนักงานทั้งสองเท่ากับการส่งคืนจริงควรเก็บวัตถุเพียงชิ้นเดียวไว้ในชุด ปัญหาคืออะไร?
เราลืมวิธีที่สำคัญอันดับสอง hashcode () เช่นเดียวกับ Javadoc ของ JDK ที่กล่าวว่าถ้าคุณเขียนวิธี Equals () ใหม่คุณต้องเขียนวิธี HashCode () ใหม่ มาเพิ่มวิธีการต่อไปนี้และโปรแกรมจะดำเนินการอย่างถูกต้อง
@Override public int hashCode () {สุดท้าย int prime = 31; int ผลลัพธ์ = 1; result = prime * result + getId (); ผลการกลับมา; -สิ่งที่ควรจดจำ
พยายามตรวจสอบให้แน่ใจว่าคุณสมบัติเดียวกันของวัตถุถูกใช้เพื่อสร้างสองวิธี: hashCode () และ Equals () ในกรณีของเราเราใช้รหัสพนักงาน
วิธี EQAULS จะต้องสอดคล้องกัน (หากวัตถุไม่ได้รับการแก้ไขเท่ากับควรส่งคืนค่าเดียวกัน)
เมื่อใดก็ได้ตราบเท่าที่ A.Equals (B), A.HashCode () ต้องเท่ากับ B.HashCode ()
ทั้งสองจะต้องเขียนใหม่ในเวลาเดียวกัน
สรุป
ข้างต้นคือทั้งหมดที่เกี่ยวกับความเข้าใจเชิงลึกของบทความนี้เกี่ยวกับวิธี HashCode ใน Java และฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!