1. जावा में वस्तुओं की तुलना करना

जावा में, वस्तुओं की तुलना संदर्भ और मूल्य दोनों से की जा सकती है।

संदर्भों की तुलना करना

यदि दो चर स्मृति में एक ही वस्तु की ओर इशारा करते हैं, तो इन चरों में संग्रहीत संदर्भ समान होते हैं। यदि आप समानता ऑपरेटर ( ==) का उपयोग करके इन चरों की तुलना करते हैं, तो आप सही हो जाते हैं, और वह परिणाम समझ में आता है। यहाँ सब कुछ सरल है।

कोड कंसोल आउटपुट
Integer a = 5;
Integer b = a;
System.out.println(a == b);


true

मूल्य से तुलना करना

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

यह निर्धारित करने के लिए कि विभिन्न वस्तुएं समान हैं या नहीं, equals()विधि का उपयोग करें। उदाहरण के लिए:

कोड कंसोल आउटपुट
String a = new String("Hello");
String b = new String("Hello");
System.out.println(a == b);
System.out.println(a.equals(b));


false
true

विधि वर्ग equalsतक ही सीमित नहीं है Stringहर वर्ग के पास है।

यहाँ तक कि वे कक्षाएँ भी जो आप स्वयं लिखते हैं, और यहाँ क्यों है।



2. Objectवर्ग

जावा में सभी वर्ग Objectवर्ग को इनहेरिट करते हैं। जावा के निर्माता इस दृष्टिकोण के साथ आए।

और यदि कोई वर्ग वर्ग को इनहेरिट करता है , तो वह वर्ग Objectके सभी तरीकों को प्राप्त करता है । Objectऔर यह वंशानुक्रम का एक प्रमुख परिणाम है।

दूसरे शब्दों में, प्रत्येक वर्ग में कक्षा के तरीके होते हैं Object, भले ही उनके कोड में उनका उल्लेख न हो।

इन विरासत में मिली विधियों में वस्तु तुलना से संबंधित विधियाँ शामिल हैं। ये हैं equals()और hashCode()तरीके।

कोड वास्तव में, यहाँ हमारे पास क्या होगा:
class Person
{
   String name;
   int age;
}
class Person extends Object
{
   String name;
   int age;

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

   public int hashCode()
   {
      return address_of_object_in_memory; // This is the default implementation, but there may be a different implementation
   }
}

ऊपर के उदाहरण में, हमने Personनाम और उम्र के मापदंडों के साथ एक साधारण वर्ग बनाया, लेकिन एक भी तरीका नहीं। लेकिन क्योंकि सभी वर्ग Objectवर्ग को प्राप्त करते हैं, Personवर्ग में स्वचालित रूप से दो विधियाँ होती हैं:

तरीका विवरण
boolean equals(Object obj)
वर्तमान वस्तु और पारित वस्तु की तुलना करता है
int hashCode()
वर्तमान वस्तु का हैशकोड लौटाता है

यह पता चला है कि बिल्कुल हर वस्तु की equalsविधि होती है, और विभिन्न प्रकार की वस्तुओं की एक दूसरे से तुलना की जा सकती है। ऐसा कोड संकलित और पूरी तरह से काम करेगा।

कोड कंसोल आउटपुट
Integer a = 5;
String s = "Hello";
System.out.println(a.equals(s));
System.out.println(s.equals(a));


false
false
Object a = new Integer(5);
Object b = new Integer(5);
System.out.println(a.equals(b)) ;


true

3. equals()विधि

equals()वर्ग से विरासत में मिली विधि , Objectवर्तमान वस्तु की पास की गई वस्तुओं से तुलना करने के लिए सबसे सरल एल्गोरिथ्म को लागू करती है: यह केवल वस्तुओं के संदर्भों की तुलना करती है।

यदि आप विधि को Personकॉल करने के बजाय चर की तुलना करते हैं तो आपको वही परिणाम मिलता है । equals()उदाहरण:

कोड कंसोल आउटपुट
Person a = new Person();
a.name = "Steve";

Person b = new Person();
b.name = "Steve";

System.out.println(a == b);
System.out.println(a.equals(b));






false
false

जब equalsविधि को चालू किया जाता है a, तो यह केवल चर में संग्रहीत संदर्भ की तुलना चर aमें संग्रहीत संदर्भ से करता है।b

हालाँकि, तुलना Stringकक्षा के लिए अलग तरह से काम करती है। क्यों?

क्योंकि कक्षा बनाने वाले लोगों ने विधि Stringका अपना कार्यान्वयन लिखा था ।equals()

equals()विधि का कार्यान्वयन

