2010-04-08 17 views
11

Autoboxing बल्कि डरावना है। जब मैं पूरी तरह से == और .equals के बीच अंतर समझना मैं लेकिन मदद नहीं कर सकता मुझे से बाहर का पालन बग नरक है:संकलक/जेवीएम सिर्फ "बस काम" ऑटोबॉक्सिंग क्यों नहीं कर सकता?

final List<Integer> foo = Arrays.asList(1, 1000); 
    final List<Integer> bar = Arrays.asList(1, 1000); 
    System.out.println(foo.get(0) == bar.get(0)); 
    System.out.println(foo.get(1) == bar.get(1)); 

प्रिंट कि

true 
false 

वे इसे इस तरह क्यों किया? यह कैश इंटीग्रर्स के साथ कुछ करने के लिए है, लेकिन अगर ऐसा है तो वे प्रोग्राम द्वारा उपयोग किए जाने वाले सभी इंटीग्रियों को कैश क्यों नहीं करते? या JVM हमेशा प्राचीन के लिए ऑटो अनबॉक्स क्यों नहीं करता है?

प्रिंटिंग झूठी झूठी या सच्ची सत्य बेहतर तरीके से होती।

संपादित

मैं पुराने कोड का टूटना सहमत नहीं हैं। foo.get(0) == bar.get(0) होने से सच हो गया है कि आप कोड को तोड़ चुके हैं।

इस बाइट कोड में पूर्णांक के साथ पूर्णांक की जगह (जब तक यह शून्य सौंपा कभी नहीं किया गया है)

+8

यह बस काम करता है !! जिस तरह से आप उम्मीद की थी;) – OscarRyz

+0

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

+0

यह pecularities के कारण हो सकता है जो स्ट्रिंग के उदाहरणों को भी प्रभावित करता है। जहां तक ​​मैं चीजों को समझता हूं, मूल्य के अनुसार दृश्यों के पीछे कुछ पूलिंग हो रही है।इसे 'नया' कीवर्ड का उपयोग करके रोका जा सकता है। –

उत्तर

9
  • वे इसे इस तरह क्यों किया है?

-128 और 127 के बीच प्रत्येक इंटीजर जावा द्वारा कैश किया जाता है। उन्होंने प्रदर्शन लाभ के लिए, माना जाता है। भले ही वे इस फैसले पर वापस जाना चाहते थे, फिर भी यह संभावना नहीं है कि वे करेंगे। अगर किसी ने इस पर निर्भर कोड बनाया है, तो इसे हटाए जाने पर उनका कोड टूट जाएगा। शौक कोडिंग के लिए, इससे कोई फर्क नहीं पड़ता, लेकिन एंटरप्राइज़ कोड के लिए, लोग परेशान हो जाते हैं और मुकदमे होते हैं।

  • वे प्रोग्राम द्वारा उपयोग किए जाने वाले सभी इंटीग्रियों को कैश क्यों नहीं करते हैं?

सभी इंटीग्रियों को कैश नहीं किया जा सकता है, क्योंकि स्मृति प्रभाव बहुत बड़ा होगा।

  • क्यों JVM हमेशा प्राचीन के लिए ऑटो अनबॉक्स नहीं करता है?

क्योंकि JVM नहीं जानता कि आप क्या चाहते थे। साथ ही, यह परिवर्तन आसानी से विरासत कोड को तोड़ सकता है जो इस मामले को संभालने के लिए नहीं बनाया गया है।

यदि JVM स्वचालित रूप से == पर कॉल पर प्राइमेटिव्स को अनबॉक्स किया गया है, तो यह समस्या वास्तव में अधिक भ्रमित हो जाएगी। अब आपको याद रखना होगा कि == हमेशा ऑब्जेक्ट संदर्भों की तुलना करता है, जब तक ऑब्जेक्ट्स को अनबॉक्स नहीं किया जा सके। यह अभी तक ऊपर बताए गए जैसा ही अधिक अजीब भ्रमित मामलों का कारण बन जाएगा।

बल्कि तो इस बारे में बहुत कठिन चिंता, बस के बजाय इस नियम याद रखें: जब तक आप उनके संदर्भ से उनकी तुलना की जा करने का इरादा

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

+0

कभी नहीं कहें ** कभी नहीं **। आपको ** ** 'enum' मानों की तुलना == के साथ करना चाहिए। –

+0

@Alexander Pogrebnyak - आप सही हैं, और इसलिए मैंने "जब तक आप उन्हें उनके संदर्भों से तुलना करने का इरादा नहीं रखते" खंड जोड़ा। इसमें enums शामिल हैं। मैं अपने ** कभी ** ** –

+2

मेला बिंदु से खड़ा हूँ। फिर भी आपके पास "मारने के लिए लाइसेंस -9" है :)। 007 आउट –

7

आप कल्पना कर सकते कितना बुरा प्रदर्शन करता है, तो हर Integer के लिए भूमि के ऊपर किए गए होगा द्वारा संकलक स्तर पर हल किया जा नहीं कर सकता नजरबंदी? new Integer के लिए भी काम नहीं करता है।

