সংগ্রহের জন্য হ্যাশকোড পদ্ধতির জন্য সর্বোত্তম বাস্তবায়ন


299

hashCode()সংগ্রহের জন্য পদ্ধতির সর্বোত্তম প্রয়োগের বিষয়ে আমরা কীভাবে সিদ্ধান্ত নেব (ধরে নিই যে সমান পদ্ধতিটি সঠিকভাবে ওভাররাইড করা হয়েছে)?


2
জাভা 7+ দিয়ে আমার ধারণা, Objects.hashCode(collection)একটি নিখুঁত সমাধান হওয়া উচিত!
ডায়াবলো

3
@ ডায়াব্লো আমি মনে করি না যে এ প্রশ্নের কোনও উত্তর নেই - এই পদ্ধতিটি কেবল ফিরে আসে collection.hashCode()( hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/… )
cbreezier

উত্তর:


438

সেরা বাস্তবায়ন? এটি একটি কঠিন প্রশ্ন কারণ এটি ব্যবহারের প্যাটার্নের উপর নির্ভর করে।

প্রায় সব ক্ষেত্রেই যুক্তিযুক্ত ভাল প্রয়োগের বিষয়টি আইটেম 8 (দ্বিতীয় সংস্করণ) এর জোশ ব্লচের কার্যকর জাভাতে প্রস্তাবিত হয়েছিল । সেখানে সন্ধান করা সবচেয়ে ভাল কারণ লেখক সেখানে ব্যাখ্যা করেছেন কেন পদ্ধতিরটি ভাল।

একটি সংক্ষিপ্ত সংস্করণ

  1. একটি তৈরি করুন int resultএবং একটি অ-শূন্য মান নির্ধারণ করুন ।

  2. পদ্ধতিতে পরীক্ষিত প্রতিটি ক্ষেত্রের জন্য একটি হ্যাশ কোড গণনা করুন :fequals()c

    • ক্ষেত্র চ যদি একটি হয় boolean: গণনা (f ? 0 : 1);
    • ক্ষেত্র চ হয় তাহলে একটি byte, char, shortবা int: ক্যালকুলেট (int)f;
    • ক্ষেত্র চ যদি একটি হয় long: গণনা (int)(f ^ (f >>> 32));
    • ক্ষেত্র চ যদি একটি হয় float: গণনা Float.floatToIntBits(f);
    • যদি ক্ষেত্র চ একটি হয় double: Double.doubleToLongBits(f)প্রতিটি দীর্ঘ মানের মতো রিটার্ন মান গণনা ও পরিচালনা করে;
    • যদি ক্ষেত্র চ একটি অবজেক্ট হয় : hashCode()পদ্ধতির ফলাফল বা 0 যদি ব্যবহার করুন f == null;
    • যদি ক্ষেত্র চ এর একটি অ্যারে থাকে : প্রতিটি ক্ষেত্রকে পৃথক উপাদান হিসাবে দেখুন এবং একটি পুনরাবৃত্ত ফ্যাশনে হ্যাশ মান গণনা করুন এবং পরবর্তী বর্ণিত মানগুলি একত্র করুন।
  3. এর cসাথে হ্যাশ মানটি একত্রিত করুন result:

    result = 37 * result + c
  4. প্রত্যাবর্তন result

এর ফলে বেশিরভাগ ব্যবহারের পরিস্থিতিতে হ্যাশ মানগুলির সঠিক বিতরণ করা উচিত।


45
হ্যাঁ আমি 37 নম্বরটি কোথা থেকে এসেছে তা সম্পর্কে বিশেষভাবে আগ্রহী।
কিপ

17
আমি জোশ ব্লচের "কার্যকর জাভা" বইয়ের আইটেম 8 ব্যবহার করেছি।
dmeister

39
@dma_k মৌলিক সংখ্যার এবং পদ্ধতি এই উত্তর বর্ণিত ব্যবহার করার জন্য কারণ তা নিশ্চিত করার জন্য হয় কম্পিউটেড হ্যাশকোড অনন্য হতে হবে । অ-মৌলিক সংখ্যাগুলি ব্যবহার করার সময়, আপনি এটির গ্যারান্টি দিতে পারবেন না। আপনি কোন প্রধান নাম্বারটি পছন্দ করেন তা বিবেচনাধীন নয়, 37 নম্বর সম্পর্কে যাদুকর কিছুই নেই (খুব খারাপ 42 টি একটি প্রাথমিক সংখ্যা নয়, তাই?)
সাইমন ফোর্সবার্গ

