ArrayList का हैश कोड जिसमें स्वयं तत्व होता है


38

क्या हम उसी hashcodeके बारे में पता लगा सकते हैं, listजिसमें खुद भी शामिल है element?

मुझे पता है कि यह एक बुरा अभ्यास है, लेकिन यह साक्षात्कारकर्ता ने पूछा है।

जब मैंने निम्नलिखित कोड चलाया तो यह फेंकता है StackOverflowError:

public class Main {
    public static void main(String args[]) {
        ArrayList<ArrayList> a = new ArrayList();
        a.add(a);
        a.hashCode();
    }
}

अब यहाँ मेरे दो सवाल हैं:

  1. क्यों है एक StackOverflowError?
  2. क्या इस तरह से हैश कोड ढूंढना संभव है?

7
क्योंकि आप सूची को खुद से जोड़ते हैं। ऐड स्टेटमेंट के बिना a.hashCode () आज़माएं
जेन्स

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


ठीक है, मुझे पता चला कि स्टैकओवरफ्लो क्यों है, क्या कोई मुझे समस्या संख्या 2 को समझाने में मदद कर सकता है 2- इसे कैसे खोजें
जोकर

9
जैसा कि दूसरों ने उत्तर दिया है, यह संभव नहीं है, Listइंटरफ़ेस की बहुत परिभाषा से , hashCodeएक सूची का सदस्य इसके सदस्यों पर निर्भर करता है। यह देखते हुए कि सूची का अपना सदस्य है, यह हैश कोड है hashCode, जो इस पर निर्भर करता है hashCode... और इसी तरह, अनंत पुनरावृत्ति और StackOverflowErrorआप में चल रहे हैं। अब सवाल यह है: आपको खुद को शामिल करने के लिए एक सूची की आवश्यकता क्यों है? मैं आपको गारंटी दे सकता हूं कि आप इस तरह से पुनरावर्ती सदस्यता की आवश्यकता के बिना, जो कुछ भी आप कर रहे हैं, वह बेहतर तरीके से प्राप्त कर सकते हैं।
अलेक्जेंडर - मोनिका

जवाबों:


36

इंटरफ़ेस में अनुरूपण Listकार्यान्वयन के लिए हैश कोड निर्दिष्ट किया गया है :

इस सूची के लिए हैश कोड मान लौटाता है। किसी सूची का हैश कोड निम्नलिखित गणना के परिणाम के रूप में परिभाषित किया गया है:

 int hashCode = 1;
 for (E e : list)
     hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

यह सुनिश्चित करता list1.equals(list2)है कि list1.hashCode()==list2.hashCode()किसी भी दो सूचियों के लिए, list1और list2, सामान्य अनुबंध के अनुसार आवश्यक है Object.hashCode()