जावा भाषा (कोई JVM समस्या नहीं) हमेशा ऑटोबॉक्स नहीं हो सकती क्योंकि प्री-1.5 जावा के लिए डिज़ाइन किया गया कोड अभी भी काम करना चाहिए।

+0

प्री-1.5 कोड का अच्छा उल्लेख। +1 – Bozho

+0

पीछे की ओर संगतता समस्या का उल्लेख करने के लिए एक और +1 – Chris

+0

वे पहले से ही पुराने कोड को तोड़कर -128 से 127 – Pyrolistical

5

Integer बाइट रेंज में एक ही वस्तु है, क्योंकि वे कैश किए गए हैं। बाइट रेंज के बाहर Integer एस नहीं हैं। यदि सभी पूर्णांक कैश किए जाने थे, तो आवश्यक स्मृति की कल्पना करें।

और here

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

+0

'इंटीजर के बाहर [-128, 127] बाहर हो सकता है या इंटर्न नहीं किया जा सकता है। (और मुझे लगता है कि मूल प्रश्न यह समझता है कि क्या हो रहा है, लेकिन जानना चाहता है क्यों?) –

+0

मुझे लगता है कि वे सूर्य के कार्यान्वयन के साथ नहीं हैं। वैसे भी, यह उन्हें कैशिंग के लिए आवश्यक संसाधनों और संसाधनों के बारे में है। – Bozho

4

यदि आप पूरी तरह से ऑटोबॉक्सिंग छोड़ते हैं, तो भी आपको यह व्यवहार मिलता है।

final List<Integer> foo = 
    Arrays.asList(new Integer(1), new Integer(1000)); 
final List<Integer> bar = 
    Arrays.asList(new Integer(1), new Integer(1000)); 

System.out.println(foo.get(0) == bar.get(0)); // false 
System.out.println(foo.get(1) == bar.get(1)); // false 

यही कारण है कि ग्रहण डिफ़ॉल्ट रूप से एक चेतावनी के रूप autoboxing गया है, एक कारण है: यदि आप किसी विशिष्ट व्यवहार चाहते

final List<Integer> foo = 
    Arrays.asList(Integer.valueOf(1), Integer.valueOf(1000)); 
final List<Integer> bar = 
    Arrays.asList(Integer.valueOf(1), Integer.valueOf(1000)); 

System.out.println(foo.get(0) == bar.get(0)); // true 
System.out.println(foo.get(1) == bar.get(1)); // false 

अधिक स्पष्ट रूप से दिखाएं।

+0

यह ग्रहण की मेरी प्रति में डिफ़ॉल्ट रूप से चालू नहीं है, और मैंने इसे नहीं बदला है। आप कौन सा संस्करण उपयोग कर रहे हैं? मैंने 3.2 और 3.4 की जांच की है। – Chris

+0

@ क्रिस: ग्रहण गैलीलियो (3.5) विंडो-> प्राथमिकताएं जावा-> कंपाइलर-> त्रुटियां/चेतावनियां-> संभावित प्रोग्रामिंग समस्याएं-> बॉक्सिंग और अनबॉक्सिंग रूपांतरण। हो सकता है कि यह डिफ़ॉल्ट रूप से चालू न हो, लेकिन जब से मैंने जावा 5 पर स्विच किया है, तब से मैंने इसे कभी भी चालू किया था। –

+0

यह डिफ़ॉल्ट रूप से डिफ़ॉल्ट रूप से नहीं है। जब मैंने इसे यहां पढ़ा तो मैंने इसे अभी बदल दिया। –

3

बहुत से लोगों को इस समस्या के साथ समस्याएं हैं, यहां तक ​​कि लोग जावा के बारे में किताबें लिखते हैं।

Pro Java Programming में, नीचे केवल इंच नीचे लेखक एक पहचान हैशैप में एक कुंजी के रूप में ऑटो-बॉक्स किए गए इंटीग्रियों का उपयोग करने के मुद्दों के बारे में बात करते थे, वह एक WeakHashMap में ऑटो-बॉक्स वाली इंटीजर कुंजी का उपयोग करता है। उनके द्वारा उपयोग किए जाने वाले उदाहरण मान 128 से अधिक हैं, इसलिए उनकी कचरा संग्रह कॉल सफल होती है। यदि कोई व्यक्ति अपने उदाहरण का उपयोग करना चाहता था और 128 से छोटे मानों का उपयोग करता था, तो उसका उदाहरण असफल हो जाएगा (कुंजी को परमा-कैश किया जा रहा है)।

2

जब आप लिखना

foo.get(0) 

संकलक कोई फर्क नहीं पड़ता कि कैसे आप सूची बनाई गई। यह केवल सूची foo के संकलन-समय प्रकार को देखता है। इसलिए, यदि यह एक सूची < इंटीजर> है, तो यह एक सूची < इंटीजर> के रूप में इसका व्यवहार करेगी, जैसा कि यह करना है, और एक सूची < इंटीजर> प्राप्त करें() हमेशा एक इंटीजर देता है। आप तो == उपयोग करना चाहते हैं आप

System.out.println(foo.get(0).intValue() == bar.get(0).intValue()); 

नहीं

System.out.println(foo.get(0) == bar.get(0)); 

लिखने के लिए क्योंकि है कि एक पूरी तरह से अलग मतलब है।