जावा में अजीबोगरीब मुक्केबाजी


114

मैंने बस इसी के समान कोड देखा:

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a == b);

        Integer c = 100, d = 100;
        System.out.println(c == d);
    }
}

भाग जाने पर, कोड का यह ब्लॉक प्रिंट हो जाएगा:

false
true

मैं समझता हूं कि पहला क्यों है false: क्योंकि दो ऑब्जेक्ट अलग-अलग ऑब्जेक्ट हैं, इसलिए ==संदर्भों की तुलना करता है। लेकिन मैं यह पता नहीं लगा सकता कि दूसरा बयान क्यों लौट रहा है true? क्या कुछ अजीब ऑटोबॉक्सिंग नियम है जो एक निश्चित सीमा में एक एंगर के मूल्य में होने पर किक करता है? यहाँ क्या चल रहा है?


1
की एक शिकार की तरह लग रहा stackoverflow.com/questions/1514910/...

3
@ आरसी - काफी हद तक नहीं, लेकिन एक समान स्थिति पर चर्चा की जाती है। हालांकि संदर्भ के लिए धन्यवाद।
जोएल

2
यह भयानक है। यही कारण है कि मैं उस पूरे आदिम, लेकिन वस्तु, लेकिन दोनों, लेकिन ऑटो-बॉक्सिंग के बिंदु को कभी भी नहीं समझ पाया, लेकिन निर्भर करता है, लेकिन आआआआआआआआआआआआआआआहहह;
njzk2

1
@ रज़िब: "ऑटोबॉक्सिंग" शब्द कोई कोड नहीं है, इसलिए इसे इस रूप में प्रारूपित न करें।
टॉम

जवाबों:


102

trueलाइन वास्तव में भाषा विनिर्देश द्वारा की गारंटी है। से खंड 5.1.7 :

यदि मूल्य p बॉक्सिंग किया जा रहा है तो सही, गलत, एक बाइट, रेंज में एक चार्ट \ u0000 से \ u007f, या -128 और 127 के बीच एक इंट या शॉर्ट नंबर है, तो r1 और r2 को किन्हीं भी दो रूपांतरण रूपांतरणों के परिणाम दें पी के। यह हमेशा ऐसा होता है कि r1 == r2।

यह चर्चा आगे बढ़ती है कि यह सुझाव दिया जाता है कि यद्यपि आपकी दूसरी पंक्ति की आउटपुट की गारंटी है, पहला नहीं है (नीचे उद्धृत अंतिम पैराग्राफ देखें):

आदर्श रूप से, दिए गए आदिम मूल्य p को बॉक्सिंग करना, हमेशा एक समान संदर्भ प्राप्त करेगा। व्यवहार में, मौजूदा कार्यान्वयन तकनीकों का उपयोग करके यह संभव नहीं है। उपरोक्त नियम एक व्यावहारिक समझौता है। ऊपर दिए गए अंतिम खंड के लिए आवश्यक है कि कुछ सामान्य मूल्यों को हमेशा अविभाज्य वस्तुओं में रखा जाए। कार्यान्वयन इन्हें कैश कर सकता है, आलसी या उत्सुकता से।

अन्य मूल्यों के लिए, यह सूत्रीकरण प्रोग्रामर की ओर से बॉक्सिंग मूल्यों की पहचान के बारे में किसी भी धारणा को अस्वीकार करता है। यह इनमें से कुछ या सभी संदर्भों को साझा करने (लेकिन आवश्यकता नहीं) की अनुमति देगा।

यह सुनिश्चित करता है कि ज्यादातर सामान्य मामलों में, अनुचित प्रदर्शन दंड लगाए बिना, विशेष रूप से छोटे उपकरणों पर व्यवहार वांछित होगा। उदाहरण के लिए, कम स्मृति-सीमित कार्यान्वयन सभी वर्ण और शॉर्ट्स, साथ ही -32K - + 32K की सीमा में पूर्णांकों और लोंगो को कैश कर सकते हैं।


17
यह भी ध्यान देने योग्य हो सकता है कि valueOfबॉक्स क्लास (जैसे Integer.valueOf(int)) की विधि को कॉल करने के लिए ऑटोबॉक्सिंग वास्तव में केवल वाक्यात्मक चीनी है । दिलचस्प है कि जेएलएस सटीक अलबॉक्सिंग डिसुगरिंग को परिभाषित करता है - intValue()एट अल का उपयोग करते हुए - लेकिन बॉक्सिंग डिसुगरिंग नहीं।
gustafc

