मुझे जावा में बराबर और हैशकोड विधियों को ओवरराइड करने की आवश्यकता क्यों है?


383

हाल ही में मैंने इस डेवलपर वर्क्स दस्तावेज़ के माध्यम से पढ़ा ।

दस्तावेज़ सभी को परिभाषित करने hashCode()और equals()प्रभावी ढंग से और सही ढंग से है, हालांकि मैं यह पता लगाने में सक्षम नहीं हूं कि हमें इन दो तरीकों को ओवरराइड करने की आवश्यकता क्यों है।

मैं इन तरीकों को कुशलता से लागू करने का निर्णय कैसे ले सकता हूं?


4
प्रोग्रामिंग में दो महान लेख हैं। वास्तव में यह समझाते हुए: मुझे बराबरी पर कब आना चाहिए? और क्यों आपको बराबरी से आगे निकलने पर हमेशा हैशकोड को ओवरराइड करना चाहिए । (चेतावनी, स्वीकृत उत्तर वास्तव में गलत है।)
aioobe

केस ओवरराइड केवल बराबर होता है: दो समान ऑब्जेक्ट में अलग-अलग हैशकोड = समान ऑब्जेक्ट अलग-अलग बाल्टी (दोहराव) में जाते हैं। केस ओवरराइड केवल हैशकोड: दो समान ऑब्जेक्ट में एक ही हैशकोड = एक ही वस्तु एक ही बाल्टी (दोहराव) में जाएगी।
VdeX

जवाबों:


524

जोशुआ बलोच प्रभावी जावा पर कहते हैं

आपको हर वर्ग में हैशकोड () के बराबर होना चाहिए जो बराबरी से आगे बढ़ता है ()। ऐसा करने में विफलता के परिणामस्वरूप Object.hashCode () के लिए सामान्य अनुबंध का उल्लंघन होगा, जो आपकी कक्षा को हैशपॉप, हैशसेट और हैशटेबल सहित सभी हैश-आधारित संग्रहों के साथ ठीक से काम करने से रोकेगा।

आइए इसे एक उदाहरण से समझने की कोशिश करते हैं कि क्या होगा अगर हम ओवरराइड equals()किए बिना ओवरराइड करते हैं hashCode()और ए का उपयोग करने का प्रयास करते हैं Map

मान लें कि हमारे पास एक वर्ग है और यह कि दो वस्तुएं MyClassसमान हैं यदि उनके importantFieldबराबर है ( ग्रहण के साथ hashCode()और equals()उत्पन्न होता है)

public class MyClass {

    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    public String getEqualField() {
        return importantField;
    }

    public String getAnotherField() {
        return anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }

}

केवल ओवरराइड करें equals

यदि केवल equalsओवरराइड किया जाता है, तो जब आप myMap.put(first,someValue)पहले कॉल करते हैं तो कुछ बाल्टी में हैश होगा और जब आप कॉल myMap.put(second,someOtherValue)करेंगे तो यह कुछ अन्य बाल्टी (जैसा कि उनके पास एक अलग है hashCode) हैश होगा । इसलिए, हालांकि वे समान हैं, क्योंकि वे एक ही बाल्टी के लिए हैश नहीं करते हैं, नक्शा यह महसूस नहीं कर सकता है और दोनों ही नक्शे में रहते हैं।


यद्यपि equals()हम ओवरराइड hashCode()करते हैं तो ओवरराइड करना आवश्यक नहीं है , आइए देखें कि इस विशेष मामले में क्या होगा जहां हम जानते हैं कि दो वस्तुएं MyClassसमान हैं यदि उनके importantFieldबराबर है लेकिन हम ओवरराइड नहीं करते हैं equals()

केवल ओवरराइड करें hashCode

कल्पना कीजिए कि आपके पास यह है

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

यदि आप केवल तभी ओवरराइड hashCodeकरते हैं, जब आप कॉल करते हैं तो myMap.put(first,someValue)यह पहली बार लेता है, इसकी गणना करता है hashCodeऔर इसे दिए गए बाल्टी में संग्रहीत करता है। फिर जब आप myMap.put(second,someOtherValue)इसे कहते हैं तो इसे मैप डॉक्यूमेंटेशन के अनुसार दूसरे के साथ बदलना चाहिए क्योंकि वे समान हैं (व्यावसायिक आवश्यकता के अनुसार)।

लेकिन समस्या यह है कि बराबरी को फिर से परिभाषित नहीं किया गया था, इसलिए जब नक्शा हैश करता है secondऔर बाल्टी के माध्यम से यह देखता है कि क्या कोई वस्तु kऐसी है second.equals(k)जो सच है तो यह किसी भी तरह second.equals(first)से नहीं मिलेगी जैसा कि होगा false

आशा है कि यह स्पष्ट था


5
क्या आप कृपया थोड़ा और विस्तार कर सकते हैं, दूसरे मामले में, दूसरी वस्तु को दूसरी बाल्टी में क्यों जाना चाहिए?
हुसैन अख्तर वाहिद 'घौरी'

57
मुझे यह उत्तर पसंद नहीं है क्योंकि यह बताता है कि आप हैशकोड () को बिना बराबरी के ओवरराइड नहीं कर सकते (), जो कि बस सच है। आप कहते हैं कि आपका उदाहरण कोड ("ओवरहाइड केवल हैशकोड" भाग) काम नहीं करेगा क्योंकि आप अपनी दो वस्तुओं को समान रूप से परिभाषित करते हैं, लेकिन - क्षमा करें - यह परिभाषा केवल आपके सिर में है। आपके पहले उदाहरण में आपके पास समान हैशकोड के साथ दो समान-बराबर ऑब्जेक्ट हैं, और यह पूरी तरह से कानूनी है। तो इसका कारण आपको बराबरी करने की ज़रूरत है () इसलिए नहीं है क्योंकि आपने पहले ही हैशकोड () को ओवरराइड कर दिया है, बल्कि इसलिए कि आप अपनी "बराबर" परिभाषा को अपने सिर से कोड तक ले जाना चाहते हैं।
user2543253

11
if you think you need to override one, then you need to override both of themगलत है। hashCodeयदि आपकी कक्षा ओवरराइड करती है तो आपको ओवरराइड करने की आवश्यकता है equalsलेकिन रिवर्स सच नहीं है।
akhil_mittal

4
मुझे लगता है कि केवल हैशकोड () के साथ ही ओवरराइडिंग () के बिना ओवरराइड करना पूरी तरह से ठीक है । यह भी प्रभावी जावा में लिखा है : books.google.fr/…
जॉनी

2
@PhantomReference, ध्यान दें कि ओवरराइडिंग केवल equalsअनुबंध में उल्लिखित अनुबंध का उल्लंघन करेगा Object: "यदि दो ऑब्जेक्ट equals(Object)विधि के अनुसार समान हैं , तो hashCodeप्रत्येक ऑब्जेक्ट पर विधि को कॉल करने पर एक ही पूर्ण परिणाम उत्पन्न करना होगा।" निश्चित रूप से, सभी अनुबंधों के सभी भागों को सभी कोड में प्रयोग नहीं किया जाता है, लेकिन फिर भी, औपचारिक रूप से यह एक उल्लंघन है और मैं इसे बग होने की प्रतीक्षा कर रहा हूं।
aioobe

263

किसी वस्तु का हैशकोड मान जैसे संग्रह HashMapऔर HashSetउपयोग यह निर्धारित करने के लिए कि उसे संग्रह के अंदर कैसे संग्रहीत किया जाना चाहिए, और हैशकोड का उपयोग फिर से अपने संग्रह में वस्तु का पता लगाने के लिए किया जाता है।

पुनर्प्रकाशन पुनर्प्राप्ति दो-चरणीय प्रक्रिया है:

  1. सही बाल्टी खोजें (उपयोग करके hashCode())
  2. सही तत्व के लिए बाल्टी खोजें (उपयोग करके equals())

यहाँ एक छोटा सा उदाहरण है कि हमें क्यों ओवरराइड करना चाहिए equals()और hashcode()

एक ऐसे Employeeवर्ग पर विचार करें जिसके दो क्षेत्र हैं: आयु और नाम।

public class Employee {

    String name;
    int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof Employee))
            return false;
        Employee employee = (Employee) obj;
        return employee.getAge() == this.getAge()
                && employee.getName() == this.getName();
    }

    // commented    
    /*  @Override
        public int hashCode() {
            int result=17;
            result=31*result+age;
            result=31*result+(name!=null ? name.hashCode():0);
            return result;
        }
     */
}