अब आइए Personकक्षा में समान पद्धति के अपने कार्यान्वयन को लिखते हैं। हम 4 मुख्य मामलों पर विचार करेंगे।

महत्वपूर्ण:
भले ही कोई भी वर्ग equalsविधि को ओवरराइड करता हो, यह हमेशा एक Objectवस्तु को एक तर्क के रूप में लेता है

परिदृश्य 1 : वही वस्तु जिस पर equalsविधि कहलाती है, equalsविधि को भी पारित की जाती है। यदि वर्तमान वस्तु और पास की गई वस्तु के संदर्भ समान हैं, तो विधि को वापस आना चाहिए true। एक वस्तु स्वयं के बराबर होती है।

कोड में यह ऐसा दिखाई देगा:

कोड विवरण
public boolean equals(Object obj)
{
   if (this == obj)
    return true;

   // The rest of the code of the equals method
}


संदर्भों की तुलना करें

परिदृश्य 2 : विधि nullको पारित किया जाता है equals- हमारे पास तुलना करने के लिए कुछ भी नहीं है। जिस वस्तु पर equalsविधि कहा जाता है वह निश्चित रूप से अशक्त नहीं है, इसलिए हमें falseइस मामले में वापस जाने की आवश्यकता है।

कोड में यह ऐसा दिखाई देगा:

कोड विवरण
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   // The rest of the code of the equals method
}


संदर्भों की तुलना करें


पास की गई वस्तु है null?

परिदृश्य 3 : किसी ऑब्जेक्ट का संदर्भ जो विधि Personमें पास नहीं किया गया है। equalsक्या Personवस्तु गैर- Personवस्तु के बराबर है? यह वर्ग के विकासकर्ता के लिए एक प्रश्न है Personकि वह कैसे चाहे या क्या चाहे।

लेकिन आमतौर पर वस्तुओं को समान माना जाने वाला एक ही वर्ग का होना चाहिए। इसलिए, अगर क्लास के ऑब्जेक्ट के अलावा कोई और चीज़ Personहमारे बराबर मेथड में पास की जाती है, तो हम हमेशा वापस आ जाएंगे false। आप किसी वस्तु के प्रकार की जांच कैसे कर सकते हैं? यह सही है — instanceofऑपरेटर का उपयोग करके।

यहाँ हमारा नया कोड कैसा दिखता है:

कोड विवरण
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   if (!(obj instanceof Person))
      return false;

   // The rest of the code of the equals method
}


संदर्भों की तुलना करें


पास की गई वस्तु है null?


यदि पास की गई वस्तु a नहीं हैPerson

4. दो Personवस्तुओं की तुलना करना

हमने क्या किया? यदि हम विधि के अंत तक पहुँच चुके हैं, तो हमारे पास एक Personवस्तु संदर्भ है जो नहीं है null। इसलिए हम इसे एक में परिवर्तित करते हैं Personऔर दोनों वस्तुओं के प्रासंगिक आंतरिक डेटा की तुलना करते हैं। और वह हमारा चौथा परिदृश्य है ।

कोड विवरण
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   if (!(obj instanceof Person))
      return false;

   Person person = (Person) obj;

   // The rest of the code of the equals method
}


संदर्भों की तुलना करें


पास की गई वस्तु है null?


यदि पास की गई वस्तु Person


टाइपकास्टिंग नहीं है

और आप दो Personवस्तुओं की तुलना कैसे करते हैं? वे समान हैं यदि उनके नाम ( name) और आयु ( age) समान हैं। अंतिम कोड इस तरह दिखेगा:

कोड विवरण
public boolean equals(Object obj)
{
   if (this == obj)
      return true;

   if (obj == null)
      return false;

   if (!(obj instanceof Person))
      return false;

   Person person = (Person) obj;

   return this.name == person.name && this.age == person.age;
}


संदर्भों की तुलना करें


पास की गई वस्तु है null?


यदि पास की गई वस्तु Person


टाइपकास्टिंग नहीं है

लेकिन वह सब नहीं है।

सबसे पहले, नाम फ़ील्ड एक है , इसलिए आपको विधि को Stringकॉल करके नाम फ़ील्ड की तुलना करने की आवश्यकता है ।equals

this.name.equals(person.name)

दूसरा, nameक्षेत्र हो सकता है null: उस स्थिति में, आप equalsउस पर कॉल नहीं कर सकते। आपको इसके लिए एक अतिरिक्त जांच की आवश्यकता है null:

this.name != null && this.name.equals(person.name)

उस ने कहा, अगर नाम फ़ील्ड nullदोनों Personवस्तुओं में है, तो नाम अभी भी बराबर हैं।

चौथे परिदृश्य के लिए कोड इस तरह दिख सकता है:

Person person = (Person) obj;

