2013-08-27 5 views
5

मैं निम्नलिखित यहोशू बलोच (आइटम 9, अध्याय 3, पेज 49)प्रभावी जावा में जोशुआ ब्लोच द्वारा सुझाए गए अनुसार जावा में कैशिंग हैशकोड कैसे काम करता है?

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

// Lazily initialized, cached hashCode 
    private volatile int hashCode; // (See Item 71) 
    @Override public int hashCode() { 
     int result = hashCode; 
     if (result == 0) { 
      result = 17; 
      result = 31 * result + areaCode; 
      result = 31 * result + prefix; 
      result = 31 * result + lineNumber; 
      hashCode = result; 
     } 
     return result; 
    } 

मेरे सवाल का कैसे कैशिंग (hashCode याद) यहाँ काम करता है। पहली बार, hashCode() विधि कहा जाता है, परिणाम देने के लिए hashCode नहीं है। यह कैशिंग काम कैसे काम करेगा इस पर एक संक्षिप्त विवरण होगा। धन्यवाद

+0

कैशिंग का मतलब आपके द्वारा गणना की गई मान को सहेजने का अर्थ है ताकि आप इसे फिर से गणना किए बिना पुनः उपयोग कर सकें। यह सब कुछ कर रहा है। –

+1

एह? कैश "निजी अस्थिर int हैशकोड" है। जब हैश की गणना की जाती है, तो यह कैश में सहेजी जाती है। प्रारंभ में मान 0 गैर-स्थानीय संख्यात्मक चर के रूप में 0 है। – Kayaman

उत्तर

9

सरल। पढ़ें नीचे मेरी एम्बेडेड टिप्पणियां ...

private volatile int hashCode; 
//You keep a member field on the class, which represents the cached hashCode value 

    @Override public int hashCode() { 
     int result = hashCode; 
     //if result == 0, the hashCode has not been computed yet, so compute it 
     if (result == 0) { 
      result = 17; 
      result = 31 * result + areaCode; 
      result = 31 * result + prefix; 
      result = 31 * result + lineNumber; 
      //remember the value you computed in the hashCode member field 
      hashCode = result; 
     } 
     // when you return result, you've either just come from the body of the above 
     // if statement, in which case you JUST calculated the value -- or -- you've 
     // skipped the if statement in which case you've calculated it in a prior 
     // invocation of hashCode, and you're returning the cached value. 
     return result; 
    } 
+0

संशोधक 'अस्थिर' का उपयोग क्यों करें? कैशिंग से संबंधित कुछ? यदि हां, तो कृपया एक संक्षिप्त विवरण दें। धन्यवाद। – Charan

+2

@Charan यह बिल्कुल जरूरी नहीं है (और यदि आप 'java.lang.String' स्रोत पर नज़र डालते हैं, तो' हैश' फ़ील्ड 'अस्थिर नहीं है। इसे अस्थिर बनाने की केवल एक ही कमी है धागे अलग-अलग चल रहे हैं सीपीयू कई बार हैशकोड का पुनर्मूल्यांकन कर सकता है। लेकिन चूंकि जावा में स्ट्रिंग्स अपरिवर्तनीय हैं, जिसके परिणामस्वरूप कोई असंगतता नहीं होगी, केवल एक संभावित प्रदर्शन दंड, जो मुझे लगता है ठीक है क्योंकि हैश की गणना की तुलना में अधिक बार पढ़ा जा रहा है (और अस्थिर पढ़ने में सामान्य पढ़ने की तुलना में महत्वपूर्ण ओवरहेड हो सकता है) – karlicoss

2

hashCode एक आवृत्ति चर में परिवर्तनीय है, और इसे स्पष्ट रूप से प्रारंभ नहीं किया गया है, so Java intializes it to 0 (JLS Section 4.12.5)। तुलना result == 0 प्रभाव में है यह देखने के लिए कि result को संभवतः गैर-शून्य हैश कोड असाइन किया गया है। अगर इसे अभी तक असाइन नहीं किया गया है, तो यह गणना करता है, अन्यथा यह पहले से गणना किए गए हैश कोड को वापस देता है।

0

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

private volatile int isHashInvalid=TRUE; 
private volatile int hashCode; //Automatically zero but it doesn't matter 

//You keep a member field on the class, which represents the cached hashCode value 
@Override public int hashCode() { 
    int result = hashCode; 
    if (isHashInvalid) { 
     result = 17; 
     result = 31 * result + areaCode; 
     result = 31 * result + prefix; 
     result = 31 * result + lineNumber; 
     //remember the value you computed in the hashCode member field 
     hashCode = result; 
     isHashInvalid=FALSE; 
    } 
    // when you return result, you've either just come from the body of the above 
    // if statement, in which case you JUST calculated the value -- or -- you've 
    // skipped the if statement in which case you've calculated it in a prior 
    // invocation of hashCode, and you're returning the cached value. 
    return result; 
} 
+1

मुझे स्पष्ट नहीं है कि एक अतिरिक्त पूर्णांक जोड़ना लागत के लायक है। शून्य का उपयोग करने में एकमात्र समस्या एक सेंटीनेल है यदि 'हैशकोड शून्य शून्य लौटा सकता है, और वह समस्या 'परिणाम' की गणना करने के बाद, बस कहकर हल किया जा सकता है, 'अगर (परिणाम == 0) परिणाम = 867530 9 + एरैकोड; ' – supercat

+1

यह या तो 64 बिट नंबर या 32 बिट नंबर है जो वास्तव में यह जा रहा है जेड होना ईरो कम है। तो उस वस्तु के infinitesimal मात्रा के लिए, हैश कोड हर समय गणना की जाएगी। कोई बड़ी बात नहीं। – Dennis

+0

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

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