คำนำ
อย่างที่เราทราบกันดีว่า java.lang.Object มีวิธีการ hashcode () และวิธี Equals () ซึ่งมีบทบาทสำคัญในการออกแบบซอฟต์แวร์ เขียนใหม่สองวิธีในบางคลาสเพื่อให้ได้ฟังก์ชั่นสำคัญบางอย่าง
1. ทำไมต้องใช้ hashcode ()?
องค์ประกอบในชุดชุดนั้นไม่เป็นระเบียบและไม่สามารถทำซ้ำได้ แล้วอะไรคือพื้นฐานสำหรับการตัดสินว่ามีสององค์ประกอบซ้ำแล้วซ้ำอีก?
บางคนพูดว่า: Object.equal() นั้นใช้เพื่อเปรียบเทียบว่าวัตถุมีค่าเท่ากันหรือไม่ อย่างไรก็ตามมีวัตถุจำนวนมากในชุดและจำนวนการเปรียบเทียบองค์ประกอบของวัตถุที่เพิ่มเข้ามาในชุดชุดจะค่อยๆเพิ่มขึ้นอย่างมากลดประสิทธิภาพของการทำงานของโปรแกรม Java ใช้อัลกอริทึมการแฮช (เรียกอีกอย่างว่าการแฮชอัลกอริทึม) เพื่อแก้ปัญหานี้ วัตถุ (หรือข้อมูล) ถูกแมปโดยตรงไปยังที่อยู่ตามอัลกอริทึมเฉพาะและประสิทธิภาพการเข้าถึงของวัตถุได้รับการปรับปรุงอย่างมาก
ด้วยวิธีนี้เมื่อชุดที่มีองค์ประกอบจำนวนมากจำเป็นต้องเพิ่มองค์ประกอบ (วัตถุ) การโทรครั้งแรก HashCode () ขององค์ประกอบนี้และคุณสามารถจัดตำแหน่งตำแหน่งที่เก็บข้อมูลจริงขององค์ประกอบนี้ได้ในครั้งเดียว หากไม่มีองค์ประกอบในตำแหน่งนี้หมายความว่าวัตถุนี้จะถูกเก็บไว้ในชุดคอลเลกชันเป็นครั้งแรกและวัตถุจะถูกเก็บไว้ที่ตำแหน่งนี้โดยตรง หากมีวัตถุที่ตำแหน่งนี้ให้โทร Equal () เพื่อดูว่าวัตถุทั้งสองเท่ากันหรือไม่ หากสิ่งเดียวกันเป็นจริงให้ทิ้งองค์ประกอบและไม่มีอยู่จริง หากไม่เท่ากันแฮชกับที่อยู่อื่น
นี่คือเหตุผลว่าทำไมเมื่อชุดตั้งค่าข้อมูลประเภทวัตถุมีความจำเป็นที่จะต้องเขียนวิธี HashCode () ของวัตถุใหม่ แต่ยังเขียนวิธี Equals () ใหม่อีกครั้ง
2. ใช้ hashcode () อย่างไร?
ความสัมพันธ์ระหว่างค่าส่งคืนของ HashCode () และ Equals ()
นี่คือตัวอย่าง ในการพัฒนาซอฟต์แวร์ที่แท้จริงจะเป็นการดีที่สุดที่จะเขียนสองวิธีนี้ใหม่
พนักงานชั้นเรียนสาธารณะ {int EmployeeId; ชื่อสตริง; @Override บูลีนสาธารณะเท่ากับ (Object obj) {ถ้า (obj == สิ่งนี้) คืนค่าจริง; พนักงาน EMP = (พนักงาน) OBJ; if (EmployeeId.equals (emp.getemployeeId ()) && name == emp.getName ()) ส่งคืนจริง; กลับเท็จ; } @Override สาธารณะ int hashCode () {int hash = 1; แฮช = แฮช * 17 + พนักงาน; hash = hash * 31 + name.hashcode (); คืนแฮช; -วิธี Equals () และ HashCode () ใช้เพื่อเปรียบเทียบในคลาสเดียวกันโดยเฉพาะอย่างยิ่งเมื่อจัดเก็บวัตถุคลาสเดียวกันในคอนเทนเนอร์เช่น Set to Store วัตถุในคลาสเดียวกัน
ก่อนอื่นเราต้องเข้าใจปัญหา:
วัตถุสองชิ้นที่มีเท่ากับ () เท่ากับ HashCode () จะต้องเท่ากันและวัตถุสองชิ้นที่มีค่าเท่ากับ () ไม่เท่ากันไม่สามารถพิสูจน์ได้ว่า hashCode () ของพวกเขาไม่เท่ากัน กล่าวอีกนัยหนึ่งสำหรับสองวัตถุที่มีค่าเท่ากับ () ไม่เท่ากัน HashCode () อาจเท่ากัน
HashCode ที่นี่เป็นเหมือนดัชนีของตัวละครแต่ละตัวในพจนานุกรมและ Equals () เป็นเหมือนการเปรียบเทียบคำที่แตกต่างกันภายใต้อักขระเดียวกันในพจนานุกรม เช่นเดียวกับในพจนานุกรมค้นหาคำสองคำว่า "ตัวเอง" และ "ธรรมชาติ" ภายใต้คำว่า "ตัวเอง" ในพจนานุกรมถ้า Equals () ถูกใช้เพื่อกำหนดความเท่าเทียมกันของคำสืบค้นคำมันเป็นคำเดียวกัน ตัวอย่างเช่นคำสองคำที่เปรียบเทียบโดย Equals () เป็น "ตัวเอง" จากนั้นค่าที่ได้รับโดยวิธีการ HashCode () จะต้องเท่ากันในเวลานี้; ถ้าเมธอดเท่ากับ () เปรียบเทียบคำว่า "ตัวเอง" และ "ตามธรรมชาติ" ผลลัพธ์ก็คือคุณไม่ต้องการรอ แต่คำทั้งสองนี้เป็นคำว่า "ตัวเอง" และเมื่อค้นหาดัชนีนั่นคือ hashcode () เหมือนกัน ถ้าเท่ากับ () เปรียบเทียบคำว่า "ตนเอง" และ "พวกเขา" ผลลัพธ์ก็แตกต่างกันและผลลัพธ์ที่ได้จาก HashCode () ก็แตกต่างกันในเวลานี้
ในทางกลับกัน: HashCode () นั้นแตกต่างกันและสามารถแนะนำได้ (Equals (); HashCode () เท่ากับเท่ากับ () อาจเท่ากันหรืออาจไม่เท่ากัน
ในคลาสวัตถุวิธี HashCode () เป็นวิธีการในท้องถิ่นซึ่งส่งคืนค่าที่อยู่ของวัตถุ เมธอด Equals () ในคลาสวัตถุยังเปรียบเทียบค่าที่อยู่ของวัตถุทั้งสอง ถ้า Equals () เท่ากันก็หมายความว่าค่าที่อยู่ของวัตถุทั้งสองนั้นเท่ากัน แน่นอน HashCode () เท่ากัน
เนื่องจาก Equals มีความแม่นยำมากขึ้นในการเปรียบเทียบองค์ประกอบที่เท่ากันทำไมต้องใช้วิธีการ HashCode ()?
เนื่องจากอัลกอริทึมแฮชให้ประสิทธิภาพสูงในการค้นหาองค์ประกอบหากคุณต้องการค้นหาว่าคอลเลกชันมีวัตถุวิธีการเขียนรหัสโปรแกรมโดยประมาณ?
คุณมักจะนำองค์ประกอบแต่ละอย่างทีละหนึ่งเพื่อเปรียบเทียบกับวัตถุที่คุณกำลังมองหา เมื่อคุณพบว่าผลลัพธ์ของการเปรียบเทียบวิธี Equals ระหว่างองค์ประกอบและวัตถุที่คุณกำลังมองหาหยุดการค้นหาและส่งคืนข้อมูลเชิงบวก มิฉะนั้นให้ส่งคืนข้อมูลเชิงลบ หากมีองค์ประกอบหลายอย่างในคอลเลกชันเช่น 10,000 องค์ประกอบและไม่มีวัตถุที่คุณกำลังมองหานั่นหมายความว่าโปรแกรมของคุณจะต้องนำองค์ประกอบ 10,000 รายการออกจากคอลเลกชันและเปรียบเทียบทีละรายการเพื่อให้ได้ข้อสรุป
คลาส Object กำหนดวิธี HashCode () เพื่อส่งคืนรหัสแฮชของวัตถุ Java แต่ละรายการ เมื่อมองหาวัตถุจากคอลเลกชัน HashSet ระบบ Java จะเรียกวิธี HashCode () ของวัตถุเป็นครั้งแรกเพื่อรับตาราง Hash Code ของวัตถุจากนั้นค้นหาพื้นที่จัดเก็บที่สอดคล้องกันตามแฮชและในที่สุดก็ได้รับแต่ละองค์ประกอบในพื้นที่จัดเก็บ ด้วยวิธีนี้คุณสามารถได้ข้อสรุปโดยไม่ต้องสำรวจองค์ประกอบทั้งหมดในคอลเลกชัน จะเห็นได้ว่าคอลเลกชัน HashSet มีประสิทธิภาพการดึงวัตถุที่ดี
อย่างไรก็ตามประสิทธิภาพของการจัดเก็บวัตถุในคอลเลกชัน HashSet ค่อนข้างต่ำเนื่องจากเมื่อเพิ่มวัตถุในคอลเลกชัน HashSet รหัสแฮชของวัตถุจะต้องคำนวณก่อนและตำแหน่งที่เก็บข้อมูลของวัตถุในคอลเลกชันจะถูกกำหนดตามรหัสแฮชนี้ เพื่อให้แน่ใจว่าวัตถุอินสแตนซ์ของคลาสสามารถเก็บไว้ได้ตามปกติใน HashSet ผลลัพธ์ของวัตถุอินสแตนซ์ทั้งสองของคลาสนี้จะต้องเท่ากันเมื่อเปรียบเทียบกับวิธี Equals () เท่ากับ นั่นคือถ้าผลลัพธ์ของ obj1.equals(obj2) เป็นจริงดังนั้นผลลัพธ์ของนิพจน์ต่อไปนี้จะต้องเป็น true:obj1.hashCode() == obj2.hashCode()
กล่าวอีกนัยหนึ่ง: เมื่อเราเขียนวิธีการเท่ากับวัตถุเราต้องเขียนวิธี HashCode ใหม่ หากเราไม่ได้เขียนวิธี HashCode ใหม่วิธี HashCode ในวัตถุวัตถุจะส่งคืนที่อยู่แฮชของวัตถุเสมอและที่อยู่นี้จะไม่เท่ากัน ดังนั้นแม้ว่าวิธีการที่ Equals จะถูกเขียนใหม่ในเวลานี้จะไม่มีผลเฉพาะเพราะหากวิธีการ HashCode ไม่ต้องการรอมันจะไม่เรียกวิธีการเปรียบเทียบสำหรับการเปรียบเทียบดังนั้นจึงไม่มีความหมาย
โครงสร้างข้อมูลส่วนใหญ่ใช้วิธี Equals เพื่อตรวจสอบว่ามีองค์ประกอบหรือไม่ตัวอย่างเช่น:
รายการ <string> list = array.aslist ("a", "b", "c"); บูลีนมี = list.contains ("b"); ตัวแปรนี้มีผลลัพธ์เป็นจริงเพราะถึงแม้ว่า "B" จะเป็นอินสแตนซ์ที่แตกต่างกัน (นอกจากนี้ยังไม่สนใจที่อยู่อาศัยของสตริง) แต่ก็เท่ากัน
พวกเขาใช้วิธีที่รวดเร็วในการเปรียบเทียบ (ลดความเท่าเทียมกันอินสแตนซ์ที่อาจเกิดขึ้น) แทนที่จะเปรียบเทียบแต่ละองค์ประกอบที่มีอยู่ในอินสแตนซ์ การเปรียบเทียบอย่างรวดเร็วต้องใช้การเปรียบเทียบด้านต่อไปนี้เท่านั้น:
การเปรียบเทียบทางลัดหมายความว่าโดยการเปรียบเทียบค่าแฮชสามารถแทนที่อินสแตนซ์ด้วยค่าจำนวนเต็ม อินสแตนซ์ที่มีรหัสแฮชเดียวกันนั้นไม่เท่ากัน แต่อินสแตนซ์ที่มีความเท่าเทียมจะต้องมีค่าแฮชเดียวกัน (หรือควรจะมีเราจะหารือกันในไม่ช้า) โครงสร้างข้อมูลเหล่านี้มักจะตั้งชื่อโดยเทคนิคนี้และพวกเขาสามารถระบุได้โดยแฮชซึ่ง HASHMAP เป็นตัวแทนที่มีชื่อเสียงที่สุด
พวกเขามักจะทำงานเช่นนี้:
เมื่อเพิ่มองค์ประกอบรหัสแฮชของมันจะใช้ในการคำนวณดัชนีของอาร์เรย์ภายใน (นั่นคือถังที่เรียกว่า)
ถ้าใช่องค์ประกอบที่ไม่เท่ากันมีรหัสแฮชเหมือนกันพวกเขาจะลงเอยที่ถังเดียวกันและรวมเข้าด้วยกันเช่นโดยการเพิ่มลงในรายการ
เมื่ออินสแตนซ์ดำเนินการมีการดำเนินการรหัสแฮชจะถูกใช้เพื่อคำนวณค่าที่เก็บ (ค่าดัชนี) และอินสแตนซ์จะถูกเปรียบเทียบเฉพาะเมื่อองค์ประกอบมีอยู่ในค่าดัชนีที่สอดคล้องกัน
ดังนั้นเท่ากับ HashCode จึงถูกกำหนดไว้ในคลาสวัตถุ
หาก HashCode ถูกใช้เป็นทางลัดเพื่อกำหนดความเท่าเทียมกันมีเพียงสิ่งเดียวที่เราควรสนใจ: วัตถุที่เท่าเทียมควรมี hashcode เดียวกันซึ่งเป็นเหตุผลว่าทำไมถ้าเราแทนที่วิธี Equals เราต้องสร้างการใช้งาน hashcode ที่ตรงกับมัน!
มิฉะนั้นวัตถุที่เท่าเทียมกันอาจไม่มีรหัสแฮชเดียวกันเพราะพวกเขาจะเรียกการใช้งานเริ่มต้นของวัตถุ
อ้างจากเอกสารอย่างเป็นทางการ
อนุสัญญา HashCode ทั่วไป:
เมื่อเรียกวัตถุเดียวกันที่ทำงานในแอปพลิเคชัน Java วิธีการ HashCode จะต้องส่งคืนจำนวนเต็มเดียวกันเสมอ จำนวนเต็มนี้ไม่จำเป็นต้องสอดคล้องกับแอปพลิเคชัน Java ที่แตกต่างกัน ตามวิธีการ equals(Object) หากวัตถุสองชิ้นมีค่าเท่ากันวัตถุทั้งสองจะเรียกวิธีการ HashCode จะต้องสร้างผลลัพธ์เดียวกัน
ตามวิธี equals(Object) หากวัตถุทั้งสองไม่เท่ากันการเรียกใช้วิธี HashCode ไม่จำเป็นต้องสร้างผลลัพธ์จำนวนเต็มที่แตกต่างกัน อย่างไรก็ตามโปรแกรมเมอร์ควรตระหนักว่าการผลิตผลลัพธ์จำนวนเต็มที่แตกต่างกันสำหรับวัตถุที่ไม่เท่ากันน่าจะช่วยปรับปรุงประสิทธิภาพของตารางแฮช
การใช้งาน hashcode
นี่คือการใช้งานอย่างง่าย ๆ ของ person.hashcode() :
@OverridePublic int hashCode () {return objects.Hash (FIRSTNAME, LastName);}บุคคลคำนวณรหัสแฮชโดยการรวมหลายฟิลด์ ทั้งหมดถูกคำนวณโดยฟังก์ชันแฮชของวัตถุ
เลือกฟิลด์
แต่มีสาขาใดที่เกี่ยวข้อง? ข้อกำหนดจะช่วยให้เราตอบคำถามนี้:
หากวัตถุที่เท่ากันต้องมีรหัสแฮชเดียวกันรหัสแฮชที่คำนวณไม่ควรรวมฟิลด์ใด ๆ ที่ไม่ได้ใช้สำหรับการตรวจสอบความเท่าเทียมกัน (มิฉะนั้นวัตถุทั้งสองเป็นเพียงว่าฟิลด์เหล่านี้แตกต่างกัน แต่พวกเขาอาจยังคงเท่ากัน แต่รหัสแฮชของวัตถุทั้งสองจะแตกต่างกันในเวลานี้) ดังนั้นชุดย่อยของฟิลด์ที่ใช้เมื่อฟิลด์กลุ่มแฮชควรเท่ากัน ฟิลด์เดียวกันนี้ใช้โดยค่าเริ่มต้น แต่มีรายละเอียดบางอย่างที่ต้องพิจารณา
สรุป
เราเข้าใจว่าการคำนวณรหัสแฮชคือการบีบอัดค่าจำนวนเต็มเท่ากัน: วัตถุที่เท่ากันจะต้องมีรหัสแฮชเดียวกันและสำหรับการพิจารณาประสิทธิภาพควรแชร์รหัสแฮชเดียวกันกับวัตถุที่ไม่เท่ากันน้อยที่สุดเท่าที่จะเป็นไปได้
ซึ่งหมายความว่าหากมีการเขียนวิธี Equals ใหม่แล้ววิธีการ HashCode จะต้องถูกเขียนใหม่
เมื่อใช้ HashCode ใช้ฟิลด์เดียวกันกับที่ใช้ในเท่ากับ (หรือชุดย่อยของฟิลด์ที่ใช้ในค่าเท่ากับ)
เป็นการดีที่สุดที่จะไม่รวมฟิลด์ที่ไม่แน่นอน อย่าพิจารณาการเรียก HashCode สำหรับคอลเลกชัน หากไม่มีโหมดเฉพาะอินพุตพิเศษให้ลองใช้อัลกอริทึมแฮชทั่วไป
โอเคข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com