34
@ সিমোনআন্ড্রে ফোর্সবার্গ ওয়েল, গণনা করা হ্যাশ কোড সর্বদা অনন্য হতে পারে না :) একটি হ্যাশকোড। তবে আমি ধারণাটি পেয়েছি: প্রাথমিক সংখ্যাটির কেবলমাত্র একটি গুণক রয়েছে, যখন নন-প্রাইমটিতে কমপক্ষে দুটি থাকে। এটি একই হ্যাশ, অর্থাৎ সংঘর্ষের কারণ হিসাবে গুণক অপারেটরের জন্য একটি অতিরিক্ত সংমিশ্রণ তৈরি করে।
dma_k


140

আপনি যদি ডেমিস্টারের প্রস্তাবিত কার্যকর জাভা প্রয়োগে খুশি হন তবে আপনি নিজের ঘূর্ণায়মান পরিবর্তে একটি লাইব্রেরি কল ব্যবহার করতে পারেন:

@Override
public int hashCode() {
    return Objects.hashCode(this.firstName, this.lastName);
}

এর জন্য com.google.common.base.Objects.hashCodeজাভা 7 ( java.util.Objects.hash) এর মধ্যে পেয়ারা ( ) বা স্ট্যান্ডার্ড লাইব্রেরি প্রয়োজন তবে একইভাবে কাজ করে।


8
যদি এগুলির ব্যবহার না করার কারও কাছে উপযুক্ত কারণ না থাকে তবে অবশ্যই কোনও ক্ষেত্রেই এটি ব্যবহার করা উচিত। (এটি আরও দৃ stronger়তর করে, যেমন এটি আইএমএইচও প্রণয়ন করা উচিত)) স্ট্যান্ডার্ড বাস্তবায়ন / গ্রন্থাগারগুলি ব্যবহারের জন্য সাধারণ যুক্তি প্রয়োগ হয় (সেরা অনুশীলন, ভাল পরীক্ষা করা, কম ত্রুটির প্রবণতা ইত্যাদি)।
কিসাকি

7
@ justin.hug তিনি আপনাকে বিভ্রান্ত বলে মনে করছেন। আপনার hashCodeযদি কাস্টম থাকে তবে আপনার কেবল ওভাররাইড করা উচিত equalsthese সম্পর্কিত ডকুমেন্টেশন তাদের আচরণ সম্পর্কে বেশ স্পষ্ট equals। একটি লাইব্রেরি বাস্তবায়ন আপনাকে সঠিক hashCodeবাস্তবায়নের বৈশিষ্ট্যগুলি কী তা জেনে বাধা দেওয়ার দাবি করে না - এই লাইব্রেরিগুলি আপনার ওভাররেড করা বেশিরভাগ ক্ষেত্রেই এই জাতীয় অনুসারী বাস্তবায়ন কার্যকর করে তোলেequals
বেকার 0

6
যে কোনও অ্যান্ড্রয়েড বিকাশকারী জাভা.ইটিল.অবজেক্টস শ্রেণীর দিকে নজর রাখার জন্য, এটি কেবলমাত্র এপিআই 19-এ প্রবর্তিত হয়েছিল, তাই আপনি কিটক্যাট বা তারপরে চালিয়ে যাচ্ছেন তা নিশ্চিত করুন অন্যথায় আপনি NoClassDefFoundError পাবেন।
অ্যান্ড্রু কেলি

3
সেরা উত্তর আইএমও, যদিও উদাহরণের মাধ্যমে আমি বরং java.util.Objects.hash(...)পেয়ারা com.google.common.base.Objects.hashCode(...)পদ্ধতির চেয়ে জেডিকে 7 পদ্ধতিটি বেছে নেব । আমি মনে করি বেশিরভাগ লোকেরা অতিরিক্ত নির্ভরতার চেয়ে মানক গ্রন্থাগারটি বেছে নেবে।
মাল্টে স্কোরুপা

2
যদি দুটি আর্গুমেন্ট বা ততোধিক যুক্তি থাকে এবং সেগুলির মধ্যে যদি একটি অ্যারে হয় তবে ফলাফলটি আপনি যা প্রত্যাশা করেছিলেন তা নাও হতে পারে কারণ hashCode()অ্যারেটির জন্য এটি কেবল তার java.lang.System.identityHashCode(...)
তারকাটকফ

59

Eclipse দ্বারা সরবরাহিত কার্যকারিতাটি ব্যবহার করা আরও ভাল যা একটি খুব ভাল কাজ করে এবং আপনি ব্যবসায়ের যুক্তি বিকাশে আপনার প্রচেষ্টা এবং শক্তি রাখতে পারেন।


