क्यों == Integer.valueOf (स्ट्रिंग) के साथ तुलना 127 और 128 के लिए अलग-अलग परिणाम देती है?


182

मुझे नहीं पता कि कोड की ये लाइनें अलग-अलग मान क्यों लौटाती हैं:

System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));

आउटपुट है:

true
false
true

पहला रिटर्न trueऔर दूसरा रिटर्न क्यों देता है false? वहाँ कुछ अलग है कि मैं 127और के बीच पता नहीं है 128? (बेशक मुझे पता है कि 127<128 )

साथ ही, तीसरा रिटर्न क्यों देता है true ?

मैंने इस प्रश्न का उत्तर पढ़ा है , लेकिन मुझे अभी भी यह नहीं पता था कि यह कैसे वापस आ सकता है true, और दूसरी पंक्ति में कोड क्यों लौटता है false


6
पूर्णांक एक वस्तु है; यदि आप समानता के लिए तुलना करना चाहते हैं, तो उपयोग करें .equals(), अन्यथा सभी दांव बंद हैं।
कार्ल दामगार्ड

6
@KarlDamgaardAsmussen वास्तव में यहां मैं वास्तव में परीक्षण करना चाहता हूं यदि वे एक ही वस्तु के संदर्भ में हैं, और सबसे पहले मुझे यह नहीं मिलता है कि 127 128 विभिन्न परिणाम क्यों लौटाते हैं।
०३

@DnR अगर जावा एक मानकीकृत विनिर्देश के साथ एक भाषा थी, तो मुझे लगता है कि यह ऐसे मामलों को लागू करने या अपरिभाषित व्यवहार को अनिवार्य करने देगा।
कार्ल दामगार्ड ने असामुसेन

1
@jszumski: हालांकि कैशिंग भाग की तुलना में इस प्रश्न के लिए अधिक है। इसके अलावा, लिंक किए गए उत्तर सबसे अच्छे रूप में अपूर्ण हैं - यह बहुत विस्तृत नहीं है कि कैश्ड क्या है और क्यों है।
मोटो 5

1
इस चर्चा पर आगे के लिए, कृपया इस मेटा पोस्ट को देखें ।
जीरो वेनवेल

जवाबों:


191

यहाँ एक हड़ताली अंतर है।

valueOfएक Integerवस्तु लौटा रहा है , जिसके मूल्य -128 और 127 के बीच कैश्ड हो सकते हैं। यही कारण है कि पहला मूल्य रिटर्न true- यह कैश्ड है - और दूसरा मूल्य रिटर्न false- 128 कैश्ड मान नहीं है, इसलिए आपको दो अलग-अलग Integerउदाहरण मिल रहे हैं ।

यह ध्यान रखना महत्वपूर्ण है कि आप संदर्भों की तुलना कर रहे हैं Integer#valueOf, और यदि आप किसी ऐसे मूल्य की तुलना कर रहे हैं जो कैश का समर्थन करता है से बड़ा है, तो यह मूल्यांकन नहीं करेगा true, भले ही पार्स किए गए मान बराबर हैं (बिंदु में मामला:) Integer.valueOf(128) == Integer.valueOf(128)। आपको इसके बजाय उपयोग करना चाहिएequals()

parseIntएक आदिम लौट रहा है int। यही कारण है कि तीसरे मूल्य का रिटर्न true- 128 == 128मूल्यांकन किया जाता है, और निश्चित रूप से,true

अब, एक उचित बिट उस तीसरे परिणाम को बनाने के लिए होता है true:

  • एक अनबॉक्सिंग रूपांतरण आपके द्वारा उपयोग किए जा रहे समतुल्य ऑपरेटर के संबंध में होता है और आपके पास मौजूद डेटाैटिप्स - intऔर Integer। आप निश्चित रूप Integerसे valueOfदाहिने हाथ की ओर से प्राप्त कर रहे हैं ।

  • रूपांतरण के बाद, आप दो आदिम intमूल्यों की तुलना कर रहे हैं। तुलना तभी होती है, जब आप इसकी अपेक्षा आदिमयों से करते हैं, इसलिए आप तुलना करते हैं 128और 128


2
@ user3152527: एक बड़ा अंतर है - एक को एक वस्तु माना जाता है, जिसका अर्थ है कि आप तरीकों को कॉल कर सकते हैं और इसके साथ सार डेटा संरचनाओं में बातचीत कर सकते हैं, जैसे List। दूसरा एक आदिम है, जो सिर्फ एक कच्चा मूल्य है।
मोटो

1
@ user3152527 आपने एक उत्कृष्ट प्रश्न पूछा (और सबसे बुरा नहीं)। लेकिन आपने इसका उपयोग करने के लिए इसे निर्धारित किया है।
user2910265

