2012-10-08 97 views
8

निम्नलिखित कार्यक्रम प्रिंट क्रमशः 'गलत' और 'सच':अवांछित autoboxing जादू

Number n = true ? new Long(1) : new Double(2.0); 
System.out.println(n instanceof Long); 
System.out.println(n instanceof Double); 

तो यह एक लंबे समय से है, लेकिन एक डबल नहीं होगा। हालांकि, यह सामान्य वर्गों पर इरादा काम करता है:

class B {} 
class D1 extends B {} 
class D2 extends B {} 

होने इस 'सही' प्रिंट होगा:

B b = true ? new D1() : new D2(); 
System.out.println(b instanceof D1); 

जिसका अर्थ है कि यह ऊपर के उदाहरण की तरह ही काम नहीं कर रहा।

मुझे यकीन है कि ऑटोबॉक्सिंग से संबंधित कुछ है, लेकिन क्या यह वास्तव में काम करना चाहिए? वह मुक्केबाजी का उपयोग क्यों करती है, जब संख्या वर्ग लंबी और दोहरी दोनों का सुपरक्लास होता है, तो अभिव्यक्ति का मूल्यांकन संख्या में किया जा सकता है?

यह वास्तव में दर्द है, क्योंकि एन प्रिंट करते समय, यह डबल मान के रूप में प्रिंट करता है। (मैं इसे वैकल्पिक हल के लिए आसान है पता है, लेकिन मुझे पागल कर दिया)

+0

':' प्रकार लेता है अंतिम अभिव्यक्ति का। यदि आपने इसे 'शून्य' बनाया है तो यह 'लांग' होगा: पी। –

+0

नहीं, यह अंतिम अभिव्यक्ति का प्रकार नहीं लेता है, बस दूसरे उदाहरण को देखें। बेशक कोड सिर्फ एक उदाहरण है, लेकिन कल्पना करें कि कुछ असली बुलियन जानकारी है जहां अब 'सत्य' ट्रेनेरी में खड़ा है। – poroszd

+2

करीबी वोट क्यों? यह मेरे लिए एक अच्छा सवाल है। –

उत्तर

7

यहाँ भाषा वकील की किताब बाहर लेते हैं: JLS §15.25

एक सशर्त अभिव्यक्ति के प्रकार के रूप में निर्धारित किया जाता है इस प्रकार है:

  • यदि दूसरे और तीसरे ऑपरेटरों में एक ही प्रकार है (जो शून्य प्रकार हो सकता है), तो वह सशर्त अभिव्यक्ति का प्रकार है।

लंबे और डबल एक ही प्रकार के नहीं हैं - लागू नहीं होते हैं।

  • दूसरे और तीसरे ऑपरेंड में से एक आदिम प्रकार टी की है, और अन्य प्रकार के मुक्केबाजी रूपांतरण आवेदन करने (§5.1.7) टी करने के लिए है, तो के प्रकार का परिणाम है तो सशर्त अभिव्यक्ति टी

कोई भी मूल्य आदिम नहीं है - लागू नहीं होता है।

  • दूसरे और तीसरे ऑपरेंड में से एक अशक्त प्रकार का है और अन्य प्रकार के लिए एक संदर्भ प्रकार है, तो सशर्त अभिव्यक्ति के प्रकार है कि संदर्भ प्रकार है।

कोई भी मूल्य शून्य नहीं है - लागू नहीं होता है।

  • अन्यथा, यदि दूसरे और तीसरे ऑपरेंड प्रकार है कि सांख्यिक प्रकार के लिए परिवर्तनीय (§5.1.8) कर रहे हैं, तो वहाँ कई मामलों रहे हैं:
    • [... के लिए विशेष मामलों बाइट/लघु/चार और उनके बक्से समकक्ष ...]
    • अन्यथा, बाइनरी न्यूमेरिक पदोन्नति (§ 5.6.2) ऑपरेंड प्रकारों पर लागू होती है, और सशर्त अभिव्यक्ति का प्रकार दूसरे और तीसरे ऑपरेंड का प्रचारित प्रकार है।

यह नियम यहाँ लागू होता है, जिसका अर्थ है सशर्त ऑपरेटर का परिणाम प्रकार है कि के रूप में यदि दोनों मूल्यों अनबॉक्स्ड थे। मान लीजिए कि इसके पीछे तर्क यह था कि अन्यथा Number n = bool ? 1 : 2.0 और Number n = bool ? new Long(1) : new Double(2.0) के पास अलग-अलग मान हैं। यह व्यवहार अप्रत्याशित और भी बदतर होगा - असंगत।

2

इसका बस बाइट कोड को देखो और आप (अपने उदाहरण बस संशोधित) देखेंगे

Number n = true ? new Long(166666) : new Double(24444.0); 
System.out.println(Boolean.toString(n instanceof Long)); 
System.out.println(Boolean.toString(n instanceof Double)); 

बाइट कोड

_new 'जावा/लैंग/लांग'

dup 
ldc 166666 
invokespecial 'java/lang/Long.<init>','(J)V' 
invokevirtual 'java/lang/Long.longValue','()J' 
l2d 
invokestatic 'java/lang/Double.valueOf','(D)Ljava/lang/Double;' 
astore 1 

मुख्य बिंदु l2d यह अगले चरण

0 बनाता है

स्टैक के एक लंबे पूर्णांक को बंद करता है, इसे डबल परिशुद्धता फ़्लोटिंग पॉइंट नंबर में डाल देता है, और डबल बैक को स्टैक पर धक्का देता है। ध्यान दें कि इससे परिशुद्धता का नुकसान हो सकता है ( में महत्व 54 बिट्स की तुलना में 54 बिट्स है, हालांकि लंबाई के 0 बिटकी हानि नहीं है (क्योंकि डबल की सीमा की सीमा से अधिक है)। आईईईई 754 राउंड-टू-नजदीकी मोड का उपयोग करके गोल किया जाता है।

और यह सब के बाद, अच्छा है तो आप डबल उदाहरण लेकिन लांग मूल्य साथ होगा! आप डीबग मोड में देखें, तो आपको लगता है कि हमारे संख्या डबल लेकिन लंबे समय से मूल्य है देखेंगे, यह बाइट कोड में ऊपर का वर्णन करता है

हम बाइट कोड में देख सकते हैं

getstatic 'java/lang/System.out','Ljava/io/PrintStream;' 
aload 1 
_instanceof 'java/lang/Long' 
invokestatic 'java/lang/Boolean.toString','(Z)Ljava/lang/String;' 
invokevirtual 'java/io/PrintStream.println','(Ljava/lang/String;)V' 
getstatic 'java/lang/System.out','Ljava/io/PrintStream;' 
aload 1 
_instanceof 'java/lang/Double' 
invokestatic 'java/lang/Boolean.toString','(Z)Ljava/lang/String;' 
invokevirtual 'java/io/PrintStream.println','(Ljava/lang/String;)V' 
return 
+0

मीठा, यह जानना अच्छा है (भले ही यह जवाब कैसे न हो, क्यों नहीं) । – poroszd

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

  • कोई संबंधित समस्या नहीं^_^