حول hashcode ، في ويكيبيديا:
في لغة برمجة Java ، يوفر كل فئة ضمنيًا أو صريحًا طريقة HashCode () ، والتي ترضم البيانات المخزنة في مثيل للفئة إلى قيمة تجزئة واحدة (عدد صحيح موقّع 32 بت).
يقوم HashCode باستخراج عدد صحيح 32 بت استنادًا إلى جميع البيانات المخزنة في مثيل الكائن. الغرض من هذا عدد صحيح هو الإشارة إلى تفرد المثيل. يشبه إلى حد ما رمز MD5 ، ويمكن لكل ملف إنشاء رمز MD5 فريد من خلال خوارزمية MD5. ومع ذلك ، فإن رمز التجزئة في Java لا ينفذ حقًا رمز التجزئة لإنشاء رمز هاشد فريد لكل كائن ، ولا تزال هناك فرصة معينة للازدواجية.
دعنا نلقي نظرة على فئة الكائن أولاً. نحن نعلم أن فئة الكائن هي فئة الوالدين المباشرة أو غير المباشرة لجميع الفئات في برنامج Java وهي في أعلى نقطة في مستوى الفصل. يتم تعريف العديد من الطرق الشائعة في فئة الكائن ، بما في ذلك طريقة HashCode التي نريد التحدث عنها ، على النحو التالي
الفئة الأمامية العامة <؟> getClass () ؛ Hashcode الأصلي العام () ؛ منطقية عامة تساوي (كائن OBJ) {return (this == obj) ؛ } السلسلة العامة toString () {return getClass (). getName () + "@" + integer.toHexString (hashcode ()) ؛ }لاحظ أن هناك معدّلًا أصليًا أمام طريقة HashCode ، مما يعني أن طريقة HashCode يتم تنفيذها بلغة غير جافا. يتم تنفيذ الطريقة المحددة خارجيا وإرجاع عنوان كائن الذاكرة.
في العديد من فصول Java ، تتم إعادة كتابة أساليب Hashcode على قدم المساواة. لماذا هذا؟ فئة السلسلة الأكثر شيوعًا ، كما لو أنني حددت سلسلتين بنفس الأحرف ، ثم عند مقارنتها ، يجب أن تكون النتيجة متساوية. إذا لم تقم بتجاوز أساليب المساواة والرمز ، فلن تكون بالتأكيد متساوية ، لأن عناوين ذاكرة الكائنين مختلفة.
public int hashcode () {int h = hash ؛ if (h == 0) {int Off = Offset ؛ char val [] = value ؛ int len = count ؛ لـ (int i = 0 ؛ i <len ؛ i ++) {h = 31*h+val [Off ++] ؛ } التجزئة = H ؛ } إرجاع 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 نفسه نفس الكائن.
يجب أن تبدو وظيفة التجزئة الجيدة مثل هذا: تنتج علامات تجزئة غير متكافئة لكائنات مختلفة.
في الحالات المثالية ، يجب أن توزع وظيفة التجزئة حالات غير متكافئة بالتساوي في المجموعة إلى جميع أشكال الترميز الممكنة. من الصعب للغاية تحقيق هذا الموقف المثالي ، على الأقل لم تحقق جافا ذلك. نظرًا لأننا نستطيع أن نرى أن الرمز البارز يتم إنشاؤه بشكل غير عشوائي ، وله قواعد معينة ، وهي المعادلة الرياضية أعلاه. يمكننا بناء بعض من نفس الرمز الهزلي ولكن قيم القيمة المختلفة ، على سبيل المثال: Hashcode of AA و BB هي نفسها.
الرمز التالي:
الفئة العامة الرئيسية {public static void main (string [] 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 ()) ؛ }}نتيجة الإخراج:
الرئيسي@2A139A55 2A139A55 2112 2112
بشكل عام ، عند إعادة كتابة الوظيفة المتساوية ، تحتاج أيضًا إلى إعادة كتابة وظيفة Hashcode. لماذا هذا؟
دعونا نلقي نظرة على هذا المثال ، دعنا ننشئ موظفًا بسيطًا في الفصل
موظف الطبقة العامة {معرف Integer الخاص ؛ سلسلة خاصة firstName ؛ سلسلة خاصة قسم السلسلة الخاص ؛ عدد صحيح عام getId () {معرف الإرجاع ؛ } public void setId (integer id) {this.id = id ؛ } السلسلة العامة getFirstName () {return firstName ؛ } public void setFirstName (String firstName) {this.firstName = firstName ؛ } السلسلة العامة getLastName () {return lastName ؛ } public void setLastName (String lastName) {this.lastname = lastName ؛ } السلسلة العامة getDepartment () {Return Department ؛ } public void setDepartment (string department) {this.department = department ؛ }}يحتوي فئة الموظفين أعلاه فقط على بعض الخصائص الأساسية والمستقبينات والمستقبين. الآن فكر في موقف تحتاج فيه إلى مقارنة موظفين.
الطبقة العامة equalStest {public static void main (string [] args) {effectee e1 = new efferene () ؛ الموظف e2 = موظف جديد () ؛ e1.setid (100) ؛ e2.setid (100) ؛ // prints false in console system.out.println (e1.equals (e2)) ؛ }}ليس هناك شك في أن البرنامج أعلاه سيؤدي إلى إخراج خطأ ، ولكن في الواقع ، تمثل الكائنان أعلاه من خلال الموظف. يأمل منطق العمل الحقيقي أن نعود صحيحًا.
لتحقيق ذلك ، نحتاج إلى إعادة كتابة طريقة متساوية.
منطقية عامة تساوي (كائن O) {if (o == null) {return false ؛ } if (o == this) {return true ؛ } if (getClass ()! = o.getClass ()) {return false ؛ } الموظف e = (الموظف) o ؛ return (this.getID () == E.GetID ()) ؛} أضف هذه الطريقة إلى الفئة أعلاه وسيقوم EAUQLSTEST بإخراج TRUE.
هل انتهينا؟ لا ، دعنا نغير طريقة الاختبار ونلقي نظرة.
استيراد java.util.hashset ؛ استيراد java.util.set ؛ الطبقة العامة equalStest {public static void main (string [] args) {exeriese e1 = new ameesee () ؛ effecte e2 = new efferene () ؛ e1.setId (100) ؛ e2.setid (100) ؛ new hashset <experiese> () ؛ الموظفين. add (e1) ؛ الموظفين. add (e2) ؛ // يطبع اثنين من كائنات system.out.println (الموظفين) ؛}البرنامج أعلاه يخرج نتيجتين. إذا كان كائدي الموظف يساويان العودة بشكل صحيح ، فيجب تخزين كائن واحد فقط في المجموعة. ما هي المشكلة؟
لقد نسينا الطريقة الثانية المهمة Hashcode (). تمامًا كما قال JAVADOC من JDK ، إذا قمت بإعادة كتابة طريقة متساوية () ، فيجب عليك إعادة كتابة طريقة HashCode (). دعنا نضيف الطريقة التالية وسيتم تنفيذ البرنامج بشكل صحيح.
Override public int hashcode () {Final int prime = 31 ؛ int النتيجة = 1 ؛ النتيجة = prime * result + getId () ؛ نتيجة العودة }أشياء يجب تذكرها
حاول التأكد من استخدام نفس خاصية الكائن لإنشاء طريقتين: HashCode () و equals (). في حالتنا ، نستخدم معرفات الموظف.
يجب أن تكون طريقة eqauls متسقة (إذا لم يتم تعديل الكائن ، فيجب أن تُرجع المساواة نفس القيمة)
في أي وقت طالما A.equals (B) ، يجب أن يكون A.HashCode () مساوياً لـ B.HashCode ().
يجب إعادة كتابة كلاهما في نفس الوقت.
لخص
ما ورد أعلاه هو كل شيء عن فهم هذه المقالة المتعمقة لطريقة هاش كود في جافا ، وآمل أن تكون مفيدة للجميع. يمكن للأصدقاء المهتمين الاستمرار في الرجوع إلى الموضوعات الأخرى ذات الصلة على هذا الموقع. إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها. شكرا لك يا أصدقائك لدعمكم لهذا الموقع!