3
आह, ऐसा प्रतीत होता है कि प्रश्नकर्ता ने जावा में एक अंतर्निहित तथ्य को नहीं समझा: दो वस्तुओं की तुलना करने के लिए "==" का उपयोग करते समय, आप परीक्षण कर रहे हैं कि क्या वे एक ही वस्तु के संदर्भ हैं। "बराबर ()" का उपयोग करते समय, आप परीक्षण कर रहे हैं कि क्या उनका समान मूल्य है। आप आदिमों की तुलना करने के लिए "बराबर" का उपयोग नहीं कर सकते।
जय

3
@ जय नहीं, मैं समझता हूँ कि। लेकिन जो मुझे पहली बार भ्रमित करता है, वह यह है कि पहला एक सच है और दूसरा एक ही तुलना पद्धति का उपयोग करके गलत है ==। वैसे भी, अब यह स्पष्ट है।
०३:२५ पर डीएनआर

1
Nit: यह सिर्फ ऐसा नहीं है कि Integer "-128" और 127 के बीच कैश किया जा सकता है। यह JLS 5.1.7 के अनुसार होना चाहिए । यह उस सीमा के बाहर कैश किया जा सकता है, लेकिन (और अक्सर नहीं है) होना नहीं है।
यशवत

127

Integerवर्ग कि दुकानों 256 विशेष एक स्थिर कैश है, Integerमन में -128 और 127 कि साथ के बीच हर मूल्य के लिए एक, इन तीन के बीच अंतर पर विचार - वस्तुओं।

new Integer(123);

यह (स्पष्ट रूप से) एक बिल्कुल नई Integerवस्तु बनाता है ।

Integer.parseInt("123");

intपार्स करने के बाद यह एक आदिम मान लौटाता है String

Integer.valueOf("123");

यह दूसरों की तुलना में अधिक जटिल है। यह पार्स करने से शुरू होता है String। फिर, यदि मान -128 और 127 के बीच है, तो यह स्थैतिक कैश से संबंधित वस्तु को लौटाता है। यदि मान इस सीमा के बाहर है, तो यह इनवोक करता हैnew Integer() मूल्य में और गुजरता है, जिससे आपको एक नई वस्तु मिलती है।

अब, प्रश्न में तीन अभिव्यक्तियों पर विचार करें।

Integer.valueOf("127")==Integer.valueOf("127");

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

Integer.valueOf("128")==Integer.valueOf("128");

यह रिटर्न false, क्योंकि 128 स्थैतिक कैश में नहीं है। तो Integerसमानता के प्रत्येक पक्ष के लिए एक नया बनाया जाता है। चूंकि दो अलग-अलग Integerवस्तुएं हैं, और ==वस्तुओं के लिए केवल तभी लौटता है trueजब दोनों पक्ष एक ही वस्तु हों, यह होने जा रहा है false

Integer.parseInt("128")==Integer.valueOf("128");

यह दाईं ओर intएक नव निर्मित Integerवस्तु के साथ, बाईं ओर के आदिम मूल्य 128 की तुलना कर रहा है । लेकिन क्योंकि यह एक तुलना करने के लिए मतलब नहीं है intएक करने के लिए Integer, जावा ऑटो Unbox जाएगा Integerतुलना करने से पहले; तो आप एक की तुलना अंत intएक करने के लिए int। चूंकि आदिम 128 स्वयं के बराबर है, इसलिए यह रिटर्न करता है true


13

इन विधियों से मान लौटाने का ध्यान रखें। ValueOf विधि रिटर्न एक पूर्णांक उदाहरण:

public static Integer valueOf(int i)

ParseInt पूर्णांक मान (आदिम प्रकार) विधि रिटर्न:

public static int parseInt(String s) throws NumberFormatException

तुलना के लिए स्पष्टीकरण:

स्मृति को बचाने के लिए, आवरण वस्तुओं के दो उदाहरण, हमेशा == तब होंगे जब उनके आदिम मूल्य समान होंगे:

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

जब == का उपयोग एक आवरण के लिए एक आदिम की तुलना करने के लिए किया जाता है, तो आवरण को हटा दिया जाएगा और तुलना आदिम से आदिम हो जाएगी।

आपकी स्थिति में (उपरोक्त नियमों के अनुसार):

Integer.valueOf("127")==Integer.valueOf("127")

यह अभिव्यक्ति उसी वस्तु के संदर्भों की तुलना करती है क्योंकि इसमें -128 और 127 के बीच पूर्णांक मान होता है इसलिए यह वापस आ जाता है true

Integer.valueOf("128")==Integer.valueOf("128")

यह अभिव्यक्ति विभिन्न वस्तुओं के संदर्भों की तुलना करती है, क्योंकि उनमें इंटगर मूल्य <-128, 127> नहीं होते हैं, इसलिए यह वापस आ जाता है false

Integer.parseInt("128")==Integer.valueOf("128")