@gustafc Integerको आधिकारिक publicAPI के माध्यम से कॉल करने के अलावा कोई अन्य तरीका नहीं है, अर्थात कॉलिंग intValue()। लेकिन Integerएक intमूल्य के लिए एक उदाहरण प्राप्त करने के लिए अन्य संभावित तरीके हैं, उदाहरण के लिए एक संकलक कोड बनाए रखने और पहले से निर्मित Integerउदाहरणों का पुन: उपयोग कर सकता है ।
होल्गर

31
public class Scratch
{
   public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;  //1
        System.out.println(a == b);

        Integer c = 100, d = 100;  //2
        System.out.println(c == d);
   }
}

आउटपुट:

false
true

संदर्भ की तुलना के लिए हां पहले उत्पादन किया जाता है; 'ए' और 'बी' - ये दो अलग-अलग संदर्भ हैं। बिंदु 1 में, वास्तव में दो संदर्भ बनाए गए हैं जो निम्नानुसार है -

Integer a = new Integer(1000);
Integer b = new Integer(1000);

दूसरी आउटपुट का उत्पादन किया जाता है क्योंकि JVMमेमोरी को बचाने की कोशिश करता है, जब Integerएक सीमा में गिरता है (-128 से 127)। बिंदु 2 पर 'd' के लिए Integer प्रकार का कोई नया संदर्भ नहीं बनाया गया है। इंटेगर प्रकार के संदर्भ चर 'डी' के लिए एक नई वस्तु बनाने के बजाय, इसे केवल 'सी' द्वारा संदर्भित पूर्व निर्मित ऑब्जेक्ट के साथ सौंपा गया है। इन सभी द्वारा किया जाता है JVM

ये मेमोरी सेविंग नियम केवल इंटीजर के लिए नहीं हैं। स्मृति बचत उद्देश्य के लिए, निम्न आवरण वस्तुओं के दो उदाहरण (बॉक्सिंग के माध्यम से बनाए गए), हमेशा == होंगे जहां उनके आदिम मूल्य समान हैं -

  • बूलियन
  • बाइट
  • \ U0000 से \u007f(7f दशमलव में 127 है) वर्ण
  • -128 से 127 तक शॉर्ट एंड इंटेगर

2
Longके रूप में एक ही सीमा के साथ भी कैश है Integer
एरिक वांग

8

कुछ रेंज में इंटेगर ऑब्जेक्ट (मुझे लगता है कि शायद -128 127 के माध्यम से) कैश्ड हो जाते हैं और फिर से उपयोग किए जाते हैं। उस सीमा के बाहर के इंटीजर को हर बार एक नई वस्तु मिलती है।


1
java.lang.Integer.IntegerCache.highसंपत्ति का उपयोग करके इस सीमा को बढ़ाया जा सकता है । दिलचस्प है कि लॉन्ग के पास वह विकल्प नहीं है।
अलेक्सांद्र क्रावट्स

5

हां, एक अजीब ऑटोबॉक्सिंग नियम है जो एक निश्चित सीमा में मूल्यों के होने पर किक करता है। जब आप किसी ऑब्जेक्ट चर के लिए एक स्थिरांक असाइन करते हैं, तो भाषा परिभाषा में कुछ भी नहीं कहता है कि एक नई वस्तु बनाई जानी चाहिए। यह कैश से किसी मौजूदा ऑब्जेक्ट का पुन: उपयोग कर सकता है।

वास्तव में, जेवीएम आमतौर पर इस उद्देश्य के लिए छोटे इंटेगर का एक कैश स्टोर करेगा, साथ ही साथ बूलियन.ट्र्यू और बूलियन.एफएलएसई जैसे मान भी।


4

मेरा अनुमान है कि जावा छोटे पूर्णांकों का एक कैश रखता है जो पहले से ही 'बॉक्सिंग' हैं, क्योंकि वे बहुत आम हैं और यह एक नया बनाने के लिए मौजूदा ऑब्जेक्ट को फिर से उपयोग करने के लिए बहुत समय की एक बिल्ली को बचाता है।


4

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

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a.equals(b));

        Integer c = 100, d = 100;
        System.out.println(c.equals(d));
    }
}

रिटर्न:

true
true

@ जॉयल ने बहुत ही अन्य विषय के लिए कहा, न कि इंटीग्रिटी समानता बल्कि ऑब्जेक्ट रनटाइम व्यवहार।
इलिया कुजनेत्सोव

3

जावा में मुक्केबाजी -128 के बीच -128 और 127 रेंज में काम करता है। जब आप इस श्रेणी में संख्याओं का उपयोग कर रहे हैं तो आप इसकी तुलना == ऑपरेटर से कर सकते हैं। सीमा के बाहर पूर्णांक वस्तुओं के लिए आपको बराबर का उपयोग करना होगा।


3