इसके लिए यह आवश्यक नहीं है कि कार्यान्वयन बिलकुल ऐसा लगे (देखें कि किसी विकल्प के लिए List.hashCode () के समान स्ट्रीम के लिए हैश कोड की गणना कैसे की जाए , लेकिन सही हैश कोड केवल एक सूची के लिए होता है। एक संख्या x == 31 + xहोना चाहिए जिसके लिए trueदूसरे शब्दों में, एक अनुरूप संख्या की गणना करना असंभव है।


1
@ होलगर, एरीक hashCode()वापस जाने के लिए पूरे फ़ंक्शन के कोड को बदलना चाहता है 0। यह तकनीकी रूप से हल करता है x == 31 + xलेकिन आवश्यकता को अनदेखा करता है कि x कम से कम 1. होना चाहिए
bxk21

4
@ मेरे उत्तर का बिंदु EricDuminil है, अनुबंध एक तर्क का वर्णन करता है जो ArrayListशाब्दिक रूप से लागू होता है, एक पुनरावृत्ति की ओर अग्रसर करता है, लेकिन कोई अनुरूप वैकल्पिक कार्यान्वयन भी नहीं है। ध्यान दें कि मैंने अपना उत्तर ऐसे समय में पोस्ट किया था जब ओपी पहले से ही समझ गया था कि यह विशेष कार्यान्वयन क्यों होता है StackOverflowError, जिसे अन्य उत्तरों में संबोधित किया गया है। इसलिए मैंने मूल्य के साथ परिमित समय में पूरा होने वाले एक अनुरूप कार्यान्वयन की सामान्य असंभवता पर ध्यान केंद्रित किया।
होल्गर

2
@pdem से कोई फर्क नहीं पड़ता कि क्या विनिर्देश एल्गोरिथम, सूत्र, छद्म कोड, या वास्तविक कोड के वर्डी विवरण का उपयोग करता है। जैसा कि उत्तर में कहा गया है, कल्पना में दिया गया कोड सामान्य रूप से वैकल्पिक कार्यान्वयन को रोकता नहीं है। विश्लेषण क्या हुआ या नहीं, इस बारे में कल्पना का रूप कुछ भी नहीं कहता है। इंटरफ़ेस दस्तावेज़ीकरण का वाक्य " जबकि सूचियों के लिए खुद को तत्वों के रूप में शामिल करने की अनुमति है, अत्यधिक सावधानी की सलाह दी जाती है: समान और हैशकोड विधियों को अब ऐसी सूची में अच्छी तरह से परिभाषित नहीं किया गया है " बताता है कि ऐसा विश्लेषण हुआ।
होल्गर

2
@ आप इसे उल्टा कर रहे हैं। मैंने कभी नहीं कहा कि हैश कोड के कारण सूची बराबर होनी चाहिए। सूचियों हैं , बराबर परिभाषा के द्वारा। Arrays.asList("foo")के बराबर है Collections.singletonList("foo"), के List.of("foo")बराबर है new ArrayList<>(List.of("foo"))। ये सभी सूचियाँ समान हैं, बिंदु। फिर, चूंकि ये सूचियां समान हैं, इसलिए उनके पास समान हैश कोड होना चाहिए। दूसरे तरीके से नहीं। चूंकि उनके पास समान हैश कोड होना चाहिए, इसलिए इसे अच्छी तरह से परिभाषित किया जाना चाहिए। भले ही वे इसे कैसे परिभाषित करें (जावा 2 में वापस), इसे सभी कार्यान्वयनों से सहमत होने के लिए अच्छी तरह से परिभाषित किया जाना चाहिए।
होल्गर

2
@pdem वास्तव में, एक कस्टम कार्यान्वयन है जो या तो, को लागू नहीं करता है Listया एक बड़ी चेतावनी है, के साथ तुलना में "सामान्य सूची के साथ मिश्रित नहीं होते हैं" है IdentityHashMapऔर उसकी " यह वर्ग है नहीं एक सामान्य प्रयोजन मानचित्र कार्यान्वयन! चेतावनी। पूर्व मामले में, आप पहले से ही लागू करने के साथ ठीक हैं, Collectionलेकिन सूची शैली सूचकांक आधारित पहुंच विधियों को भी जोड़ रहे हैं । फिर, कोई समानता बाधा मौजूद नहीं है, लेकिन यह अभी भी अन्य संग्रह प्रकारों के साथ आसानी से काम करता है।
होल्गर

23

कक्षा hashCodeमें विधि का कंकाल कार्यान्वयन देखें AbstractList

public int hashCode() {
    int hashCode = 1;
    for (E e : this)
        hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
    return hashCode;
}

सूची में प्रत्येक तत्व के लिए, यह कॉल करता है hashCode। आपकी केस लिस्ट में एकमात्र तत्व है। अब यह कॉल कभी खत्म नहीं होती। विधि स्वयं को पुनरावर्ती कहती है और पुनरावृत्ति तब तक चलती रहती है जब तक कि उसका सामना न हो जाए StackOverflowError। तो आप hashCodeइस तरह से नहीं पा सकते हैं ।


तो जवाब है कि इस तरह से हैश कोड खोजने का कोई तरीका नहीं है?
जोकर

3
हाँ, पुनरावर्ती स्थिति के कारण
वसंत

इतना ही नहीं, यह इस तरह से परिभाषित किया गया है।
क्राइसिस -ऑन स्ट्राइक-

14

आपने एक (पैथोलॉजिकल) सूची को परिभाषित किया है जिसमें स्वयं शामिल है।

वहाँ क्यों है StackOverflowError?

के अनुसार javadocs (विनिर्देश यानी), एक की hashCode Listउसके तत्वों में से प्रत्येक के hashCode के एक समारोह को परिभाषित किया गया है। इसे कहते हैं:

"किसी सूची का हैश कोड निम्नलिखित गणना के परिणाम के रूप में परिभाषित किया गया है:"

int hashCode = 1;
    for (E e : list)
         hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

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

क्या इस तरह से हैश कोड ढूंढना संभव है?

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


मुझे नहीं पता कि यह जवाब दो अन्य की तुलना में कम क्यों है क्योंकि यह वास्तव में स्पष्टीकरण के साथ ओपी सवालों का जवाब देता है।
नेत

1
@ कुछ उपयोगकर्ताओं को केवल शीर्ष पर उत्तर पढ़ें।
होल्गर

8

नहीं, प्रलेखन का उत्तर है

सूची संरचना का प्रलेखन स्पष्ट रूप से बताता है:

नोट: जबकि सूचियों में खुद को तत्वों के रूप में शामिल करने की अनुमति है, अत्यधिक सावधानी की सलाह दी जाती है: समान और हैशकोड विधियों को अब ऐसी सूची में अच्छी तरह से परिभाषित नहीं किया गया है।

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


1
आपने बताया कि यह विनिर्देश के बाहर क्यों है, इसलिए यह बताता है कि यह बग नहीं है। वह अन्य उत्तरों से गायब था।
pdem

3

रवींद्र का जवाब बिंदु 1 के लिए एक अच्छी व्याख्या देता है। प्रश्न 2 पर टिप्पणी करने के लिए:

क्या इस तरह से हैश कोड ढूंढना संभव है?

यहां कुछ गोलाकार है। इस स्टैक ओवरफ़्लो त्रुटि के संदर्भ में इन 2 में से कम से कम एक गलत होना चाहिए:

  • सूची के हैश कोड को इसके तत्वों को ध्यान में रखना चाहिए
  • किसी सूची का अपना तत्व होना ठीक है

अब, क्योंकि हम एक के साथ काम कर रहे हैं ArrayList, पहला बिंदु तय हो गया है। दूसरे शब्दों में, हो सकता है कि आपको किसी पुनरावर्ती सूची के हैश कोड की सार्थक रूप से गणना करने में सक्षम होने के लिए एक अलग कार्यान्वयन की आवश्यकता हो ... कोई ArrayListतत्वों के हैश कोड को जोड़ और बढ़ा सकता है , कुछ ऐसा

for (E e : this)
  if(e == this) continue; //contrived rules
  hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

इसके बजाय ऐसी कक्षा का उपयोग करना ArrayList, आप कर सकते थे।

के साथ ArrayList, दूसरा बिंदु गलत है। तो अगर साक्षात्कारकर्ता का अर्थ "क्या इस तरह से हैश कोड ढूंढना संभव है (एक सरणी सूची के साथ)?" , तो जवाब नहीं है, क्योंकि यह बेतुका है।


1
हैश कोड गणना द्वारा अनिवार्य है अनुबंध । कोई भी मान्य कार्यान्वयन स्वयं को छोड़ नहीं सकता। विनिर्देश से, आप प्राप्त कर सकते हैं कि आप एक पाते हैं संख्या जिसके लिए है , तो आप एक मान्य छोटा-कट ... लागू कर सकते हैंListintx == 31 + xtrue
होल्गर

मुझे यह समझ में नहीं आया कि @ होल्गर क्या कह रहा था। लेकिन समाधान के साथ 2 समस्याएँ हैं: पहला: यह समस्या को हल करता है जब यह सूची स्वयं की एक वस्तु है और न कि यदि सूची जहां स्वयं की वस्तु का एक आइटम (पुनरावृत्ति की गहरी परतें) दूसरा: यदि सूची स्वयं ही छोड़ दी गई है एक खाली सूची के बराबर हो सकता है।
जोनास मिशेल

1
@JonasMichel मैंने एक समाधान का प्रस्ताव नहीं किया। मैं सिर्फ दार्शनिकता से सवाल के घेरे में चारों ओर बहस कर रहा हूं। अगर हमें ऐसी सूची के लिए एक हैश कोड की गणना करनी चाहिए , तो यह तब तक काम नहीं करेगा जब तक कि हम किसी सरणी सूची की बाधा को नहीं हटाते (और होल्गर यह कहते हुए पुष्ट करते हैं कि Listफ़ॉर्मूला तय नहीं होता है हैश कोड लॉजिक को कार्यान्वयन के साथ पालन किया जाना है)
ernest_k

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

1
@Teepeemm Listएक इंटरफ़ेस है। यह एक अनुबंध को परिभाषित करता है , यह एक कार्यान्वयन प्रदान नहीं करता है। बेशक, अनुबंध में समानता और हैश कोड दोनों शामिल हैं। चूंकि समानता का सामान्य अनुबंध यह है कि इसे सममित होना पड़ता है, यदि आप एक सूची कार्यान्वयन को बदलते हैं, तो आपको सभी मौजूदा सूची कार्यान्वयनों को बदलना होगा, अन्यथा, आप मूल अनुबंध को भी तोड़ देंगे java.lang.Object
होल्गर

1

क्योंकि जब आप एक ही फ़ंक्शन से एक ही फ़ंक्शन को कॉल करते हैं तो यह पुनरावृत्ति की स्थिति पैदा करेगा जो कभी समाप्त नहीं होता है। और इस ऑपरेशन को रोकने के लिए जेएवीए वापस आ जाएगाjava.lang.StackOverflowError

नीचे उदाहरण कोड है जो समान परिदृश्य की व्याख्या करता है:

public class RefTest {

    public static void main(String... strings) {
        RefTest rf = new RefTest();
        rf.message(message("test"));
    }

    public static String message2(String s){
        return message(s);
    }

    public static String message(String s){
        return message2(s);
    }

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