4
+1 একটি ভাল ব্যবহারিক সমাধান। ডেমিস্টারের সমাধানটি আরও বিস্তৃত, তবে আমি যখন হ্যাশকোডগুলি নিজে লেখার চেষ্টা করি তখন আমি নালগুলি হ্যান্ডেল করতে ভুলে যাই।
কোয়ান্টাম

1
+1 কোয়ান্টাম 7 এর সাথে একমত, তবে আমি বলব যে গ্রহগ্রাহ দ্বারা উত্পাদিত বাস্তবায়ন কী করছে এবং এটি এর বাস্তবায়নের বিশদ কোথায় পেয়েছে তা বুঝতে পেরে এটি সত্যিই ভাল।
jwir3

15
দুঃখিত তবে "[কিছু আইডিই] দ্বারা সরবরাহিত কার্যকারিতা" জড়িত উত্তরগুলি সাধারণভাবে প্রোগ্রামিং ভাষার প্রসঙ্গে প্রাসঙ্গিক নয়। কয়েক ডজন আইডিই রয়েছে এবং এটি প্রশ্নের উত্তর দেয় না ... কারণ এটি অ্যালগরিদমিক সংকল্প সম্পর্কে আরও বেশি এবং সরাসরি সমান () প্রয়োগের সাথে সম্পর্কিত - কোনও আইডিই কিছু জানতে পারে না।
ড্যারেল টিগু

57

যদিও এটি Androidডকুমেন্টেশন (ওয়েব্যাক মেশিন) এবং গিথুবে আমার নিজস্ব কোডের সাথে লিঙ্কযুক্ত , এটি সাধারণভাবে জাভার পক্ষে কাজ করবে। আমার উত্তরটি কেবল কোড সহ dmeister এর উত্তরের একটি বর্ধিতাংশ যা পড়তে এবং বুঝতে খুব সহজ।

@Override 
public int hashCode() {

    // Start with a non-zero constant. Prime is preferred
    int result = 17;

    // Include a hash for each field.

    // Primatives

    result = 31 * result + (booleanField ? 1 : 0);                   // 1 bit   » 32-bit

    result = 31 * result + byteField;                                // 8 bits  » 32-bit 
    result = 31 * result + charField;                                // 16 bits » 32-bit
    result = 31 * result + shortField;                               // 16 bits » 32-bit
    result = 31 * result + intField;                                 // 32 bits » 32-bit

    result = 31 * result + (int)(longField ^ (longField >>> 32));    // 64 bits » 32-bit

    result = 31 * result + Float.floatToIntBits(floatField);         // 32 bits » 32-bit

    long doubleFieldBits = Double.doubleToLongBits(doubleField);     // 64 bits (double) » 64-bit (long) » 32-bit (int)
    result = 31 * result + (int)(doubleFieldBits ^ (doubleFieldBits >>> 32));

    // Objects

    result = 31 * result + Arrays.hashCode(arrayField);              // var bits » 32-bit

    result = 31 * result + referenceField.hashCode();                // var bits » 32-bit (non-nullable)   
    result = 31 * result +                                           // var bits » 32-bit (nullable)   
        (nullableReferenceField == null
            ? 0
            : nullableReferenceField.hashCode());

    return result;

}

সম্পাদনা

সাধারণত, আপনি যখন ওভাররাইড করবেন তখন আপনি ওভাররাইড hashcode(...)করতে চান equals(...)। সুতরাং যেগুলি ইতিমধ্যে বাস্তবায়ন করবে বা বাস্তবায়ন করেছে তাদের জন্য equalsএখানে আমার গিতুব থেকে একটি ভাল রেফারেন্স দেওয়া হয়েছে ...

@Override
public boolean equals(Object o) {

    // Optimization (not required).
    if (this == o) {
        return true;
    }

    // Return false if the other object has the wrong type, interface, or is null.
    if (!(o instanceof MyType)) {
        return false;
    }

    MyType lhs = (MyType) o; // lhs means "left hand side"

            // Primitive fields
    return     booleanField == lhs.booleanField
            && byteField    == lhs.byteField
            && charField    == lhs.charField
            && shortField   == lhs.shortField
            && intField     == lhs.intField
            && longField    == lhs.longField
            && floatField   == lhs.floatField
            && doubleField  == lhs.doubleField

            // Arrays

            && Arrays.equals(arrayField, lhs.arrayField)

            // Objects

            && referenceField.equals(lhs.referenceField)
            && (nullableReferenceField == null
                        ? lhs.nullableReferenceField == null
                        : nullableReferenceField.equals(lhs.nullableReferenceField));
}