अब एक क्लास बनाएं, Employeeऑब्जेक्ट को एक में डालें HashSetऔर टेस्ट करें कि वह ऑब्जेक्ट मौजूद है या नहीं।

public class ClientTest {
    public static void main(String[] args) {
        Employee employee = new Employee("rajeev", 24);
        Employee employee1 = new Employee("rajeev", 25);
        Employee employee2 = new Employee("rajeev", 24);

        HashSet<Employee> employees = new HashSet<Employee>();
        employees.add(employee);
        System.out.println(employees.contains(employee2));
        System.out.println("employee.hashCode():  " + employee.hashCode()
        + "  employee2.hashCode():" + employee2.hashCode());
    }
}

यह निम्नलिखित प्रिंट करेगा:

false
employee.hashCode():  321755204  employee2.hashCode():375890482

अब अप्रतिबंध hashcode()विधि, उसी को निष्पादित करें और आउटपुट होगा:

true
employee.hashCode():  -938387308  employee2.hashCode():-938387308

अब आप देख सकते हैं कि यदि दो वस्तुओं को समान माना जाता है, तो उनका हैशकोड भी समान होना चाहिए? अन्यथा, आप ऑब्जेक्ट को कभी भी पा नहीं पाएंगे क्योंकि क्लास ऑब्जेक्ट में डिफ़ॉल्ट हैशकोड विधि हमेशा वस्तुतः प्रत्येक ऑब्जेक्ट के लिए एक अद्वितीय संख्या के साथ आती है, भले ही equals()विधि इस तरह से ओवरराइड हो कि दो या दो से अधिक ऑब्जेक्ट को समान माना जाता है । इससे कोई फर्क नहीं पड़ता कि वस्तुएं कितनी समान हैं यदि उनका हैशकोड प्रतिबिंबित नहीं करता है। तो एक बार और: यदि दो वस्तुएं समान हैं, तो उनका हैशकोड भी समान होना चाहिए।


4
एकदम सही उदाहरण। स्पष्ट रूप से अंतर का प्रदर्शन किया!
कोडरपीसी

3
अच्छा समझाया @rajeev
VdeX

2
@VikasVerma बराबर वस्तु के पास समान हैशकोड होगा इसका मतलब असमान वस्तु के पास असमान हैशकोड नहीं होगा। क्या होगा अगर ऑब्जेक्ट वास्तव में अलग हैं, लेकिन उनका हैशकोड समान है?
रवि

1
बहुत अच्छी तरह से समझाया :)
राहुल

4
बहुत बेहतर जवाब तो स्वीकृत जवाब! धन्यवाद
driftwood

50

आपको हर वर्ग में हैशकोड () के बराबर होना चाहिए जो बराबरी से आगे बढ़ता है ()। ऐसा करने में विफलता के परिणामस्वरूप Object.hashCode () के लिए सामान्य अनुबंध का उल्लंघन होगा, जो आपकी कक्षा को हैशपॉप, हैशसेट और हैशटेबल सहित सभी हैश-आधारित संग्रहों के साथ ठीक से काम करने से रोकेगा।


जोशुआ बलोच द्वारा प्रभावी जावा    से

परिभाषित equals()और hashCode()लगातार करके , आप हैश-आधारित संग्रहों में कुंजियों के रूप में अपनी कक्षाओं की उपयोगिता में सुधार कर सकते हैं। जैसा कि हैशकोड के लिए एपीआई डॉक्टर बताते हैं: "यह विधि हैशटैब के लाभ के लिए समर्थित है जैसे कि उन लोगों द्वारा प्रदान की गई है java.util.Hashtable।"

इन विधियों को कुशलतापूर्वक लागू करने के तरीके के बारे में आपके प्रश्न का सबसे अच्छा उत्तर आपको प्रभावी जावा के अध्याय 3 को पढ़ने का सुझाव दे रहा है ।


4
यह सही उत्तर है। निश्चित रूप से, कोरोलरी होने के नाते, कि यदि आप कभी भी हैश-आधारित संग्रह में कक्षा का उपयोग नहीं करते हैं, तो इससे कोई फर्क नहीं पड़ता कि आपने लागू नहीं किया है hashCode()
स्लिम

1
अधिक जटिल मामलों में, आप कभी नहीं जानते हैं कि आपके द्वारा उपयोग किए जाने वाले संग्रह हैश का उपयोग कर रहे हैं, इसलिए "यह कोई फर्क नहीं पड़ता कि आपने हैशकोड लागू नहीं किया है" से दूर रहें
विक्टर सर्जेनको

1
क्या मैं बराबरी के (बिना) हैशकोड () को ओवरराइड कर सकता हूं?
जॉनी

@StasS, हाँ, इसके विपरीत जो स्वीकृत उत्तर कहता है। इस लेख के दूसरे भाग में स्पष्टीकरण देखें: जब आप बराबरी करते समय हमेशा
हैशकोड को

22

सीधे शब्दों में कहें, संदर्भ समानता के लिए ऑब्जेक्ट चेक में बराबर-विधि, जहां गुण के बराबर होने पर भी आपकी कक्षा के दो उदाहरण शब्दार्थ के समान हो सकते हैं। यह उदाहरण के लिए महत्वपूर्ण है जब अपनी वस्तुओं को एक कंटेनर में डालते हैं जो हैशपॉप और सेट की तरह बराबरी और हैशकोड का उपयोग करता है । मान लीजिए कि हमारे पास एक वर्ग है:

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }
}

हम एक ही आईडी से दो उदाहरण बनाते हैं :

Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");

बराबरी के बिना हमें मिल रहा है:

  • a.equals (b) गलत है क्योंकि वे दो अलग-अलग उदाहरण हैं
  • a.equals (a) सही है क्योंकि यह एक ही उदाहरण है
  • b.equals (b) सही है क्योंकि यह एक ही उदाहरण है

सही बात? वैसे हो सकता है, अगर आप यही चाहते हैं। लेकिन हम कहते हैं कि हम वस्तुओं को एक ही आईडी के साथ एक ही वस्तु चाहते हैं, भले ही यह दो अलग-अलग उदाहरण हो। हम बराबर (और हैशकोड) को ओवरराइड करते हैं:

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Foo) {
            return ((Foo)other).id.equals(this.id);   
        }
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

समान लागू करने और हैशकोड के लिए मैं अमरूद के सहायक तरीकों का उपयोग करने की सिफारिश कर सकता हूं


20

पहचान समानता नहीं है।

  • ऑपरेटर ==परीक्षण पहचान के बराबर होती है ।
  • equals(Object obj) विधि समानता परीक्षण की तुलना करती है (अर्थात हमें विधि को ओवरराइड करके समानता बताने की आवश्यकता है)

मुझे जावा में समान और हैशकोड विधियों को ओवरराइड करने की आवश्यकता क्यों है?

पहले हमें समान पद्धति के उपयोग को समझना होगा।

दो वस्तुओं के बीच अंतर की पहचान करने के लिए हमें समतुल्य विधि को ओवरराइड करना होगा।

उदाहरण के लिए:

Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.

------------------------------
Now I have overriden Customer class equals method as follows:
 @Override
    public boolean equals(Object obj) {
        if (this == obj)   // it checks references
            return true;
        if (obj == null) // checks null
            return false;
        if (getClass() != obj.getClass()) // both object are instances of same class or not
            return false;
        Customer other = (Customer) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference 
            return false;
        return true; 
    }
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2);  // returns true by our own logic

अब हैशकोड विधि आसानी से समझ सकते हैं।

हैशकोड , HashMap , HashSet जैसी डेटा संरचनाओं में ऑब्जेक्ट को स्टोर करने के लिए हैशकोड पूर्णांक बनाता है ।

मान लें कि हमने Customerऊपर की विधि के बराबर ओवरराइड की है,

customer1.equals(customer2);  // returns true by our own logic