इंटर्नल रेफरेंस के लिए एक इंटर्न शाब्दिक का प्रत्यक्ष असाइनमेंट ऑटो-बॉक्सिंग का एक उदाहरण है, जहां ऑब्जेक्ट कन्वर्जन कोड के लिए शाब्दिक मूल्य संकलक द्वारा नियंत्रित किया जाता है।

इसलिए संकलन चरण के दौरान संकलक में परिवर्तित हो Integer a = 1000, b = 1000;जाता है Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);

तो यह वह Integer.valueOf()विधि है जो वास्तव में हमें पूर्णांक वस्तुएं प्रदान करती है, और यदि हम Integer.valueOf()विधि के स्रोत कोड को देखते हैं, तो हम स्पष्ट रूप से -128 में 127 (समावेशी) में विधि पूर्णांक वस्तुओं को देख सकते हैं।

/**
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
 public static Integer valueOf(int i) {
     if (i >= IntegerCache.low && i <= IntegerCache.high)
         return IntegerCache.cache[i + (-IntegerCache.low)];
     return new Integer(i);
 }

इसलिए नई पूर्णांक वस्तुओं को बनाने और वापस करने के बजाय, Integer.valueOf()विधि आंतरिक से आंतरिक वस्तुओं को लौटाती है IntegerCacheयदि पारित इंट शाब्दिक -128 से अधिक और 127 से कम है।

जावा इन पूर्णांक वस्तुओं को कैश करता है क्योंकि पूर्णांकों की इस श्रेणी का उपयोग दिन प्रतिदिन की प्रोग्रामिंग में बहुत अधिक हो जाता है जो अप्रत्यक्ष रूप से कुछ मेमोरी को बचाता है।

स्टैटिक ब्लॉक की वजह से क्लास को मेमोरी में लोड होने पर कैश को पहले इस्तेमाल पर शुरू किया जाता है। कैश की अधिकतम सीमा को -XX:AutoBoxCacheMaxजेवीएम विकल्प द्वारा नियंत्रित किया जा सकता है।

पूर्णांक वस्तुओं के लिए ही, Integer.IntegerCache हम भी करने के लिए इसी तरह की यह कैशिंग व्यवहार लागू नहीं है ByteCache, ShortCache, LongCache, CharacterCacheके लिए Byte, Short, Long, Characterक्रमशः।

आप मेरे लेख Java Integer Cache - Why Integer.valueOf (127) == Integer.valueOf (127) इज़ ट्रू पर अधिक पढ़ सकते हैं ।


0

जावा 5 में, मेमोरी को बचाने और इंटेगर टाइप ऑब्जेक्ट हैंडलिंग के लिए प्रदर्शन को बेहतर बनाने के लिए एक नई सुविधा शुरू की गई थी। आंतरिक वस्तुओं को आंतरिक रूप से कैश किया जाता है और उसी संदर्भित वस्तुओं के माध्यम से पुन: उपयोग किया जाता है।

  1. यह -127 से +127 के बीच सीमा में पूर्णांक मान के लिए लागू होता है (अधिकतम पूर्णांक मान)।

  2. यह इंटेगर कैशिंग ऑटोबॉक्सिंग पर ही काम करता है। जब वे कंस्ट्रक्टर का उपयोग करके बनाए जाते हैं तो पूर्णांक ऑब्जेक्ट्स को कैश नहीं किया जाएगा।

अधिक विवरण के लिए pls नीचे दिए गए लिंक पर जाएं:

विस्तार में कैशियर कैश


0

यदि हम Integerobeject के स्रोत कोड की जांच करते हैं , तो हम valueOfइस तरह से विधि का स्रोत पाएंगे :

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

जो समझा सकता है कि Integerऑब्जेक्ट्स, जो -128 ( Integer.low) से 127 ( Integer.high) तक की रेंज में हैं, ऑटोबॉक्सिंग के दौरान समान संदर्भित ऑब्जेक्ट हैं। और हम देख सकते हैं कि एक वर्ग कैश ऐरे IntegerCacheका ध्यान रखता है Integer, जो एक निजी स्टेटिक इनर क्लास Integerक्लास है।

एक और दिलचस्प उदाहरण हमें इस अजीब स्थिति को समझने में मदद कर सकता है:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

      Class cache = Integer.class.getDeclaredClasses()[0]; 
      Field myCache = cache.getDeclaredField("cache"); 
      myCache.setAccessible(true);

      Integer[] newCache = (Integer[]) myCache.get(cache); 
      newCache[132] = newCache[133]; 

      Integer a = 2;
      Integer b = a + a;
      System.out.printf("%d + %d = %d", a, a, b); //The output is: 2 + 2 = 5    

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