1
অ্যান্ড্রয়েড ডকুমেন্টেশন এখন উপরের কোডটি আর অন্তর্ভুক্ত করে না, সুতরাং এখানে
ওয়েব্যাক

17

প্রথমে নিশ্চিত হয়ে নিন যে সমানগুলি সঠিকভাবে প্রয়োগ করা হয়েছে। থেকে একটি IBM DeveloperWorks নিবন্ধ :

  • প্রতিসামগ্রী: দুটি রেফারেন্সের জন্য, a এবং b, a.equals (b) এবং কেবলমাত্র b.equals (a)
  • রিফ্লেক্সিভিটি: সমস্ত নাল রেফারেন্সের জন্য, a.equals (a)
  • ট্রানজিটিভিটি: যদি a.equals (b) এবং b.equals (c) হয়, তবে a.equals (c)

তারপরে নিশ্চিত হয়ে নিন যে হ্যাশকোডের সাথে তাদের সম্পর্ক যোগাযোগটিকে সম্মান করে (একই নিবন্ধ থেকে):

  • হ্যাশকোড () সহ সামঞ্জস্যতা: দুটি সমান বস্তুর অবশ্যই হ্যাশকোড () মান থাকতে হবে

পরিশেষে একটি ভাল হ্যাশ ফাংশন আদর্শ হ্যাশ ফাংশন যোগাযোগ করার চেষ্টা করা উচিত ।


11

সম্পর্কে 8.blogspot.com, আপনি বলেছেন

যদি সমান () দুটি বস্তুর জন্য সত্য দেয়, তবে হ্যাশকোড () একই মানটি প্রদান করবে। যদি সমান () মিথ্যা ফেরত দেয় তবে হ্যাশকোড () এর বিভিন্ন মান দেওয়া উচিত

আমি আপনার সাথে একমত হতে পারে না। দুটি বস্তুর যদি একই হ্যাশকোড থাকে তবে এর অর্থ এই নয় যে তারা সমান।

যদি A সমান B হয় তবে আহাশকোড অবশ্যই বি.স্কোডের সমান

কিন্তু

যদি এ্যাশকোড বি.এইচস্কোডের সমান হয় তবে এর অর্থ এই নয় যে এ অবশ্যই বি এর সমান হবে


3
যদি (A != B) and (A.hashcode() == B.hashcode()), আমরা একে হ্যাশ ফাংশন সংঘর্ষ বলি। এর কারণ হ্যাশ ফাংশনের কোডোমেন সর্বদা সসীম হয়, তবে এটির ডোমেন সাধারণত হয় না। কোডোমেন যত বড়, সংঘর্ষ কম হওয়া উচিত। ভাল হ্যাশ ফাংশনটি বিশেষ কোডোমেন আকারে সর্বাধিক সম্ভাব্য অর্জনের সাথে বিভিন্ন অবজেক্টের জন্য বিভিন্ন হ্যাশ ফিরিয়ে দেয়। এটি খুব কমই যদিও সম্পূর্ণরূপে গ্যারান্টিযুক্ত হতে পারে।
ক্রিজিসটফ জাবোসস্কি

এটি কেবল ধূসর উপরের পোস্টে একটি মন্তব্য হওয়া উচিত। ভাল তথ্য তবে এটি সত্যই প্রশ্নের উত্তর দেয় না
ক্রিস্টোফার রুকিনস্কি

ভাল মন্তব্য তবে শব্দটি 'ভিন্ন ভিন্ন অবজেক্ট' ব্যবহার করার বিষয়ে সাবধানতা অবলম্বন করুন ... কারণ সমান () এবং এইভাবে হ্যাশকোড () বাস্তবায়ন কোনও ওও প্রসঙ্গে বিভিন্ন অবজেক্ট সম্পর্কে অগত্যা নয় তবে সাধারণত তাদের ডোমেন মডেলের উপস্থাপনা সম্পর্কে আরও বেশি থাকে (যেমন, দুটি লোকেরা যদি কোনও দেশের কোড এবং দেশের আইডি ভাগ করে নেয় তবে তারা একই হিসাবে বিবেচিত হতে পারে - যদিও এটি কোনও জেভিএম-এ দুটি পৃথক 'অবজেক্ট' হতে পারে - তারা 'সমান' এবং একটি হ্যাশকোডযুক্ত বলে বিবেচিত হয়) ...
ড্যারেল

7

আপনি যদি গ্রহনটি ব্যবহার করেন তবে আপনি উত্পাদন equals()এবং hashCode()ব্যবহার করতে পারেন :

উত্স -> হ্যাশকোড তৈরি করুন () এবং সমান ()।