डेटा संरचना के साथ काम करते समय जब हम बाल्टी में वस्तु को संग्रहीत करते हैं (बाल्टी फ़ोल्डर के लिए एक फैंसी नाम है)। अगर हम अंतर्निहित हैश तकनीक का उपयोग करते हैं, तो ऊपर के दो ग्राहकों के लिए यह दो अलग-अलग हैशकोड बनाता है। तो हम एक ही समान वस्तु को दो अलग-अलग स्थानों पर संग्रहीत कर रहे हैं। इस तरह के मुद्दों से बचने के लिए हमें निम्नलिखित सिद्धांतों के आधार पर हैशकोड विधि को भी ओवरराइड करना चाहिए।

  • संयुक्त राष्ट्र के बराबर उदाहरणों में समान हैशकोड हो सकता है।
  • समान उदाहरणों को समान हैशकोड वापस करना चाहिए।

3
यह वही है जो मैं पिछले 1 घंटे से देख रहा था। बहुत बढ़िया दोस्त (y)
अदनान

13

ठीक है, मुझे बहुत सरल शब्दों में अवधारणा की व्याख्या करें।

सबसे पहले एक व्यापक परिप्रेक्ष्य से हमारे पास संग्रह है, और हैशमैप संग्रह में डेटास्ट्रक्चर में से एक है।

यह समझने के लिए कि हमें बराबरी और हैशकोड पद्धति दोनों को ओवरराइड क्यों करना है, अगर पहले समझने की जरूरत है कि हैशमैप क्या है और क्या है।

हैशमैप एक डाटासट्रक्चर है जो एरे फैशन में डेटा के प्रमुख मूल्य जोड़े रखता है। आइए हम एक [] कहते हैं, जहां 'ए' में प्रत्येक तत्व एक महत्वपूर्ण मूल्य युग्म है।

इसके अलावा, उपरोक्त सरणी के प्रत्येक सूचकांक को एक सूची में एक से अधिक मान रखने वाली सूची से जोड़ा जा सकता है।

अब एक हैशमैप का उपयोग क्यों किया जाता है? अगर हमें एक बड़े सरणी के बीच में खोजना है तो प्रत्येक के माध्यम से खोजना अगर वे कुशल नहीं होंगे, तो हैश तकनीक हमें क्या बताती है जो सरणी को कुछ तर्क के साथ संसाधित करने देती है और उस तर्क के आधार पर तत्वों को समूह बनाती है अर्थात हैशिंग

उदाहरण: हमारे पास 1,2,3,4,5,6,7,8,9,10,11 हैं और हम एक हैश फ़ंक्शन मॉड 10 लागू करते हैं, इसलिए 1,11 को एक साथ समूहीकृत किया जाएगा। इसलिए अगर हमें पिछली सरणी में 11 को खोजना था तो हमें पूर्ण सरणी को पुनरावृत्त करना होगा लेकिन जब हम समूह बनाते हैं तो हम इसे पुनरावृत्ति के हमारे दायरे को सीमित करते हैं जिससे गति में सुधार होता है। उपरोक्त सभी सूचनाओं को संग्रहीत करने के लिए उपयोग किए जाने वाले डेटास्ट्रक्चर को सादगी के लिए 2 डी सरणी के रूप में सोचा जा सकता है

अब उपरोक्त हैशमैप के अलावा यह भी बताता है कि इसमें कोई डुप्लिकेट नहीं जोड़ा जाएगा। और यह मुख्य कारण है कि हमें बराबरी और हैशकोड को ओवरराइड करना होगा

इसलिए जब इसके ने कहा कि हैशमैप के आंतरिक कार्य की व्याख्या करें, तो हमें यह खोजने की आवश्यकता है कि हैशमैप के क्या तरीके हैं और यह उपरोक्त नियमों का पालन कैसे करता है, जो मैंने ऊपर बताया है

इसलिए हैशमप में पुट (के, वी) नामक विधि है, और हैशमप के अनुसार इसे सरणी को कुशलतापूर्वक वितरित करने और कोई डुप्लिकेट नहीं जोड़ने के उपरोक्त नियमों का पालन करना चाहिए।

इसलिए जो कुछ किया जाता है, वह पहले दिए गए कुंजी के लिए हैशकोड जनरेट करेगा ताकि यह तय किया जा सके कि किस इंडेक्स में जाना चाहिए। अगर उस इंडेक्स में कुछ भी मौजूद नहीं है, तो नया मूल्य वहां पर जोड़ा जाएगा, अगर कुछ पहले से ही वहां मौजूद है फिर उस सूचकांक पर लिंक की गई सूची के अंत के बाद नया मूल्य जोड़ा जाना चाहिए। लेकिन याद रखें कि हैशमाप के वांछित व्यवहार के अनुसार कोई डुप्लिकेट नहीं जोड़ा जाना चाहिए। तो आप दो पूर्णांक वस्तुओं आ = 11, bb = 11 कहते हैं। ऑब्जेक्ट क्लास से निकाली गई प्रत्येक वस्तु के रूप में, दो वस्तुओं की तुलना करने के लिए डिफ़ॉल्ट कार्यान्वयन यह है कि यह संदर्भ की तुलना करता है न कि ऑब्जेक्ट के अंदर मूल्यों की। इसलिए उपरोक्त मामले में, हालांकि शब्दार्थ दोनों समान रूप से समानता परीक्षण में विफल होंगे, और संभावना है कि दो ऑब्जेक्ट जो एक ही हैशकोड और एक ही मान मौजूद होंगे जिससे डुप्लिकेट बनेंगे। यदि हम ओवरराइड करते हैं तो हम डुप्लिकेट को जोड़ने से बच सकते हैं। आप भी देख सकते हैंविस्तार से काम कर रहा है

import java.util.HashMap;


public class Employee {

String name;
String mobile;
public Employee(String name,String mobile) {
    this.name=name;
    this.mobile=mobile;
}

@Override
public int hashCode() {
    System.out.println("calling hascode method of Employee");
    String str=this.name;
    Integer sum=0;
    for(int i=0;i<str.length();i++){
        sum=sum+str.charAt(i);
    }
    return sum;

}
@Override
public boolean equals(Object obj) {
    // TODO Auto-generated method stub
    System.out.println("calling equals method of Employee");
    Employee emp=(Employee)obj;
    if(this.mobile.equalsIgnoreCase(emp.mobile)){

        System.out.println("returning true");
        return true;
    }else{
        System.out.println("returning false");
        return false;
    }


}

public static void main(String[] args) {
    // TODO Auto-generated method stub

    Employee emp=new Employee("abc", "hhh");
    Employee emp2=new Employee("abc", "hhh");
    HashMap<Employee, Employee> h=new HashMap<>();
    //for (int i=0;i<5;i++){
        h.put(emp, emp);
        h.put(emp2, emp2);

    //}

    System.out.println("----------------");
    System.out.println("size of hashmap: "+h.size());


}

}

मुझे एक भ्रम है, जब हम हाशप के मामले में हैशकोड विधि को ओवरराइड करते हैं तो हमें बराबरी की विधि की आवश्यकता क्यों होती है? किसी भी मामले में, हैशमैप वैल्यू को बदल देता है यदि ऑब्जेक्ट का हैशकोड बराबर है।
विकास वर्मा

@VikasVerma hashmap किसी भी प्रकार के मान को प्रतिस्थापित नहीं करता है यदि ऑब्जेक्ट का हैशकोड समान है, तो यह केवल उस इंडेक्स को तय करता है जहां हैशमैप में नई जोड़ी गई वस्तु को रखा जाना है। अब सूचकांक में ऑब्जेक्ट हो सकते हैं, इसलिए डुप्लिकेट से बचने के लिए हम बराबर पद्धति को ओवरराइड करते हैं और हम परिभाषित करने के लिए तर्क लिखते हैं जब तुलना में दो वस्तुओं को समान माना जाता है। यदि ओवरराइड नहीं किया गया है, हालांकि समान मूल्य वाले ऑब्जेक्ट को संग्रहीत किया जाएगा क्योंकि दोनों वस्तुओं का संदर्भ अलग होगा
चेतन

11

hashCode() :

यदि आप केवल हैश-कोड विधि को ओवरराइड करते हैं तो कुछ भी नहीं होगा। क्योंकि यह हमेशा hashCodeएक ऑब्जेक्ट क्लास के रूप में प्रत्येक ऑब्जेक्ट के लिए नया लौटाता है ।

equals() :

यदि आप केवल समान विधि को ओवरराइड करते हैं, तो a.equals(b)यह सच है कि इसका मतलब hashCodeए और बी समान होना चाहिए लेकिन ऐसा नहीं होता है। क्योंकि आपने hashCodeविधि को ओवरराइड नहीं किया ।

