2011-11-13 40 views
15

java.lang.Object में इन विधियों को शामिल करने के फैसले के पीछे क्या तर्क है? समानता और हैशिंग कई वर्गों के लिए समझ में नहीं आता है।ऑब्जेक्ट में बराबर और हैशकोड परिभाषित क्यों किया गया था?

यह दो इंटरफेस बनाने के लिए अधिक तार्किक होगा:

interface Equalable { 
    boolean equals(Equalable other); 
} 

interface Hashable extends Equalable { 
    int hashCode(); 
} 

उदाहरण के लिए HashSet परिभाषा की तरह

class HashSet<T extends Hashable> ... 

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

+0

किसी चीज़ पर एक अच्छे लेख के लिए [यहां] (http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx) देखें संबंधित (जॉन स्कीट द्वारा)। –

+1

लिंक मृत लगता है। [यह] (http://codeblog.jonskeet.uk/2008/12/05/redesigning-system-object-java-lang-object/) एक ही लेख हो सकता है। – tkokasih

उत्तर

13

जब हम इंटरफेस द्वारा परिभाषित अनुबंध Interface हम inject (or accept) लागू करते हैं।

Equalable & Hashable दो अलग-अलग अनुबंध हैं। लेकिन अगर हम बारीकी से नजर रखते हैं तो हम देखेंगे कि वे दोनों एक दूसरे पर निर्भर हैं, जिसका अर्थ है कि वे single interface का हिस्सा हैं, EqualableAndHashable जैसे कुछ।

अब स्पष्ट सवाल यह है कि क्या उन्हें इस नए EqualableAndHashable इंटरफ़ेस या Object का हिस्सा होना चाहिए?

चलो पता लगाएं। दो वस्तुओं की समानता की जांच के लिए हमारे पास == (equal operator) है। == ऑपरेटर पुष्टि करता है कि मूल्य/संदर्भ दो अलग-अलग प्राइमेटिव/ऑब्जेक्ट्स के बराबर हैं या नहीं। लेकिन == ऑपरेटर के साथ जांच करके जवाब देना हमेशा संभव नहीं होता है।

अब सवाल यह है कि क्या यह समानता, which is also a contract, ऑब्जेक्ट क्लास के इंटरफेस या भाग के माध्यम से इंजेक्शन दी जानी चाहिए?

यदि हम एक बार देख ले, हम बस यह नहीं कह सकते कुछ की तरह:

TypeX समानता अनुबंध गारंटी नहीं है।

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

तो हमें equals के कार्यान्वयन के साथ आने के लिए ऑब्जेक्ट की आवश्यकता है। लेकिन यह केवल equals विधि को लागू नहीं कर सकता है, इसे hashcode विधि को भी लागू करने की आवश्यकता है।

+2

'=' वास्तव में असाइनमेंट ऑपरेटर है;) –

+0

@ डेव न्यूटन धन्यवाद। तदनुसार बदल दिया – Kowser

+1

मैं आपके द्वारा उल्लेख किए गए "अराजकता" को समझ नहीं पा रहा हूं। मैं सेट्स और मैप्स में अपनी कक्षाओं का उपयोग करने के लिए इन तरीकों को हर समय लागू करता हूं। मेरे लिए हर कीमत पर डिफ़ॉल्ट कार्यान्वयन से बचने के लिए यह आसान होगा, इसलिए मैं ऑब्जेक्ट से इन तरीकों को हटाने के लिए हूं। : डी –

1

(व्यक्तिगत रूप से, अगर वे एक अंतरफलक में थे, मैं उन दोनों को वहाँ में डाल equals/hashCode गलतियों की कम से कम एक वर्ग से बचने के लिए चाहते हैं।)

मुझे लगता है कि आप वस्तु में एक कार्यान्वयन चाहते हैं, एक पतन-तंत्र तंत्र के रूप में, जिसका मतलब है कि सब कुछ एक कार्यान्वयन होगा, इंटरफ़ेस या नहीं।

मुझे संदेह है कि इसमें बहुत कुछ ऐतिहासिक है; प्रोग्रामिंग जावा आज जावा प्रोग्रामिंग की तुलना में काफी अलग दिखता है।

0

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

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

+0

आपका मुद्दा है? – delnan

1

एमएचएच यकीन नहीं है, लेकिन जब जावा 1.0 जारी किया गया था जेनेरिक अभी तक मौजूद नहीं था। उन्हें 2004 में जावा 5.0 में जोड़ा गया था .. इसलिए आपका प्रस्ताव जावा 1.0

+2