यह अभिव्यक्ति आदिम मूल्य (बाएं हाथ की ओर) और वस्तु (दाएं हाथ की ओर) के संदर्भ की तुलना करती है, इसलिए दाहिने हाथ की तरफ को अलिखित किया जाएगा और उसके आदिम प्रकार की तुलना बाईं ओर की जाएगी ताकि यह वापस आ जाए true


3
इसी तरह के सवाल: stackoverflow.com/questions/9824053/…
piobab

क्या आप उद्धरण स्रोत के लिए एक URL प्रदान कर सकते हैं?
फिलजेन

"... रैपर वस्तुओं के दो उदाहरण, हमेशा == होंगे जब उनके आदिम मूल्य समान होते हैं ..." - बिल्कुल झूठ। यदि आप एक ही मूल्य के साथ दो रैपर ऑब्जेक्ट बनाते हैं, तो वे तुलना करने पर सही नहीं लौटेंगे ==, क्योंकि वे अलग-अलग ऑब्जेक्ट हैं।
दाऊद इब्न करीम

6

इंटेगर की वस्तुएं -128 और 256 के बीच इंटीग्रेटर की संख्या 256 है

आपको == या ! = के साथ ऑब्जेक्ट संदर्भों की तुलना नहीं करनी चाहिए । आपको उपयोग करना चाहिए । बराबरी (..) के बजाय, या बेहतर - पूर्णांक के बजाय आदिम int का उपयोग करें।

parseInt : स्ट्रिंग तर्क को एक हस्ताक्षरित दशमलव पूर्णांक के रूप में देखता है। स्ट्रिंग में वर्ण सभी दशमलव अंक होने चाहिए, सिवाय इसके कि पहला वर्ण एक ASCII ऋण चिह्न हो सकता है '-' ('\ u002D') एक नकारात्मक मूल्य इंगित करने के लिए। परिणामी पूर्णांक मान लौटाया जाता है, ठीक वैसे ही जैसे तर्क और मूलांक 10 को तर्क के रूप में दिए गए थे (java.lang.String, int) विधि।

दूसरे तर्क द्वारा दिए गए मूलांक के साथ पार्स किए जाने पर निर्दिष्ट स्ट्रिंग से निकाले गए मान को पकड़े हुए एक पूर्णांक वस्तु लौटाता है। पहले तर्क की व्याख्या दूसरे तर्क द्वारा निर्दिष्ट मूलांक में एक हस्ताक्षरित पूर्णांक के रूप में की जाती है, ठीक उसी तरह जैसे कि तर्क parseInt (java.lang.String, int) विधि को दिए गए थे। परिणाम एक पूर्णांक वस्तु है जो स्ट्रिंग द्वारा निर्दिष्ट पूर्णांक मान का प्रतिनिधित्व करता है।

के बराबर

new Integer(Integer.parseInt(s, radix))

मूलांक - मूलांक की व्याख्या में प्रयुक्त होने वाला मूलांक

इसलिए यदि आप Integer.valueOf()पूर्णांक इनबेटन के बराबर हैं

-128 से 127 यह आपकी स्थिति में सही है

के लिए lesser than-128 और greater than127 यह देता हैfalse


6

दिए गए उत्तरों के पूरक के लिए, निम्नलिखित पर भी ध्यान दें:

public class Test { 
    public static void main(String... args) { 
        Integer a = new Integer(129);
        Integer b = new Integer(129);
        System.out.println(a == b);
    }
}

यह कोड भी प्रिंट होगा: false

उपयोगकर्ता के रूप में जे ने स्वीकार किए गए उत्तर के लिए एक टिप्पणी में दावा किया है, ==वस्तुओं पर ऑपरेटर का उपयोग करते समय देखभाल की जानी चाहिए , यहां आप जाँच कर रहे हैं कि क्या दोनों संदर्भ समान हैं, जो कि नहीं है, क्योंकि वे अलग-अलग objets हैं, हालांकि वे बहुत प्रतिनिधित्व करते हैं एक ही मूल्य। वस्तुओं की तुलना करने के लिए, आपको equals इसके बजाय विधि का उपयोग करना चाहिए :

Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a.equals(b));

यह प्रिंट करेगा: true

आप पूछ सकते हैं, लेकिन फिर पहली पंक्ति क्यों छपीtrue ? Integer.valueOfविधि के लिए स्रोत कोड की जाँच , आप निम्नलिखित देख सकते हैं:

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

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

अगर परम एक पूर्णांक IntegerCache.low(-128 के लिए डिफ़ॉल्ट) और IntegerCache.high(न्यूनतम मूल्य 127 के साथ रनटाइम परिकलित ) के बीच पूर्णांक है, तो एक पूर्व-आवंटित (कैश्ड) ऑब्जेक्ट वापस आ जाता है। इसलिए जब आप पैरामीटर के रूप में 127 का उपयोग करते हैं, तो आप एक ही कैश्ड ऑब्जेक्ट के दो संदर्भ प्राप्त कर रहे हैं और trueसंदर्भ की तुलना में प्राप्त कर रहे हैं।

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