नोट: hashCode()ऑब्जेक्ट क्लास का तरीका हमेशा hashCodeप्रत्येक ऑब्जेक्ट के लिए नया लौटाता है ।

इसलिए जब आपको हैशिंग आधारित संग्रह में अपनी वस्तु का उपयोग करने की आवश्यकता होती है, तो दोनों को ओवरराइड करना चाहिए equals()और hashCode()


यह दिलचस्प बिंदु है, केवल हैशकोड () के बारे में । यह पूरी तरह से ठीक है, है ना? या समस्याग्रस्त मामले भी हो सकते हैं?
जॉनी

1
यह एक भ्रामक और गलत उत्तर है। ओवरराइडिंग (= केवल =) हैशकोड () यह सुनिश्चित करता है कि संबंधित गुण के साथ संबंधित वर्ग की जिस वस्तु का तत्काल मूल्यांकन किया जा रहा है, वही हैश कोड है। लेकिन उपयोगी नहीं होगा क्योंकि उनमें से कोई भी एक दूसरे के बराबर नहीं होगा।
mfaisalhyder

8

जावा एक नियम डालता है

"यदि ऑब्जेक्ट ऑब्जेक्ट क्लास पद्धति के उपयोग से दो ऑब्जेक्ट समान हैं, तो हैशकोड विधि को इन दो ऑब्जेक्ट के लिए समान मान देना चाहिए।"

इसलिए, यदि हमारी कक्षा में हम ओवरराइड equals()करते हैं तो हमें hashcode()इस नियम का पालन करने के लिए विधि को भी ओवरराइड करना चाहिए । दोनों विधियों, equals()और hashcode(), का उपयोग किया जाता है Hashtable, उदाहरण के लिए, मानों को कुंजी-मूल्य जोड़े के रूप में संग्रहीत करने के लिए। यदि हम एक को नहीं बल्कि दूसरे को ओवरराइड करते हैं, तो एक संभावना है कि Hashtableहम जैसा चाहते हैं, वैसा काम नहीं कर सकते हैं, अगर हम एक कुंजी के रूप में ऐसी वस्तु का उपयोग करते हैं।


6

क्योंकि यदि आप उन्हें ओवरराइड नहीं करते हैं, तो आप ऑब्जेक्ट में डिफ़ॉल्ट निहितार्थ का उपयोग करेंगे।

यह देखते हुए कि समानता और हैकोड मानों को आम तौर पर इस बात की जानकारी की आवश्यकता होती है कि किसी वस्तु को बनाने के लिए उन्हें किसी भी ठोस अर्थ के लिए आपकी कक्षा में नए सिरे से परिभाषित करने की आवश्यकता होती है।


6

हमारी अपनी कक्षा की वस्तुओं को हाशप, हैशटेबल इत्यादि जैसे संग्रह में कुंजियों के रूप में उपयोग करने के लिए, हमें संग्रह की आंतरिक कार्यप्रणाली के बारे में जागरूकता रखकर दोनों तरीकों (हैशकोड (और बराबर) () को ओवरराइड करना चाहिए। अन्यथा, यह गलत परिणाम देता है जिसकी हमें उम्मीद नहीं है।


6

@Lombo के उत्तर में जोड़ना

आपको समतुल्य () से अधिक की आवश्यकता कब होगी?

ऑब्जेक्ट के बराबर () का डिफ़ॉल्ट कार्यान्वयन है

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

जिसका अर्थ है कि दो वस्तुओं को समान माना जाएगा, यदि उनके पास समान स्मृति पता होगा जो केवल तभी सत्य होगा जब आप किसी वस्तु की खुद से तुलना कर रहे हों।

लेकिन आप दो वस्तुओं पर एक ही विचार करना चाहते हैं यदि उनके पास एक या अधिक गुणों के लिए समान मूल्य हो (@Lombo के उत्तर में दिए गए उदाहरण को देखें)।

तो आप equals()इन स्थितियों में आगे निकल जाएंगे और आप समानता के लिए अपनी खुद की शर्तें देंगे।

मैंने सफलतापूर्वक बराबर लागू किया है () और यह बहुत अच्छा काम कर रहा है। क्यों वे हैशकोड () को भी ओवरराइड करने के लिए कह रहे हैं?

जब तक आप अपने उपयोगकर्ता-परिभाषित वर्ग पर "हैश" आधारित संग्रह का उपयोग नहीं करते हैं , यह ठीक है। लेकिन भविष्य में कुछ समय आप उपयोग करना चाह सकते हैं HashMapया HashSetयदि आप नहीं करते हैं overrideऔर हैशकोड () को "सही ढंग से लागू" करते हैं , तो ये हैश आधारित संग्रह इरादा के अनुसार काम नहीं करेंगे।

ओवरराइड केवल बराबर (@Lombo के उत्तर के अलावा)

myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?

सबसे पहले, HashMap जाँच करता है कि क्या हैशकोड secondसमान है first। केवल यदि मान समान हैं, तो यह एक ही बाल्टी में समानता की जांच करने के लिए आगे बढ़ेगा।

लेकिन यहाँ हैशकोड इन 2 वस्तुओं के लिए अलग है (क्योंकि उनके पास अलग-अलग मेमोरी एड्रेस है-डिफ़ॉल्ट कार्यान्वयन से)। इसलिए यह समानता की जांच करने के लिए भी परवाह नहीं करेगा।

यदि आपके पास आपके ओवरराइड समान () विधि के अंदर एक विराम बिंदु है, तो यह अलग-अलग हैशकोड में नहीं होगा। contains()चेक hashCode()और केवल अगर वे समान हैं तो यह आपकी equals()विधि को कॉल करेगा ।

हम सभी बाल्टियों में समानता के लिए हाशप की जाँच क्यों नहीं करवा सकते? इसलिए मेरे लिए हैशकोड () को ओवरराइड करने की कोई आवश्यकता नहीं है !!

फिर आपको हैश आधारित संग्रह की बात याद आ रही है। निम्नलिखित को धयान मे रखते हुए :

Your hashCode() implementation : intObject%9.

बाल्टी के रूप में संग्रहीत कुंजी निम्नलिखित हैं।

Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...

कहो, आप जानना चाहते हैं कि क्या मानचित्र में कुंजी 10 है। क्या आप सभी बाल्टियों को खोजना चाहते हैं? या क्या आप केवल एक बाल्टी खोजना चाहेंगे?

हैशकोड के आधार पर, आप यह पहचानेंगे कि यदि 10 मौजूद है, तो यह 1 बाल्टी में मौजूद होना चाहिए। इसलिए केवल बाल्टी 1 की खोज की जाएगी !!


5
class A {
    int i;
    // Hashing Algorithm
    if even number return 0 else return 1
    // Equals Algorithm,
    if i = this.i return true else false
}
  • डाल ('कुंजी', 'मूल्य') hashCode()बाल्टी का निर्धारण करने के लिए उपयोग करके हैश मूल्य की गणना करेगा और यह जानने के लिए equals()विधि का उपयोग करता है कि क्या मूल्य पहले से ही बाल्टी में मौजूद है। यदि इसे जोड़ा नहीं जाता है तो इसे वर्तमान मूल्य के साथ बदल दिया जाएगा
  • get ('की' hashCode()) पहले Entry (बकेट) equals()खोजने के लिए और Entry में वैल्यू ज्ञात करने के लिए उपयोग करेगा

यदि दोनों को ओवरराइड किया जाता है,

नक्शा < >

Map.Entry 1 --> 1,3,5,...
Map.Entry 2 --> 2,4,6,...

अगर बराबरी की मनाही नहीं है

नक्शा < >

Map.Entry 1 --> 1,3,5,...,1,3,5,... // Duplicate values as equals not overridden
Map.Entry 2 --> 2,4,6,...,2,4,..

अगर हैशकोड ओवरराइड नहीं है

नक्शा < >

Map.Entry 1 --> 1
Map.Entry 2 --> 2
Map.Entry 3 --> 3
Map.Entry 4 --> 1
Map.Entry 5 --> 2
Map.Entry 6 --> 3 // Same values are Stored in different hasCodes violates Contract 1
So on...

हैशकोड समान अनुबंध

  1. समान विधि के अनुसार दो कुंजी समान हैशकोड उत्पन्न करना चाहिए
  2. समान हैशकोड उत्पन्न करने वाली दो कुंजी समान होने की आवश्यकता नहीं है (उपरोक्त उदाहरण में सभी संख्याएँ समान हैश कोड उत्पन्न करती हैं)

4

काले रंग में एक बाल्टी में गेंदों के संग्रह पर विचार करें। आपका काम निम्न प्रकार से उन गेंदों को रंगना है और उपयुक्त खेल के लिए इसका उपयोग करना है,

टेनिस के लिए - पीला, लाल। क्रिकेट के लिए - सफेद

अब बाल्टी में तीन रंगों येलो, रेड और व्हाइट में बॉल हैं। और वह अब आपने रंग किया केवल आप जानते हैं कि कौन सा रंग किस खेल के लिए है।

गेंदों को रंग देना - हैशिंग। खेल के लिए गेंद का चयन - बराबर

अगर आपने रंग जमा दिया और कोई एक गेंद को क्रिकेट या टेनिस के लिए चुनता है तो वे रंग को पसंद नहीं करेंगे !!!


4

मैं स्पष्टीकरण में देख रहा था "यदि आप केवल हैशकोड को ओवरराइड करते हैं तो जब आप कॉल करते हैं तो myMap.put(first,someValue)यह पहले लेता है, इसके हैशकोड की गणना करता है और इसे दिए गए बाल्टी में संग्रहीत करता है। फिर जब आप कॉल करते हैं।myMap.put(first,someOtherValue) इसे इसे मैप डॉक्यूमेंटेशन के अनुसार दूसरे के साथ पहले स्थान पर होना चाहिए। (हमारी परिभाषा के अनुसार)। " :

मुझे लगता है कि जब हम इसमें जोड़ रहे हैं, तो दूसरा समय myMap तो यह 'दूसरी' वस्तु होनी चाहिएmyMap.put(second,someOtherValue)


4

1) सामान्य गलती नीचे दिए गए उदाहरण में दिखाई गई है।