यदि 'तुलनात्मक' लागू करने के लिए 'ट्रीसेट' को कुंजी की आवश्यकता हो सकती है यदि कोई 'तुलनाकर्ता' निर्दिष्ट नहीं किया गया था, तो हैशसेट को 'हैशबल' की आवश्यकता क्यों नहीं हो सकती? जेनेरिक की तुलना में इसके लिए और भी कुछ है। – meriton

0

के लिए लागू नहीं किया जा सका यदि आपके पास ऑब्जेक्ट्स की एक सूची है और आप contains विधि को कॉल करते हैं तो Java क्या करना चाहिए? मुझे लगता है कि डिफ़ॉल्ट कार्यान्वयन (संदर्भों की तुलना) एक सभ्य निर्णय है। इस तरह आप संग्रह में उपयोग की जाने वाली प्रत्येक कक्षा के लिए खुद को equals और hashcode लागू करने की आवश्यकता नहीं होगी।

1

मूल रूप से, जावा में, कोई जेनरिक नहीं था। यह किसी भी संग्रह के सदस्य होने के लिए Object को अनुमति देकर काम किया गया था, और इस प्रकार ObjecthashCode और equals की आवश्यकता थी। अब तक यह बदलने के लिए बहुत जुड़ा हुआ है।

+0

जेनरिक की अनुपस्थिति अप्रासंगिक है। उदाहरण के लिए, यदि 'कंप्रेसर' निर्दिष्ट नहीं किया गया था, तो उसने 'तुलनात्मक' को लागू करने के लिए कुंजी की आवश्यकता से 'ट्रीसेट' को नहीं रोका। – meriton

2

java.lang.Object में डिफ़ॉल्ट कार्यान्वयन समझ में आता है। अक्सर बार, यह काफी अच्छा है। जेपीए/वेब अनुप्रयोगों में, अगर मैं कभी भी बराबर और हैशकोड ओवरराइड करता हूं तो मुझे बहुत ही कम लगता है।

एक बेहतर सवाल हो सकता है: स्ट्रिंग, लांग इत्यादि जैसी अपरिवर्तनीय मूल्य वस्तुओं के लिए, आप == ऑपरेटर को बराबर कॉल करने के लिए ओवरराइड क्यों नहीं कर सकते हैं, जैसे कि आप सी # में कर सकते हैं? मैंने अधिक त्रुटियों को देखा है क्योंकि मेरे पास डिफ़ॉल्ट बराबर/हैशकोड सही चीज़ नहीं कर रहा है। उदाहरण के लिए,

Long x = obj.getId(); 
Long y = obj2.getId(); 
if (x == y) { // oops, probably meant x.equals(y)! } 

यह एक निष्पक्ष सवाल है,, हालांकि क्यों डिफ़ॉल्ट तरीकों डिफ़ॉल्ट Object.clone() की तरह एक टैगिंग इंटरफ़ेस के पीछे बंद नहीं कर रहे हैं। एक डिफ़ॉल्ट कार्यान्वयन है लेकिन आपको स्पष्ट रूप से स्वीकार करना होगा कि आप क्लोनेबल लागू करके इसका उपयोग करना चाहते हैं। कलेक्टिबल या इक्वटेबल जैसे समान टैगिंग इंटरफेस के रूप में आसानी से हो सकता है, और उसके बाद संग्रह विधियों के लिए हस्ताक्षर ऑब्जेक्ट के बजाय इक्वेटेबल हो सकता था।

0

वास्तव में, यह केवल सुविधा के लिए है, और यह इस तरह से बेहतर है। खैर, यह वस्तु समानता करने के लिए यदि आप .equals विधि नहीं था ले जाएगा क्या बारे में सोचते हैं:

AreEqual(Object obj1,Object obj2) { 
    if(!obj1 instanceof Equalable) return false; 
    if(!obj2 instanceof Equalable) return false; 
    return ((Equalable)(obj1).equals((Equalable)obj2); 
} 

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

ऑब्जेक्ट में एक डिफ़ॉल्ट (और कभी-कभी पर्याप्त) होना आवश्यक है। असफल और .शैशकोड फ़ंक्शन और नए कॉमर्स के लिए कुछ समस्याएं पैदा करते हैं, जिससे भाषा के लगातार उपयोगकर्ता अधिक लाल टेप के माध्यम से टकराते हैं।

0

कोई भी वस्तु, इसके प्रकार के बावजूद, समझदारी से जवाब दे सकती है कि यह किसी अन्य वस्तु के बराबर है, भले ही अन्य ऑब्जेक्ट का प्रकार किसी के बारे में कभी नहीं सुना है। यदि यह अन्य ऑब्जेक्ट के प्रकार के बारे में कभी नहीं सुना है, तो यह तथ्य यह रिपोर्ट करने के लिए पर्याप्त है कि यह बाद की वस्तु के बराबर नहीं है।

संबंधित मुद्दे