এই ফাংশনটি ব্যবহার করে আপনি সিদ্ধান্ত নিতে পারেন আপনি কোন ক্ষেত্রগুলি সাম্যতা এবং হ্যাশ কোড গণনার জন্য ব্যবহার করতে চান এবং Eclipse সম্পর্কিত পদ্ধতি উত্পন্ন করে।


7

সেখানে একটি ভাল বাস্তবায়ন এর কার্যকরী জাভা এর hashcode()এবং equals()যুক্তি এ্যাপাচি কমন্স ল্যাঙ । চেকআউট হ্যাশকোডবিল্ডার এবং সমতুল্য বিল্ডার


1
আপনি যখনই সমান এবং হ্যাশকোড কল করেন তখন প্রতিবার এই আইপিএলের ক্ষয়ক্ষতিটি হ'ল (যদি না আপনার বস্তু অপরিবর্তনীয় হয় এবং আপনি হ্যাশ প্রাক্পম্প্ট করেন না), যা নির্দিষ্ট ক্ষেত্রে অনেক কিছু হতে পারে।
জেমস ম্যাকমাহন

এটি আমার প্রিয় পন্থা ছিল, সাম্প্রতিক অবধি। SharedKey OneToOne অ্যাসোসিয়েশনের জন্য একটি মানদণ্ড ব্যবহার করার সময় আমি স্ট্যাকওভারফ্লোআরারে দৌড়েছি। আরো বেশি Objectsবর্গ উপলব্ধ hash(Object ..args)& equals()উপর Java7 থেকে পদ্ধতি। এই JDK 1.7+ ব্যবহার করে যে কোনও অ্যাপ্লিকেশনের জন্য সুপারিশ করা হয়
ডায়াবলো

@ ডায়াবলো আমার ধারণা, আপনার সমস্যাটি অবজেক্ট গ্রাফের একটি চক্র ছিল এবং তারপরে আপনি বেশিরভাগ বাস্তবায়নের সাথে ভাগ্যের বাইরে যাবেন কারণ আপনাকে কিছু রেফারেন্স উপেক্ষা করতে হবে বা চক্রটি ভেঙে ফেলতে হবে (বাধ্যতামূলক IdentityHashMap)। FWIW আমি একটি আইডি-ভিত্তিক হ্যাশকোড ব্যবহার করি এবং সমস্ত সত্ত্বার সমান।
মার্টিনাস

6

অন্যান্য আরও বিস্তারিত উত্তর (কোডের মেয়াদে) সম্পূর্ণ করার জন্য একটি দ্রুত নোট:

আমি যদি জাভা-তে-তৈরি-একটি-হ্যাশ-টেবিল-ইন-জাভা এবং বিশেষত জেগুরু এফএকিউ প্রবেশের প্রশ্নটি বিবেচনা করি তবে আমি বিশ্বাস করি যে হ্যাশ কোডটি বিচার করা যেতে পারে এমন আরও কিছু মানদণ্ড হল:

  • সিঙ্ক্রোনাইজেশন (আলগো কি সমবর্তী অ্যাক্সেস সমর্থন করে বা না)?
  • নিরাপদ পুনরাবৃত্তি ব্যর্থ (আলগো কোনও সংগ্রহটি আবিষ্কার করে যা পুনরাবৃত্তির সময় পরিবর্তন হয়)
  • নাল মান (হ্যাশ কোড সমর্থনে নাল মান সমর্থন করে)

4

যদি আমি আপনার প্রশ্নটি সঠিকভাবে বুঝতে পারি তবে আপনার একটি কাস্টম সংগ্রহের ক্লাস রয়েছে (অর্থাত্ একটি নতুন শ্রেণি যা সংগ্রহ ইন্টারফেস থেকে প্রসারিত) এবং আপনি হ্যাশকোড () পদ্ধতিটি প্রয়োগ করতে চান।

যদি আপনার সংগ্রহ শ্রেণিটি অ্যাবস্ট্রাকলিস্টকে প্রসারিত করে, তবে আপনাকে এটি নিয়ে চিন্তিত হওয়ার দরকার নেই, ইতিমধ্যে সমান () এবং হ্যাশকোড () এর একটি বাস্তবায়ন রয়েছে যা সমস্ত বস্তুর মাধ্যমে পুনরাবৃত্তি করে এবং তাদের হ্যাশকোডগুলি () একসাথে যুক্ত করে কাজ করে।

   public int hashCode() {
      int hashCode = 1;
      Iterator i = iterator();
      while (i.hasNext()) {
        Object obj = i.next();
        hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
      }
  return hashCode;
   }