public class Car {

    private String color;

    public Car(String color) {
        this.color = color;
    }

    public boolean equals(Object obj) {
        if(obj==null) return false;
        if (!(obj instanceof Car))
            return false;   
        if (obj == this)
            return true;
        return this.color.equals(((Car) obj).color);
    }

    public static void main(String[] args) {
        Car a1 = new Car("green");
        Car a2 = new Car("red");

        //hashMap stores Car type and its quantity
        HashMap<Car, Integer> m = new HashMap<Car, Integer>();
        m.put(a1, 10);
        m.put(a2, 20);
        System.out.println(m.get(new Car("green")));
    }
}

ग्रीन कार नहीं मिली है

2. हैशकोड के कारण समस्या ()

समस्या अप्रभावित विधि के कारण होती है hashCode()। के बीच अनुबंध equals()और hashCode()है:

  1. यदि दो ऑब्जेक्ट समान हैं, तो उनके पास समान हैश कोड होना चाहिए।
  2. यदि दो वस्तुओं का समान हैश कोड है, तो वे समान हो सकते हैं या नहीं भी हो सकते हैं।

    public int hashCode(){  
      return this.color.hashCode(); 
    }

4

वैल्यू ऑब्जेक्ट्स का उपयोग करते समय यह उपयोगी है । निम्नलिखित पोर्टलैंड पैटर्न रिपॉजिटरी से एक अंश है :

मूल्य वस्तुओं के उदाहरण संख्या, दिनांक, मुद्राएं और तार जैसी चीजें हैं। आमतौर पर, वे छोटी वस्तुएं होती हैं जो काफी व्यापक रूप से उपयोग की जाती हैं। उनकी पहचान उनकी वस्तु पहचान के बजाय उनके राज्य पर आधारित है। इस तरह, आपके पास एक ही वैचारिक मूल्य की कई प्रतियां हो सकती हैं।

इसलिए मेरे पास 16 जनवरी 1998 की तारीख का प्रतिनिधित्व करने वाली एक वस्तु की कई प्रतियां हो सकती हैं। इनमें से कोई भी प्रति एक दूसरे के बराबर होगी। इस तरह की एक छोटी सी वस्तु के लिए, नए लोगों को बनाने और तारीख का प्रतिनिधित्व करने के लिए किसी एक वस्तु पर भरोसा करने के बजाय उन्हें स्थानांतरित करना अक्सर आसान होता है।

एक मान ऑब्जेक्ट हमेशा जावा (या = स्मालटाक में) में असमानता () को ओवरराइड करना चाहिए। (ओवरहेडकोड ​​() के रूप में अच्छी तरह से याद रखें।)


3

मान लें कि आपके पास वर्ग (ए) है जो दो अन्य (बी) (सी) को एकत्र करता है, और आपको हैशटेबल के अंदर (ए) के उदाहरणों को संग्रहीत करने की आवश्यकता है। डिफ़ॉल्ट कार्यान्वयन केवल उदाहरणों को अलग करने की अनुमति देता है, लेकिन (बी) और (सी) द्वारा नहीं। तो A के दो उदाहरण बराबर हो सकते हैं, लेकिन डिफ़ॉल्ट रूप से आप उनकी तुलना सही तरीके से नहीं कर पाएंगे।


3

विधियाँ समतुल्य और हैशकोड ऑब्जेक्ट क्लास में परिभाषित हैं। डिफ़ॉल्ट रूप से यदि बराबर विधि सही हो जाती है, तो सिस्टम आगे जाकर हैश कोड के मूल्य की जांच करेगा। यदि 2 वस्तुओं का हैश कोड भी एक ही है तो वस्तुओं को समान माना जाएगा। इसलिए यदि आप केवल समतुल्य विधि को ओवरराइड करते हैं, तो भले ही ओवरराइड बराबरी विधि 2 वस्तुओं को समान होने का संकेत देती है, सिस्टम परिभाषित हैशकोड इंगित नहीं कर सकता है कि 2 ऑब्जेक्ट समान हैं। इसलिए हमें हैश कोड को भी ओवरराइड करना होगा।


यदि समान पद्धति सही है, तो हैशकोड की जाँच करने की कोई आवश्यकता नहीं है। यदि दो वस्तुओं के अलग-अलग हैशकोड हैं, तो, एक को कॉल करने के लिए बिना उन्हें अलग-अलग मानने में सक्षम होना चाहिए। इसके अलावा, ज्ञान कि किसी सूची में किसी भी चीज़ का कोई विशेष हैश कोड नहीं है, का अर्थ है कि सूची की कोई भी चीज़ उस हैश कोड के साथ nay ऑब्जेक्ट से मेल नहीं खा सकती है। एक साधारण उदाहरण के रूप में, यदि किसी के पास उन वस्तुओं की एक सूची है जिनके हैश कोड भी संख्याएँ हैं, और वस्तुओं की एक सूची जहाँ वे विषम संख्याएँ हैं, तो कोई भी वस्तु जिसका हैश कोड एक समान संख्या नहीं है, दूसरी सूची में होगी।
सुपरकैट

यदि किसी के पास दो ऑब्जेक्ट्स X और Y हैं, जिनके "बराबर" तरीकों से उनका मिलान हुआ है, लेकिन X का हैश कोड एक सम संख्या है और Y का हैश कोड एक विषम संख्या है, जैसा कि ऊपर वर्णित एक संग्रह है कि ऑब्जेक्ट Y का हैश कोड विषम और संग्रहीत था यह दूसरी सूची में ऑब्जेक्ट X के लिए एक मैच खोजने में सक्षम नहीं होगा। यह देखेगा कि X का हैश कोड भी था, और चूंकि दूसरी सूची में समान-हैश कोड के साथ कोई ऑब्जेक्ट नहीं है, इसलिए यह परेशान नहीं करेगा कुछ के लिए वहाँ खोज करने के लिए जो X से मेल खाता है, भले ही Y, X से मेल खाए। आपको क्या कहना चाहिए ...
Supercat

... यह होगा कि कई संग्रह उन चीजों की तुलना करने से बचेंगे जिनके हैश कोड का अर्थ होगा कि वे समान नहीं हो सकते। दो ऑब्जेक्ट्स जिनके हैश कोड अज्ञात हैं, को देखते हुए उनकी तुलना अपने हैश कोड्स की तुलना में सीधे करना तेजी से होता है, इसलिए इस बात की कोई गारंटी नहीं है कि जो चीजें असमान हैश कोड की रिपोर्ट करती हैं true, लेकिन उनके लिए रिटर्न equalsको मिलान के रूप में नहीं माना जाएगा। दूसरी ओर, अगर संग्रह में यह नोटिस आता है कि चीजों में समान हैश कोड नहीं हो सकता है, तो संभवत: वे नोटिस नहीं करेंगे कि वे समान हैं।
सुपरकैट