if (this.age != person.age)
   return false;

if (this.name == null)
   return person.name == null;

return this.name.equals(person.name);


यदि आयु समान नहीं है,
तत्काल return false

यदि this.nameके बराबर है null, तो equalsविधि का उपयोग करके तुलना करने का कोई मतलब नहीं है। यहाँ या तो दूसरा nameक्षेत्र के बराबर है null, या यह नहीं है। विधि का

उपयोग करके दो नाम फ़ील्ड की तुलना करें ।equals


5. hashCode()विधि

विधि के अलावा equals, जिसका उद्देश्य दोनों वस्तुओं के सभी क्षेत्रों की विस्तृत तुलना करना है, एक और तरीका है जिसका उपयोग एक सटीक लेकिन बहुत तेज़ तुलना के लिए किया जा सकता है: hashCode().

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

लेकिन इसे तेज किया जा सकता है। मान लीजिए कि हमारे पास ऐसे शब्द हैं जो विभिन्न अक्षरों से शुरू होते हैं - यह तुरंत स्पष्ट हो जाता है कि वे भिन्न हैं। लेकिन अगर वे एक ही अक्षर से शुरू होते हैं, तो हम अभी यह नहीं कह सकते कि परिणाम क्या होगा: शब्द समान या भिन्न हो सकते हैं।

विधि hashCode()एक समान सिद्धांत का उपयोग करके काम करती है। यदि आप इसे किसी वस्तु पर कॉल करते हैं, तो यह कुछ संख्या देता है - एक शब्द में पहले अक्षर के अनुरूप। इस संख्या के निम्नलिखित गुण हैं:

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

इसे और भी स्पष्ट करने के लिए, आइए इन गुणों को शब्दों के संदर्भ में फिर से लिखें:

  • समान शब्दों के पहले अक्षर हमेशा समान होते हैं।
  • अलग-अलग शब्दों के पहले अक्षर एक जैसे हो सकते हैं, या उनके पहले अक्षर अलग-अलग हो सकते हैं
  • यदि शब्दों के पहले अक्षर अलग हैं, तो शब्द निश्चित रूप से अलग हैं

वस्तुओं की तुलना में तेजी लाने के लिए अंतिम संपत्ति का उपयोग किया जाता है:

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

लेकिन अगर हैशकोड समान हैं, तो हमें अभी भी समान पद्धति का उपयोग करके वस्तुओं की तुलना करनी होगी।



6. कोड में अनुबंध

ऊपर वर्णित व्यवहार जावा में सभी वर्गों द्वारा लागू किया जाना चाहिए। संकलन के दौरान, यह जांचने का कोई तरीका नहीं है कि वस्तुओं की तुलना सही ढंग से की गई है या नहीं।

जावा प्रोग्रामर के पास एक सार्वभौमिक समझौता है कि यदि वे बराबरी () पद्धति के अपने स्वयं के कार्यान्वयन को लिखते हैं और इस तरह मानक कार्यान्वयन (कक्षा में Object) को ओवरराइड करते हैं, तो उन्हें hashCode()विधि के अपने स्वयं के कार्यान्वयन को भी इस तरह से लिखना होगा कि उपरोक्त नियम हैं संतुष्ट।

इस व्यवस्था को अनुबंध कहा जाता है ।

यदि आप अपनी कक्षा में केवल equals()या केवल hashCode()पद्धति को लागू करते हैं, तो आप अनुबंध का घोर उल्लंघन कर रहे हैं (आपने अनुबंध तोड़ दिया है)। ऐसा मत करो।

यदि अन्य प्रोग्रामर आपके कोड का उपयोग करते हैं, तो यह ठीक से काम नहीं कर सकता है। और तो और, आप उस कोड का उपयोग करेंगे जो उपरोक्त अनुबंधों के पालन पर निर्भर करता है।

महत्वपूर्ण!

equalsकिसी तत्व की खोज करते समय, सभी जावा संग्रह पहले वस्तुओं के हैशकोड की तुलना करते हैं, और उसके बाद ही विधि का उपयोग करके तुलना करते हैं।

इसका मतलब यह है कि यदि आप अपनी कक्षा को एक equalsविधि देते हैं लेकिन आप अपनी hashCode()विधि नहीं लिखते हैं या आप इसे गलत तरीके से लागू करते हैं, तो हो सकता है कि संग्रह आपकी वस्तुओं के साथ सही ढंग से काम न करें।

उदाहरण के लिए, आप किसी सूची में कोई वस्तु जोड़ सकते हैं और फिर विधि का उपयोग करके उसे खोज सकते हैं contains(), लेकिन संग्रह को आपकी वस्तु नहीं मिल सकती है।