এখন আপনি যদি চান তবে নির্দিষ্ট শ্রেণীর জন্য হ্যাশ কোড গণনা করার সবচেয়ে ভাল উপায়, আমি সাধারণত আমি সমান পদ্ধতিতে ব্যবহার করি এমন সমস্ত ক্ষেত্রগুলি প্রক্রিয়া করতে ^ (বিটওয়াইজ এক্সক্লুসিভ বা) অপারেটরটি ব্যবহার করি:

public int hashCode(){
   return intMember ^ (stringField != null ? stringField.hashCode() : 0);
}

2

@ About8: সেখানে একটি দুর্দান্ত গুরুতর বাগ আছে।

Zam obj1 = new Zam("foo", "bar", "baz");
Zam obj2 = new Zam("fo", "obar", "baz");

একই হ্যাশকোড

আপনি সম্ভবত কিছু চান

public int hashCode() {
    return (getFoo().hashCode() + getBar().hashCode()).toString().hashCode();

(আপনি কি আজকাল জাভাতে সরাসরি ইন্টার থেকে হ্যাশকোড পেতে পারেন? আমার মনে হয় এটি কিছুটা স্ব-কাস্টিং করে .. এটি যদি হয় তবে টসস্ট্রিং এড়িয়ে যান, এটি কুৎসিত))


3
বাগ 88bbspsp.com দ্বারা দীর্ঘ উত্তরে রয়েছে - একটি স্ট্রিংগুলির সংমিশ্রণ থেকে হ্যাশকোড পাওয়া আপনাকে একটি হ্যাশ ফাংশন দেয় যা একই স্ট্রিং পর্যন্ত যুক্ত হওয়া কোনও স্ট্রিংয়ের সংমিশ্রনের জন্য একই।
স্কয়ারকোগ

1
সুতরাং এটি কি মেটা-আলোচনা এবং প্রশ্নের সাথে সম্পর্কিত নয়? ;-)
হুপ্পি

1
এটি প্রস্তাবিত উত্তরের একটি সংশোধন যার মোটামুটি উল্লেখযোগ্য ত্রুটি রয়েছে।
স্কয়ারকোগ

এটি একটি অত্যন্ত সীমাবদ্ধ বাস্তবায়ন
ক্রিস্টোফার রুকিনস্কি

আপনার বাস্তবায়ন সমস্যা এড়াতে এবং অন্য একটি পরিচয় করিয়ে দেয়; অদলবদল fooএবং barএকই দিকে নিয়ে যায় hashCode। আপনার toStringআফাইক সংকলন করে না, এবং যদি এটি হয় তবে এটি মারাত্মক অদক্ষ। এর মতো 109 * getFoo().hashCode() + 57 * getBar().hashCode()কিছু দ্রুত, সহজ এবং অযথা সংঘাতের জন্ম দেয়।
মার্টিনাস

2

আপনি যেমন সংগ্রহের জন্য বিশেষভাবে জিজ্ঞাসা করেছিলেন, আমি এমন একটি দিক যুক্ত করতে চাই যা অন্যান্য উত্তরগুলি এখনও উল্লেখ করেনি: একটি হ্যাশম্যাপ সংগ্রহের সাথে যুক্ত হওয়ার পরে তাদের কীগুলি তাদের হ্যাশকোড পরিবর্তন করবে বলে আশা করে না। পুরো উদ্দেশ্যকে পরাস্ত করবে ...


2

অ্যাপাচি কমন্স ইকুয়ালস বিল্ডার এবং হ্যাশকোডবিল্ডারে প্রতিবিম্বের পদ্ধতিগুলি ব্যবহার করুন ।


1
আপনি যদি এটি ব্যবহার করতে যাচ্ছেন তবে সচেতন হন যে প্রতিবিম্ব ব্যয়বহুল। আমি সতর্কতার সাথে কোড থ্রো কোড ছাড়াও কোনও কিছুর জন্য এটি ব্যবহার করব না।
জেমস ম্যাকমাহন

2

আমি চারপাশে একটি ছোট্ট মোড়ক ব্যবহার করি Arrays.deepHashCode(...)কারণ এটি প্যারামিটার হিসাবে সরবরাহ করা অ্যারেগুলি সঠিকভাবে পরিচালনা করে

public static int hash(final Object... objects) {
    return Arrays.deepHashCode(objects);
}

1