3

जावा में बराबर और हैशकोड तरीके

वे java.lang.Object क्लास के तरीके हैं जो सभी वर्गों (कस्टम कक्षाओं के साथ-साथ जावा एपीआई में परिभाषित अन्य) की सुपर क्लास है।

कार्यान्वयन:

सार्वजनिक बूलियन बराबर (ऑब्जेक्ट obj)

सार्वजनिक int हैशकोड ()

यहां छवि विवरण दर्ज करें

सार्वजनिक बूलियन बराबर (ऑब्जेक्ट obj)

यह विधि बस जाँचती है कि क्या दो ऑब्जेक्ट x और y एक ही ऑब्जेक्ट को संदर्भित करते हैं। यानी यह जाँचता है कि क्या x == y है।

यह प्रतिवर्त है: किसी भी संदर्भ मूल्य x के लिए, x.equals (x) को सही लौटना चाहिए।

यह सममित है: किसी भी संदर्भ मानों के लिए x और y, x.equals (y) सही होना चाहिए और यदि केवल y.equals (x) सही लौटाता है।

यह सकर्मक है: किसी भी संदर्भ मानों के लिए x, y और z, यदि x.equals (y) सही और y.equals (z) सही लौटाता है, तो x.equals (z) सही लौटना चाहिए।

यह सुसंगत है: किसी भी संदर्भ मानों के लिए x और y, x.equals (y) के कई इनवॉइस लगातार सत्य होते हैं या लगातार झूठे होते हैं, बशर्ते कि वस्तु पर बराबरी की तुलना में उपयोग की गई कोई भी जानकारी संशोधित न हो।

किसी भी गैर-शून्य संदर्भ मान x के लिए, x.equals (नल) को गलत लौटना चाहिए।

सार्वजनिक int हैशकोड ()

यह विधि उस ऑब्जेक्ट के लिए हैश कोड मान लौटाती है जिस पर यह विधि लागू होती है। यह विधि हैश कोड मान को एक पूर्णांक के रूप में लौटाती है और हैशटेबल, हैशमैप, हैशसेट आदि जैसे हैशिंग आधारित संग्रह वर्गों के लाभ के लिए समर्थित है। इस पद्धति को हर वर्ग में ओवरराइड किया जाना चाहिए जो समान पद्धति को ओवरराइड करता है।

हैशकोड का सामान्य अनुबंध है:

जब भी जावा एप्लिकेशन के निष्पादन के दौरान इसे एक से अधिक बार एक ही ऑब्जेक्ट पर लागू किया जाता है, तो हैशकोड विधि को लगातार एक ही पूर्णांक को वापस करना होगा, बशर्ते वस्तु पर तुलना में उपयोग की गई कोई भी जानकारी संशोधित न हो।

इस पूर्णांक को एक अनुप्रयोग के एक निष्पादन से एक ही अनुप्रयोग के दूसरे निष्पादन के अनुरूप नहीं रहना चाहिए।

यदि दो ऑब्जेक्ट समान (ऑब्जेक्ट) विधि के अनुसार समान हैं, तो दो ऑब्जेक्ट्स में से प्रत्येक पर हैशकोड विधि को कॉल करके एक ही पूर्णांक परिणाम का उत्पादन करना होगा।

यह आवश्यक नहीं है कि यदि दो वस्तुएं समान (java.lang.Object) विधि के अनुसार असमान हैं, तो दो वस्तुओं में से प्रत्येक पर हैशकोड विधि को कॉल करके अलग पूर्णांक परिणाम उत्पन्न करना होगा। हालांकि, प्रोग्रामर को यह पता होना चाहिए कि असमान वस्तुओं के लिए अलग पूर्णांक परिणाम बनाने से हैशटेबल्स के प्रदर्शन में सुधार हो सकता है।

समान वस्तुओं को समान हैश कोड का उत्पादन करना चाहिए जब तक वे समान हैं, हालांकि असमान वस्तुओं को अलग-अलग हैश कोड का उत्पादन करने की आवश्यकता नहीं है।

संसाधन:

JavaRanch

चित्र


चित्र (वीडियो लिंक) निजी मोड में है। यह देखने के लिए सार्वजनिक करें।
उदयकिरण पुलिपति

2

नीचे दिए गए उदाहरण में, यदि आप व्यक्ति वर्ग में बराबर या हैशकोड के लिए ओवरराइड टिप्पणी करते हैं, तो यह कोड टॉम के आदेश को देखने में विफल होगा। हैशकोड के डिफ़ॉल्ट कार्यान्वयन का उपयोग करने से हैशटेबल लुक्स में विफलताएं हो सकती हैं।

मेरे पास जो कुछ भी है वह एक सरलीकृत कोड है जो व्यक्ति द्वारा व्यक्ति के आदेश को खींचता है। व्यक्ति को हैशटेबल में एक कुंजी के रूप में उपयोग किया जा रहा है।

public class Person {
    String name;
    int age;
    String socialSecurityNumber;

    public Person(String name, int age, String socialSecurityNumber) {
        this.name = name;
        this.age = age;
        this.socialSecurityNumber = socialSecurityNumber;
    }

    @Override
    public boolean equals(Object p) {
        //Person is same if social security number is same

        if ((p instanceof Person) && this.socialSecurityNumber.equals(((Person) p).socialSecurityNumber)) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int hashCode() {        //I am using a hashing function in String.java instead of writing my own.
        return socialSecurityNumber.hashCode();
    }
}


public class Order {
    String[]  items;

    public void insertOrder(String[]  items)
    {
        this.items=items;
    }

}



import java.util.Hashtable;

public class Main {

    public static void main(String[] args) {

       Person p1=new Person("Tom",32,"548-56-4412");
        Person p2=new Person("Jerry",60,"456-74-4125");
        Person p3=new Person("Sherry",38,"418-55-1235");

        Order order1=new Order();
        order1.insertOrder(new String[]{"mouse","car charger"});

        Order order2=new Order();
        order2.insertOrder(new String[]{"Multi vitamin"});

        Order order3=new Order();
        order3.insertOrder(new String[]{"handbag", "iPod"});

        Hashtable<Person,Order> hashtable=new Hashtable<Person,Order>();
        hashtable.put(p1,order1);
        hashtable.put(p2,order2);
        hashtable.put(p3,order3);

       //The line below will fail if Person class does not override hashCode()
       Order tomOrder= hashtable.get(new Person("Tom", 32, "548-56-4412"));
        for(String item:tomOrder.items)
        {
            System.out.println(item);
        }
    }
}

2

स्ट्रिंग वर्ग और आवरण वर्गों के विभिन्न कार्यान्वयन है equals()औरhashCode() ऑब्जेक्ट क्लास की तुलना में तरीके हैं। ऑब्जेक्ट क्लास के समतुल्य () विधि वस्तुओं के संदर्भों की तुलना करती है, सामग्री की नहीं। हैशकोड () ऑब्जेक्ट क्लास का तरीका हर एक ऑब्जेक्ट के लिए अलग-अलग हैशकोड देता है, चाहे कंटेंट समान हो।

जब आप मानचित्र संग्रह का उपयोग करते हैं तो यह समस्या पैदा करता है और कुंजी स्थायी प्रकार, स्ट्रिंगबफ़र / बिल्डर प्रकार की होती है। चूँकि वे स्ट्रिंग क्लास के बराबर () और हैशकोड () के बराबर नहीं होते हैं, जब आप दोनों समान सामग्री होते हुए भी दो अलग-अलग ऑब्जेक्ट्स की तुलना करते हैं, तो बराबर () गलत हो जाएगा। यह उसी सामग्री कुंजी को संग्रहीत करते हुए हैश मैप बनाएगा। समान सामग्री कुंजियों को संग्रहीत करने का मतलब है कि यह मैप के नियम का उल्लंघन कर रहा है क्योंकि मैप डुप्लिकेट कुंजियों को बिल्कुल भी अनुमति नहीं देता है। इसलिए आप अपनी कक्षा में बराबर () के साथ-साथ हैशकोड () विधियों को ओवरराइड करते हैं और कार्यान्वयन प्रदान करते हैं (IDE इन विधियों को उत्पन्न कर सकता है) ताकि वे स्ट्रिंग के बराबर () और हैशकोड () के समान काम करें और एक ही समय की कुंजी को रोकें।

आपको हैशकोड () पद्धति को समतुल्य () के साथ ओवरराइड करना होगा क्योंकि हैशकोड के अनुसार बराबरी () काम करती है।

समतुल्य हैशकोड () पद्धति के साथ समतुल्य () बराबरी () हैशकोड () अनुबंध को बनाए रखने में मदद करता है: "यदि दो वस्तुएं समान हैं, तो उनके पास समान हैश कोड होना चाहिए।"

आपको हैशकोड () के लिए कस्टम कार्यान्वयन लिखने की आवश्यकता कब है?

जैसा कि हम जानते हैं कि हाशप का आंतरिक कार्य हाशिंग के सिद्धांत पर है। कुछ बाल्टियाँ हैं जहाँ एंट्रीसेट्स जमा हो जाते हैं। आप अपनी आवश्यकता के अनुसार हैशकोड () कार्यान्वयन को अनुकूलित करते हैं ताकि समान श्रेणी की वस्तुओं को एक ही सूचकांक में संग्रहीत किया जा सके। जब आप put(k,v)विधि का उपयोग करके मानचित्र संग्रह में मूल्यों को संग्रहीत करते हैं , तो पुट का आंतरिक कार्यान्वयन होता है ():

put(k, v){
hash(k);
index=hash & (n-1);
}

मीन्स, यह इंडेक्स बनाता है और इंडेक्स विशेष कुंजी ऑब्जेक्ट के हैशकोड के आधार पर उत्पन्न होता है। इसलिए इस विधि को अपनी आवश्यकता के अनुसार हैशकोड जनरेट करें क्योंकि उसी हैशकोड एंट्रीसेट को उसी बाल्टी या इंडेक्स में संग्रहीत किया जाएगा।

बस!


1

hashCode()विधि का उपयोग किसी दिए गए ऑब्जेक्ट के लिए एक अद्वितीय पूर्णांक प्राप्त करने के लिए किया जाता है। यह पूर्णांक बाल्टी स्थान का निर्धारण करने में, जब इस वस्तु कुछ में रखने की ज़रूरत हो के लिए प्रयोग किया जाता है HashTable, HashMapडेटा संरचना की तरह। डिफ़ॉल्ट रूप से, ऑब्जेक्ट की hashCode()विधि रिटर्न और मेमोरी एड्रेस का पूर्णांक प्रतिनिधित्व जहां ऑब्जेक्ट संग्रहीत होता है।

hashCode()वस्तुओं की विधि का उपयोग तब किया जाता है जब हम उन्हें एक में सम्मिलित करते हैं HashTable, HashMapया HashSet। के बारे में अधिकHashTablesसंदर्भ के लिए Wikipedia.org पर ।

मानचित्र डेटा संरचना में किसी भी प्रविष्टि को सम्मिलित करने के लिए, हमें कुंजी और मान दोनों चाहिए। यदि कुंजी और मान दोनों उपयोगकर्ता डेटा प्रकार परिभाषित करते हैं, hashCode()तो कुंजी का निर्धारण यह निर्धारित किया जाएगा कि वस्तु को आंतरिक रूप से कहाँ संग्रहीत किया जाए। जब ऑब्जेक्ट को मैप से भी देखने की आवश्यकता होती है, तो कुंजी का हैश कोड निर्धारित किया जाएगा कि ऑब्जेक्ट को कहां खोजना है।

हैश कोड केवल एक निश्चित "क्षेत्र" (या सूची, बाल्टी आदि) को आंतरिक रूप से इंगित करता है। चूंकि अलग-अलग प्रमुख ऑब्जेक्ट संभावित रूप से एक ही हैश कोड हो सकते हैं, हैश कोड ही कोई गारंटी नहीं है कि सही कुंजी मिली है। HashTableफिर इस क्षेत्र (एक ही हैश कोड के साथ सभी चाबियाँ) iterates और चाबी का उपयोग करता है equals()सही कुंजी खोजने के लिए विधि। एक बार सही कुंजी मिल जाने पर, उस कुंजी के लिए संग्रहित वस्तु वापस आ जाती है।

इसलिए, जैसा कि हम देख सकते हैं, भंडारण करते समय और जब वस्तुओं को एक में देखा जाता है, तो संयोजन hashCode()और equals()विधियों का उपयोग किया जाता है HashTable

टिप्पणियाँ:

  1. हमेशा किसी वस्तु के समान गुण उत्पन्न करने के लिए hashCode()और equals()दोनों का उपयोग करें। जैसा कि हमारे मामले में, हमने कर्मचारी आईडी का उपयोग किया है।

  2. equals() सुसंगत होना चाहिए (यदि वस्तुओं को संशोधित नहीं किया गया है, तो इसे उसी मूल्य पर वापस लौटाते रहना चाहिए)।

  3. जब भी a.equals(b), तब a.hashCode()जैसा होना चाहिए b.hashCode()

  4. यदि आप एक को ओवरराइड करते हैं, तो आपको दूसरे को ओवरराइड करना चाहिए।

http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html


hashCode()प्रत्येक वस्तु के लिए एक अद्वितीय पूर्णांक वापस करने के लिए उपयोग नहीं किया जाता है। वह असंभव है। आपने चौथे पैराग्राफ के दूसरे वाक्य में इसका स्वयं खंडन किया है।
लोर्ने

@ ईजेपी, अधिकांश बार हैकोड () दो अलग-अलग वस्तुओं के लिए अद्वितीय अंतराल लौटाएगा। लेकिन दो अलग-अलग ऑब्जेक्ट के लिए हैकोड के टकराने की संभावना होगी, इस अवधारणा को हैशकोड टकराव कहा जाता है । कृपया देखें: Tech.queryhome.com/96931/…
परमीश कोरकुट्टी

1

IMHO, यह नियम के अनुसार है - यदि दो वस्तुएं समान हैं, तो उनके पास समान हैश होना चाहिए, अर्थात, समान ऑब्जेक्ट को समान हैश मान का उत्पादन करना चाहिए।

ऊपर दिया गया, ऑब्जेक्ट में डिफ़ॉल्ट बराबरी () = = है, जो पते पर तुलना करता है, हैशकोड () पूर्णांक में पता देता है (वास्तविक पते पर हैश) जो फिर से अलग वस्तु के लिए अलग है।

यदि आपको हैश आधारित संग्रहों में कस्टम ऑब्जेक्ट्स का उपयोग करने की आवश्यकता है, तो आपको दोनों समान () और हैशकोड () को ओवरराइड करने की आवश्यकता है, उदाहरण यदि मैं कर्मचारी ऑब्जेक्ट के हैशसेट को बनाए रखना चाहता हूं, अगर मैं मजबूत हैशकोड और समान का उपयोग नहीं करता हूं मैं दो अलग-अलग कर्मचारी वस्तुओं को ओवरराइड कर सकता हूं, यह तब होता है जब मैं उम्र को हैशकोड () के रूप में उपयोग करता हूं, हालांकि मुझे अद्वितीय मूल्य का उपयोग करना चाहिए जो कि कर्मचारी आईडी हो सकता है।


1

डुप्लिकेट ऑब्जेक्ट्स की जांच करने में आपकी मदद करने के लिए, हमें एक कस्टम समान और हैशकोड की आवश्यकता है।

चूँकि हैशकोड हमेशा एक संख्या देता है जो किसी अल्फ़ाबेटिक कुंजी के बजाय किसी संख्या का उपयोग करके किसी वस्तु को पुनः प्राप्त करने के लिए हमेशा तेज़ रहता है। यह कैसे करेंगे? मान लें कि हमने कुछ मान पास करके एक नई वस्तु बनाई है जो पहले से ही किसी अन्य वस्तु में उपलब्ध है। अब नई वस्तु उसी हैश मान को किसी अन्य वस्तु के रूप में लौटाएगी क्योंकि पारित मूल्य समान है। एक बार समान हैश मान वापस आने के बाद, JVM हर बार एक ही मेमोरी एड्रेस पर जाएगा और अगर ऐसी हैश वैल्यू के लिए एक से अधिक ऑब्जेक्ट मौजूद हैं तो वह सही ऑब्जेक्ट की पहचान करने के लिए बराबर () विधि का उपयोग करेगा।


1

जब आप अपने कस्टम ऑब्जेक्ट को मैप में एक कुंजी के रूप में संग्रहीत और पुनः प्राप्त करना चाहते हैं, तो आपको हमेशा अपने कस्टम ऑब्जेक्ट में बराबर और हैशकोड को ओवरराइड करना चाहिए। उदाहरण के लिए:

Person p1 = new Person("A",23);
Person p2 = new Person("A",23);
HashMap map = new HashMap();
map.put(p1,"value 1");
map.put(p2,"value 2");

यहाँ p1 और P2 केवल एक वस्तु के रूप में विचार करेंगे और mapआकार केवल 1 होगा क्योंकि वे समान हैं।


1
public class Employee {