যে কোনও হ্যাশিং পদ্ধতি যা সম্ভাব্য পরিসরের তুলনায় সমানভাবে হ্যাশ মান বিতরণ করে তা হ'ল একটি ভাল বাস্তবায়ন। কার্যকর জাভা দেখুন ( http://books.google.com.au/books?id=ZZOiqZQIbRMC&dq=effective+java&pg=PP1&ots=UZMZ2siN25&sig=kR0n73DHJOn-D77qGj0wOxAxiZw&hl=en&res1Xi &res1X&res1X &&1 হ্যাশকোড বাস্তবায়নের জন্য সেখানে (আইটেম 9 আমি মনে করি ...)।


1

আমি ক্লাস অবজেক্টস থেকে গুগল কালেকশন লিব থেকে ইউটিলিটি পদ্ধতিগুলি ব্যবহার করা পছন্দ করি যা আমার কোড পরিষ্কার রাখতে আমাকে সহায়তা করে। আইডিই এর টেম্পলেট থেকে খুব প্রায়শই equalsএবং hashcodeপদ্ধতিগুলি তৈরি করা হয়, তাই সেগুলি পড়ার জন্য পরিষ্কার নয়।


1

এখানে আরও একটি জেডিকে 1.7+ সুপারক্লাস লজিকসের সাথে যোগাযোগের বিক্ষোভ প্রদর্শন করা হয়েছে। আমি এটিকে অবজেক্ট ক্লাসের হ্যাশকোড () হিসাবে হিসাবরক্ষক, খাঁটি জেডিকে নির্ভরতা এবং কোনও অতিরিক্ত ম্যানুয়াল কাজের সাথে বেশ দৃ .়প্রতিজ্ঞ হিসাবে দেখছি। দয়া করে নোট Objects.hash()নাল সহনশীল।

আমি কোনও equals()বাস্তবায়ন অন্তর্ভুক্ত করি নি তবে বাস্তবে আপনার অবশ্যই এটির প্রয়োজন হবে।

import java.util.Objects;

public class Demo {

    public static class A {

        private final String param1;

        public A(final String param1) {
            this.param1 = param1;
        }

        @Override
        public int hashCode() {
            return Objects.hash(
                super.hashCode(),
                this.param1);
        }

    }

    public static class B extends A {

        private final String param2;
        private final String param3;

        public B(
            final String param1,
            final String param2,
            final String param3) {

            super(param1);
            this.param2 = param2;
            this.param3 = param3;
        }

        @Override
        public final int hashCode() {
            return Objects.hash(
                super.hashCode(),
                this.param2,
                this.param3);
        }
    }

    public static void main(String [] args) {

        A a = new A("A");
        B b = new B("A", "B", "C");

        System.out.println("A: " + a.hashCode());
        System.out.println("B: " + b.hashCode());
    }

}

1

মান বাস্তবায়ন দুর্বল এবং এটি ব্যবহার করা অপ্রয়োজনীয় সংঘর্ষের দিকে পরিচালিত করে। ভাবুন ক

class ListPair {
    List<Integer> first;
    List<Integer> second;

    ListPair(List<Integer> first, List<Integer> second) {
        this.first = first;
        this.second = second;
    }

    public int hashCode() {
        return Objects.hashCode(first, second);
    }

    ...
}

এখন,

new ListPair(List.of(a), List.of(b, c))

এবং

new ListPair(List.of(b), List.of(a, c))

একই আছে hashCodeযেমন, 31*(a+b) + cজন্য ব্যবহার করা গুণক হিসাবে List.hashCodeএখানে পুনঃব্যবহৃত পায়। স্পষ্টতই, সংঘর্ষগুলি অনিবার্য, তবে অপ্রয়োজনীয় সংঘর্ষ উত্পাদন করা কেবল ... অযথা প্রয়োজন।

ব্যবহার সম্পর্কে যথেষ্ট স্মার্ট কিছুই নেই 31। তথ্য হারাতে এড়াতে গুণককে অবশ্যই বিজোড় হতে হবে (যে কোনও গুণকও অন্তত সর্বাধিক উল্লেখযোগ্য বিট হারান, চারটি গুণক দুটি হারান ইত্যাদি), যে কোনও বিজোড় গুণক ব্যবহারযোগ্য। ছোট গুণকরা দ্রুত গণনার দিকে পরিচালিত করতে পারে (জেআইটি শিফট এবং সংযোজন ব্যবহার করতে পারে), তবে যে গুণটি আধুনিক ইন্টেল / এএমডি তে কেবল তিনটি চক্রের বিলম্বিত রয়েছে, এটি খুব কমই গুরুত্বপূর্ণ। ছোট গুণকগুলি ছোট ইনপুটগুলির জন্য আরও সংঘর্ষের দিকে পরিচালিত করে, যা কখনও কখনও সমস্যা হতে পারে।

প্রাইম ব্যবহার করা অর্থহীন কারণ প্রাইমগুলির জেড / (2 ** 32) রিংয়ের কোনও অর্থ নেই।

সুতরাং, আমি এলোমেলোভাবে নির্বাচিত বড় বিজোড় নম্বর ব্যবহার করার প্রস্তাব দিই (কোনও প্রাইম নিতে নিরবচ্ছিন্ন)। যেমন i86 / amd64 সিপিইউগুলি একক স্বাক্ষরিত বাইটে অপারেটিং ফিটিংয়ের জন্য একটি সংক্ষিপ্ত নির্দেশনা ব্যবহার করতে পারে, তাই 109 এর মতো গুণকগুলির জন্য একটি ছোট গতির সুবিধা রয়েছে coll সংঘর্ষ হ্রাস করতে, 0x58a54cf5 এর মতো কিছু নিন।

বিভিন্ন জায়গায় বিভিন্ন গুণক ব্যবহার করা সহায়ক, তবে অতিরিক্ত কাজটি ন্যায়সঙ্গত করার পক্ষে সম্ভবত যথেষ্ট নয়।


0

হ্যাশ মানগুলির সংমিশ্রণের সময়, আমি সাধারণত সম্মিলন পদ্ধতি ব্যবহার করি যা বুস্ট সি ++ লাইব্রেরিতে ব্যবহৃত হয়, যথা:

seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);

এটি একটি এমনকি বিতরণ নিশ্চিত করার জন্য মোটামুটি ভাল কাজ করে। এই সূত্রটি কীভাবে কাজ করে সে সম্পর্কে কিছু আলোচনার জন্য, স্ট্যাক ওভারফ্লো পোস্টটি দেখুন: জাদুতে জাদু সংখ্যা :: হ্যাশ_কোম্বাইন

এখানে বিভিন্ন হ্যাশ ফাংশন সম্পর্কে একটি ভাল আলোচনা রয়েছে: http://burtleburtle.net/bob/hash/doobs.html


1
এটি জাভা সম্পর্কে একটি প্রশ্ন, সি ++ নয়।
ড্যানো

-1

একটি সাধারণ শ্রেণীর জন্য প্রায়শই সমান () প্রয়োগের মাধ্যমে পরীক্ষিত শ্রেণীর ক্ষেত্রগুলির উপর ভিত্তি করে হ্যাশকোড () প্রয়োগ করা সহজ।

public class Zam {
    private String foo;
    private String bar;
    private String somethingElse;

    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj == null) {
            return false;
        }

        if (getClass() != obj.getClass()) {
            return false;
        }

        Zam otherObj = (Zam)obj;

        if ((getFoo() == null && otherObj.getFoo() == null) || (getFoo() != null && getFoo().equals(otherObj.getFoo()))) {
            if ((getBar() == null && otherObj. getBar() == null) || (getBar() != null && getBar().equals(otherObj. getBar()))) {
                return true;
            }
        }

        return false;
    }

    public int hashCode() {
        return (getFoo() + getBar()).hashCode();
    }

    public String getFoo() {
        return foo;
    }

    public String getBar() {
        return bar;
    }
}

সর্বাধিক গুরুত্বপূর্ণ বিষয় হ্যাশকোড () এবং সমান () সামঞ্জস্য রাখা: যদি দুটি বস্তুর সমান () সমান হয়, তবে হ্যাশকোড () একই মানটি প্রদান করবে। যদি সমান () মিথ্যা ফেরত দেয় তবে হ্যাশকোড () এর বিভিন্ন মান প্রদান করা উচিত।


1
স্কয়ারকোগের মতো ইতিমধ্যে লক্ষ্য করা গেছে। তাহলে হ্যাশকোড দুই স্ট্রিং সংযুক্তকরণের থেকে একবার উৎপন্ন হয় এটা দুর্ঘটনায় এর জনসাধারণ জেনারেট করতে অত্যন্ত সহজ: ("abc"+""=="ab"+"c"=="a"+"bc"==""+"abc")। এটা মারাত্মক ত্রুটি। উভয় ক্ষেত্রের জন্য হ্যাশকোড মূল্যায়ন করা এবং তারপরে লিনিয়ার সংমিশ্রণ গণনা করা ভাল (অগ্রাধিকার সহগ হিসাবে প্রাইমগুলি ব্যবহার করা) ভাল would
ক্রিজিসটফ জাবোসস্কি

@ KrzysztofJabłoński ঠিক আছে। তদ্ব্যতীত, অদলবদল fooএবং barখুব অযথা সংঘাত উত্পাদন করে।
মার্টিনাস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.