    private int empId;
    private String empName;

    public Employee(int empId, String empName) {
        super();
        this.empId = empId;
        this.empName = empName;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", empName=" + empName + "]";
    }

    @Override
    public int hashCode() {
        return empId + empName.hashCode();
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }
        if (!(this instanceof Employee)) {
            return false;
        }
        Employee emp = (Employee) obj;
        return this.getEmpId() == emp.getEmpId() && this.getEmpName().equals(emp.getEmpName());
    }

}

टेस्ट क्लास

public class Test {

    public static void main(String[] args) {
        Employee emp1 = new Employee(101,"Manash");
        Employee emp2 = new Employee(101,"Manash");
        Employee emp3 = new Employee(103,"Ranjan");
        System.out.println(emp1.hashCode());
        System.out.println(emp2.hashCode());
        System.out.println(emp1.equals(emp2));
        System.out.println(emp1.equals(emp3));
    }

}

ऑब्जेक्ट क्लास में समान (ऑब्जेक्ट ऑब्ज) का उपयोग एड्रेस कंपेरिजन की तुलना करने के लिए किया जाता है। इसलिए जब टेस्ट क्लास में आप दो ऑब्जेक्ट्स की तुलना करते हैं तो झूठी देने वाली विधि के बराबर होती है लेकिन जब हम हैशकोड को ओवरराइड करते हैं (तो यह कंटेंट की तुलना कर सकता है और उचित परिणाम दे सकता है।


और टेस्ट क्लास I को नीचे कार्यक्रम में जोड़ा गया।
मानष रंजन डाकुआ

ऑब्जेक्ट क्लास में समान (ऑब्जेक्ट ओब्ज) का उपयोग एड्रेस कंपेरिजन की तुलना करने के लिए किया जाता है। इसलिए जब टेस्ट क्लास में आप दो ऑब्जेक्ट्स की तुलना करते हैं तो झूठी देने वाली विधि के बराबर होती है लेकिन जब हम हैशकोड को ओवरराइड करते हैं (तो यह कंटेंट की तुलना कर सकता है और उचित परिणाम दे सकता है।
मानश रंजन डाकुआ

1
आप अपने उत्तर में जोड़ने के लिए इस उत्तर के ठीक नीचे संपादित लिंक का उपयोग कर सकते हैं .. कृपया दो अधूरे के रूप में एक उत्तर न जोड़ें
सूरज राव

1

यदि आप ओवरराइड करते हैं equals()और नहीं करते हैं hashcode(), तो आपको कोई समस्या नहीं मिलेगी, जब तक कि आप या कोई अन्य उस वर्ग प्रकार का उपयोग हैशेड संग्रह में नहीं करता HashSet। मुझसे पहले के लोगों ने कई बार प्रलेखित सिद्धांत को स्पष्ट रूप से समझाया है, मैं बस यहाँ एक बहुत ही सरल उदाहरण प्रदान करने के लिए हूं।

एक ऐसे वर्ग पर विचार करें जिसका equals()कुछ अनुकूलित करने की आवश्यकता है: -

    public class Rishav {

        private String rshv;

        public Rishav(String rshv) {
            this.rshv = rshv;
        }

        /**
        * @return the rshv
        */
        public String getRshv() {
            return rshv;
        }

        /**
        * @param rshv the rshv to set
        */
        public void setRshv(String rshv) {
            this.rshv = rshv;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Rishav) {
                obj = (Rishav) obj;
                if (this.rshv.equals(((Rishav) obj).getRshv())) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }

        @Override
        public int hashCode() {
            return rshv.hashCode();
        }

    }

अब इस मुख्य वर्ग पर विचार करें: -

    import java.util.HashSet;
    import java.util.Set;

    public class TestRishav {

        public static void main(String[] args) {
            Rishav rA = new Rishav("rishav");
            Rishav rB = new Rishav("rishav");
            System.out.println(rA.equals(rB));
            System.out.println("-----------------------------------");

            Set<Rishav> hashed = new HashSet<>();
            hashed.add(rA);
            System.out.println(hashed.contains(rB));
            System.out.println("-----------------------------------");

            hashed.add(rB);
            System.out.println(hashed.size());
        }

    }

इससे निम्नलिखित उत्पादन प्राप्त होगा: -

    true
    -----------------------------------
    true
    -----------------------------------
    1

मैं परिणामों से खुश हूं। लेकिन अगर मैंने ओवरराइड नहीं किया है hashCode(), तो यह दुःस्वप्न का कारण होगा क्योंकि Rishavसमान सदस्य सामग्री वाली वस्तुओं को अब विल के रूप में अद्वितीय नहीं माना hashCodeजाएगा, जैसा कि अलग-अलग होगा, जैसा कि डिफ़ॉल्ट व्यवहार से उत्पन्न होता है, यहां आउटपुट होगा: -

    true
    -----------------------------------
    false
    -----------------------------------
    2

0

दोनों विधियाँ ऑब्जेक्ट क्लास में परिभाषित की गई हैं। और दोनों इसके सरलतम कार्यान्वयन में हैं। इसलिए जब आपको आवश्यकता हो तो आप इन विधियों में कुछ और कार्यान्वयन जोड़ना चाहते हैं तब आप अपनी कक्षा में ओवरराइड कर लेते हैं।

उदाहरण के लिए: ऑब्जेक्ट में बराबर () विधि केवल संदर्भ पर इसकी समानता की जांच करती है। इसलिए अगर आपको इसके राज्य की तुलना करने की आवश्यकता है तो आप इसे ओवरराइड कर सकते हैं जैसा कि स्ट्रिंग क्लास में किया जाता है।


-3

बाह - "आपको हर वर्ग में हैशकोड () के बराबर होना चाहिए जो बराबरी से आगे बढ़ता है ()।"

[प्रभावी जावा से, जोशुआ बलोच द्वारा?]

क्या यह गलत तरीका नहीं है? ओवरशाइडिंग हैशकोड की संभावना है कि आप एक हैश-कुंजी वर्ग लिख रहे हैं, लेकिन ओवरराइडिंग बराबर नहीं करता है। कई वर्ग हैं जो हैश-कीज़ के रूप में उपयोग नहीं किए जाते हैं, लेकिन किसी अन्य कारण से तार्किक-समानता-परीक्षण विधि चाहते हैं। यदि आप इसके लिए "बराबरी" चुनते हैं, तो आपको इस नियम के अत्यधिक आवेदन द्वारा हैशकोड कार्यान्वयन लिखने के लिए बाध्य किया जा सकता है। यह सब हासिल करने वाले कोडबेस में अनकैप्ड कोड जोड़ रहे हैं, जो भविष्य में किसी को यात्रा करने की प्रतीक्षा कर रहा है। इसके अलावा कोड की जरूरत है आप विरोधी चुस्त है। यह सिर्फ गलत है (और एक विचारधारा उत्पन्न होती है जो संभवतः आपके हाथ से तैयार किए गए समान के साथ असंगत होगी)।

निश्चित रूप से उन्हें कुंजी के रूप में उपयोग की जाने वाली वस्तुओं पर एक इंटरफ़ेस अनिवार्य होना चाहिए? भले ही, ऑब्जेक्ट को डिफ़ॉल्ट हैशकोड () और बराबर () imho प्रदान नहीं करना चाहिए। यह शायद कई टूटे हुए हैश संग्रह को प्रोत्साहित करता है।

लेकिन वैसे भी, मुझे लगता है कि "नियम" को वापस सामने लिखा गया है। इस बीच, मैं समानता परीक्षण विधियों के लिए "बराबरी" का उपयोग करने से बचता रहूँगा :-(

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.