== ऑपरेटर स्ट्रिंग मान की तुलना जावा से क्यों नहीं हुई?


50

प्रत्येक सक्षम जावा प्रोग्रामर जानता है कि आपको स्ट्रिंग की तुलना करने के लिए String.equals () का उपयोग करने की आवश्यकता है, बजाय == क्योंकि == संदर्भ समानता के लिए जांच करता है।

जब मैं तार के साथ काम कर रहा हूं, तो ज्यादातर समय मैं संदर्भ समानता के बजाय मूल्य समानता के लिए जाँच कर रहा हूं। मुझे लगता है कि यह अधिक सहज होगा यदि भाषा ने स्ट्रिंग मानों को केवल == का उपयोग करके तुलना करने की अनुमति दी।

तुलना के रूप में, सी # के == ऑपरेटर स्ट्रिंग एस के लिए मूल्य समानता के लिए जाँच करता है । और अगर आपको वास्तव में संदर्भ समानता की जांच करने की आवश्यकता है, तो आप String.ReferenceEquals का उपयोग कर सकते हैं।

एक और महत्वपूर्ण बिंदु यह है कि स्ट्रिंग्स अपरिवर्तनीय हैं, इसलिए इस सुविधा को अनुमति देने से कोई नुकसान नहीं है।

क्या जावा में इसे लागू नहीं करने का कोई विशेष कारण है?


12
आप स्काला को देखना चाह सकते हैं, जहां ==वस्तु समानता है और eqसंदर्भ समानता ( inps.oreilly.com/tmarks/9780596155957/… ) है।
जियोर्जियो

बस एक नोट के रूप में, और यह आपकी मदद नहीं कर सकता है, लेकिन जहाँ तक मुझे याद है, आप स्ट्रिंग शाब्दिक की तुलना '==' के साथ कर सकते हैं
Kgrover

10
@ किग्रोवर: आप कर सकते हैं, लेकिन यह संदर्भ समानता का सिर्फ एक सुविधाजनक उप-उत्पाद है और जावा आक्रामक स्ट्रिंग ऑब्जेक्ट के संदर्भ में उसी वस्तु के संदर्भ में आक्रामक रूप से कैसे अनुकूलन करता है। दूसरे शब्दों में, यह काम करता है, लेकिन गलत कारणों से।
tdammers

1
@ ==ऑपरेटर ऑपरेटर को केवल मैप करता है Equalsयदि ==ऑपरेटर उस तरह से लागू किया गया था। के लिए डिफ़ॉल्ट व्यवहार ==समान है ReferenceEquals(वास्तव में, ReferenceEqualsवस्तु संस्करण के रूप में परिभाषित किया गया है ==)
पैट्रिक Huizinga

3
यह डिजाइन निर्णयों का परिणाम है जो कई अन्य परिदृश्यों में बहुत मायने रखता है। लेकिन जब से आपको यह पता लगता है कि और इस रास्ते से पूछ रहा हूं, तो मुझे आपके सवाल का जवाब देने के लिए मजबूर होना पड़ता है: स्ट्रिंग संदर्भ संदर्भ के लिए उपयोग मामला क्यों होना चाहिए?
याकूब रायहल

जवाबों:


90

मुझे लगता है कि यह सिर्फ स्थिरता है, या "कम से कम विस्मय का सिद्धांत"। स्ट्रिंग एक वस्तु है, इसलिए यदि अन्य वस्तुओं की तुलना में अलग तरह से व्यवहार किया जाता है तो यह आश्चर्य की बात होगी।

उस समय जब जावा बाहर आया (~ 1995), केवल कुछ Stringप्रोग्रामर्स के लिए कुल लक्जरी जैसा कुछ था, जो शून्य-समाप्त सरणियों के रूप में तार का प्रतिनिधित्व करने के आदी थे। Stringव्यवहार अब यह है कि यह तब क्या था, और यह अच्छा है; बाद में व्यवहार को बदलने से काम के कार्यक्रमों में आश्चर्यजनक, अवांछित प्रभाव पड़ सकता है।

एक साइड नोट के रूप में, आप String.intern()स्ट्रिंग का एक कैनोनिकल (इंटर्न) प्राप्त करने के लिए उपयोग कर सकते हैं , जिसके बाद तुलना की जा सकती है ==। इंटर्निंग में कुछ समय लगता है, लेकिन उसके बाद, तुलना वास्तव में तेज होगी।

परिवर्धन: कुछ उत्तरों के विपरीत, यह ऑपरेटर के ओवरलोडिंग के समर्थन के बारे में नहीं है+ऑपरेटर (संयोजन) पर काम करता है Stringरों भले ही जावा अधिक भार ऑपरेटर का समर्थन नहीं करता; यह बस संकलक में एक विशेष मामले के रूप में संभाला जाता है, को हल करता है StringBuilder.append()। इसी तरह, ==एक विशेष मामले के रूप में संभाला जा सकता था।

फिर विशेष मामले के साथ विस्मय क्यों +लेकिन साथ नहीं ==? क्योंकि, गैर- वस्तुओं पर लागू होने पर +बस संकलन नहीं होता है , Stringइसलिए यह जल्दी स्पष्ट होता है। अलग व्यवहार की ==बहुत कम स्पष्ट है और इस तरह और अधिक आश्चर्यजनक है जब यह आप हिट होगा।


8
विशेष मामले विस्मय को जोड़ते हैं।
ब्लरफ्ल

17
1995 में स्ट्रिंग्स एक लक्जरी थीं? वास्तव में?? कंप्यूटर भाषाओं के इतिहास को देखें। उस समय कुछ प्रकार की स्ट्रिंग वाली भाषाओं की संख्या उन लोगों से कहीं अधिक थी, जो नहीं करते थे। C के अलावा कितनी भाषाएं हैं और इसके वंशजों ने शून्य समाप्त सरणियों का उपयोग किया है?
वारेनटी

14
@WarrenT: निश्चित रूप से, कुछ (यदि अधिकांश नहीं) भाषाओं में कुछ प्रकार के स्ट्रिंग थे, लेकिन यूनिकोड-सक्षम, कचरा-एकत्र किए गए तार 1995 में एक नवीनता थे, मुझे लगता है। उदाहरण के लिए, पायथन ने वर्ष २००० के संस्करण २.० के साथ यूनिकोड के तार पेश किए। अपरिवर्तनीयता चुनना भी उस समय के लिए एक विवादास्पद विकल्प था।
जूनस पुलकका

3
@JoonasPulakka तब शायद आपको अपना उत्तर संपादित करने के लिए कहना चाहिए। क्योंकि यह खड़ा है, आपके जवाब का "कुल लक्जरी" हिस्सा काफी गलत है।
svick

1
इंटरस्टिंग में एक लागत होती है: आपको एक स्ट्रिंग मिलती है जिसे कभी भी निपटाया नहीं जाएगा। (ठीक है, तब तक नहीं जब तक कि आप अपने खुद के इंटर्निंग इंजन का उपयोग नहीं करते हैं जिसे आप फेंक सकते हैं।)
डोनल फैलो

32

जावा के निर्माता जेम्स गोसलिंग ने इसे जुलाई 2000 में इस तरह समझाया :

मैंने ऑपरेटर को अत्यधिक व्यक्तिगत पसंद के रूप में ओवरलोडिंग छोड़ दिया क्योंकि मैंने बहुत से लोगों को सी ++ में इसका दुरुपयोग करते देखा था। मैंने पिछले पांच से छह वर्षों में बहुत समय बिताया है, जो ऑपरेटर ओवरलोडिंग के बारे में लोगों का सर्वेक्षण कर रहा है और यह वास्तव में आकर्षक है, क्योंकि आप समुदाय को तीन टुकड़ों में तोड़ देते हैं: संभवतः लगभग 20 से 30 प्रतिशत आबादी ऑपरेटर ओवरलोडिंग के बारे में सोचते हैं। शैतान के स्पॉन; किसी ने ऑपरेटर को ओवरलोडिंग के साथ कुछ किया है जो वास्तव में उन्हें बंद कर दिया है, क्योंकि उन्होंने सूची प्रविष्टि के लिए + का उपयोग किया है और यह जीवन को वास्तव में, वास्तव में भ्रमित करता है। इस समस्या का एक बहुत कुछ इस तथ्य से उपजा है कि लगभग आधा दर्जन ऑपरेटर हैं जो आप समझदारी से ओवरलोड कर सकते हैं, और फिर भी हजारों या लाखों ऑपरेटर हैं जिन्हें लोग परिभाषित करना चाहते हैं - इसलिए आपको चुनना होगा


50
आह, हाँ, पुराने "देता है 'नुकीले उपकरण को कुंद कर देते हैं ताकि ओफ खुद को चोट न पहुंचाए।"
ब्लरफ्ल

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

15
-1। इस सवाल का जवाब बिल्कुल नहीं है। जावा करता ऑपरेटर ओवरलोडिंग की है। ==ऑपरेटर वस्तुओं और पुरातन के लिए ओवरलोड हो गया है। +ऑपरेटर के लिए ओवरलोड हो गया है byte, short, int, long, float, double, Stringऔर शायद एक दूसरों की जोड़ी मैं भूल गया था। यह पूरी तरह से संभव हो गया होता ओवरलोड ==के लिए Stringके रूप में अच्छी तरह से।
जॉर्ग डब्ल्यू मित्तग

10
@ जॉर्ग - नहीं यह नहीं है। उपयोगकर्ता स्तर पर परिभाषित करने के लिए ऑपरेटर ओवरलोडिंग असंभव है। संकलक में वास्तव में कुछ विशेष मामले हैं, लेकिन यह शायद ही योग्य है
AZ01

9
@ ब्लरफ्ल: मुझे इस बात से ऐतराज नहीं है कि ओफ्स खुद को चोट पहुंचा रहे हैं। यह तब होता है जब वे गलती से मेरी आंख फोड़ देते हैं कि मैं नाराज हो जाता हूं।
जोनास

9

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

जावा के भीतर:

  • संख्यात्मक प्रकारों के बीच, ==संख्यात्मक समानता की तुलना करता है
  • बूलियन प्रकारों के बीच, ==बूलियन समानता की तुलना करता है
  • वस्तुओं के बीच, ==संदर्भ पहचान की तुलना करता है
    • .equals(Object o)मूल्यों की तुलना करने के लिए उपयोग करें

बस। सरल नियम और आप क्या चाहते हैं की पहचान करने के लिए सरल। यह सब JLS की धारा 15.21 में शामिल है । इसमें तीन उपसमूह शामिल हैं, जिनके बारे में समझना, लागू करना और कारण जानना आसान है।

एक बार जब आप ओवरलोडिंग की अनुमति देते हैं== , तो सटीक व्यवहार कुछ ऐसा नहीं है जिसे आप जेएलएस को देख सकते हैं और अपनी उंगली को किसी विशेष आइटम पर रख सकते हैं और कह सकते हैं कि "यह कैसे काम करता है," कोड के बारे में तर्क करना मुश्किल हो सकता है। ==एक उपयोगकर्ता के लिए सटीक व्यवहार आश्चर्यजनक हो सकता है। हर बार जब आप इसे देखते हैं, तो आपको वापस जाकर देखना होगा कि वास्तव में इसका क्या मतलब है।

चूंकि जावा ऑपरेटरों के ओवरलोडिंग के लिए अनुमति नहीं देता है, इसलिए किसी को एक मूल्य समानता परीक्षण करने की आवश्यकता होती है जिसे आप आधार परिभाषा को ओवरराइड कर सकते हैं। इस प्रकार, यह इन डिजाइन विकल्पों द्वारा अनिवार्य था। ==जावा में संख्यात्मक प्रकारों के लिए संख्यात्मक परीक्षण, बूलियन प्रकारों के लिए बूलियन समानता, और बाकी सब चीजों के लिए संदर्भ समानता (जो .equals(Object o)मूल्य समानता के लिए जो कुछ भी करना चाहते हैं उसे करने के लिए ओवरराइड कर सकते हैं )।

यह "इस डिजाइन निर्णय के किसी विशेष परिणाम के लिए उपयोग मामला है" का एक मुद्दा नहीं है, बल्कि "यह इन अन्य चीजों को सुविधाजनक बनाने के लिए एक डिजाइन निर्णय है, यह इसका एक परिणाम है।"

स्ट्रिंग इंटर्निंग , इसका एक ऐसा उदाहरण है। जेएलएस 3.10.5 के अनुसार , सभी स्ट्रिंग शाब्दिक इंटर्न हैं। अन्य स्ट्रिंग्स को नजरअंदाज कर दिया जाता है यदि कोई .intern()उन पर आक्रमण करता है। यह "foo" == "foo"सच है, स्ट्रिंग शाब्दिकों द्वारा लिए गए स्मृति पदचिह्न को कम करने के लिए किए गए डिजाइन निर्णयों का एक परिणाम है। इसके अलावा, स्ट्रिंग इंटर्निंग एक ऐसी चीज है जो जेवीएम स्तर पर होती है, जिसमें उपयोगकर्ता के लिए थोड़ा सा जोखिम होता है, लेकिन भारी बहुमत के मामलों में, ऐसा कुछ नहीं होना चाहिए जो प्रोग्रामर को चिंतित करता हो (और प्रोग्रामर के लिए मामलों का उपयोग नहीं करता था) कुछ ऐसा है जो इस सुविधा पर विचार करते समय डिजाइनरों के लिए सूची में उच्च था)।

लोग बताते हैं कि +और +=स्ट्रिंग के लिए अतिभारित हैं। हालाँकि, यह न तो यहाँ है और न ही वहाँ है। यह स्थिति बनी हुई है कि यदि ==स्ट्रिंग (और केवल स्ट्रिंग) के लिए मान समानता अर्थ है, तो संदर्भ समानता के लिए किसी को एक अलग विधि (जो केवल स्ट्रिंग में मौजूद है) की आवश्यकता होगी । इसके अलावा, यह अनावश्यक रूप से जटिल तरीके होंगे जो ऑब्जेक्ट लेते हैं और ==एक तरह से व्यवहार करने की अपेक्षा करते हैं और एक और .equals()व्यवहार करने की आवश्यकता होती है ताकि उपयोगकर्ताओं को स्ट्रिंग के लिए उन सभी तरीकों को विशेष स्थिति में लाया जा सके।

==वस्तुओं पर लगातार अनुबंध यह है कि यह केवल संदर्भ समानता है और यह .equals(Object o)उन सभी वस्तुओं के लिए मौजूद है, जिन्हें मूल्य समानता के लिए परीक्षण करना चाहिए । इसकी शिकायत करना बहुत सारी चीजों को दूर करता है।


जवाब देने में व़क्त लेने के लिए शुक्रिया। यह उन अन्य सवालों पर बहुत अच्छा जवाब होगा, जिनसे मैं जुड़ा था। दुर्भाग्य से, यह इस प्रश्न के लिए उपयुक्त नहीं है। मैं टिप्पणियों के आधार पर स्पष्टीकरण के साथ ओपी को अपडेट करूंगा। मैं उन उपयोग मामलों की तलाश कर रहा हूं, जहां एक भाषा-उपयोगकर्ता स्ट्रिंग की तुलना करते समय गलत-नकारात्मक होना चाहता है। भाषा इस सुविधा को स्थिरता के रूप में प्रदान करती है, अब मैं चाहूंगा कि हम एक कदम और आगे बढ़ें। शायद नई भाषा के डिजाइनर से इस बारे में सोचना, क्या इसकी आवश्यकता है? (दुर्भाग्य से, कोई लैंगडेसाइन.ईएस)
एंसनेज

3
@ एक झूठी नकारात्मक नहीं है। वे एक ही वस्तु नहीं हैं। बस इतना ही कह रही है। मुझे यह भी बताना चाहिए कि जावा 8 में, new String("foo") == new String("foo")सच हो सकता है ( स्ट्रिंग डेडुप्लीकेशन देखें )।

1
भाषा डिजाइन के अनुसार, CS.SE विज्ञापन देता है कि यह विषय पर हो सकता है।

ऊह, धन्यवाद! मैं अपने भविष्य के लैंग-डिज़ाइन प्रश्नों को वहां पोस्ट करूंगा। :) और, हाँ, दुर्भाग्य से 'गलत-नकारात्मक' मेरे सवाल का वर्णन करने के लिए सबसे सटीक तरीका नहीं है और मैं जो खोज रहा हूँ .. मुझे और अधिक शब्द लिखने की ज़रूरत है ताकि लोगों को यह अनुमान लगाने की ज़रूरत न हो कि मैं क्या हूँ कहने की कोशिश।
अनॉसेज

2
"भाषा के भीतर संगति" भी जेनरिक के साथ मदद करता है
ब्रेंडन

2

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

मैं C # में कोई विशेषज्ञ नहीं हूं, लेकिन उस भाषा के डिजाइनरों ने इसे ऐसे स्थापित किया है कि हर आदिम एक है structऔर हर structएक वस्तु है। चूँकि C # ऑपरेटर को ओवरलोडिंग की अनुमति देता है, इसलिए यह व्यवस्था Stringकिसी भी ऑपरेटर के लिए "अपेक्षित" तरीके से खुद को काम करने के लिए, किसी भी वर्ग के लिए बहुत आसान नहीं बनाती है। C ++ एक ही चीज़ की अनुमति देता है।


1
"जावा ऑपरेटर ओवरलोडिंग का समर्थन नहीं करता है, जिसका अर्थ है == केवल आदिम प्रकार या संदर्भों पर लागू होता है। किसी अन्य चीज को किसी विधि की आवश्यकता होती है।": एक जोड़ सकता है कि यदि ==स्ट्रिंग समानता का मतलब है, तो हमें संदर्भ समानता के लिए एक और नोटेशन की आवश्यकता होगी।
जियोर्जियो

@ जियोर्जियो: बिल्कुल। गिलद नामन के उत्तर पर मेरी टिप्पणी देखें।
ब्लरफ्ल

यद्यपि यह एक स्थिर विधि द्वारा हल किया जा सकता है जो दो वस्तुओं (या एक ऑपरेटर) के संदर्भों की तुलना करता है। उदाहरण के लिए, C # में।
गिलाद नामन

@ गिलादनामन: यह एक शून्य-राशि वाला खेल होगा क्योंकि यह जावा के पास अब विपरीत समस्या का कारण बनता है: समानता एक ऑपरेटर पर होगी और आपको संदर्भों की तुलना करने के लिए एक विधि लागू करनी होगी। इसके अलावा, आपको यह शर्त भी लगानी होगी कि सभी वर्ग कुछ ऐसा लागू करें जिससे वह बाध्य हो सके ==। यह प्रभावी रूप से ऑपरेटर ओवरलोडिंग को जोड़ रहा है, जो कि जावा को लागू करने के तरीके पर जबरदस्त प्रभाव पड़ेगा।
ब्लरफ्ल

1
@ ब्लरफ्ल: वास्तव में नहीं। संदर्भ की तुलना करने के लिए हमेशा एक परिभाषित तरीका होगा ( ClassName.ReferenceEquals(a,b)), और एक डिफ़ॉल्ट ==ऑपरेटर और Equalsविधि दोनों की ओर इशारा करता है ReferenceEquals
गिलाद नमन

2

इसे अन्य भाषाओं में अलग बनाया गया है।

ऑब्जेक्ट पास्कल (डेल्फी / फ्री पास्कल) और सी # में, समानता ऑपरेटर को मूल्यों की तुलना करने के लिए परिभाषित किया गया है, संदर्भ नहीं, जब तार पर काम करते हैं।

विशेष रूप से पास्कल में, स्ट्रिंग एक आदिम प्रकार है (चीजों में से एक है जो मैं पास्कल के बारे में बहुत प्यार करता हूं, सिर्फ एक असंक्रामक स्ट्रिंग के कारण NullreferenceException प्राप्त करना बस परेशान कर रहा है) और इस तरह से (ज्यादातर समय) स्ट्रिंग संचालन को कॉपी-ऑन-राइट लिखना है। सस्ते (दूसरे शब्दों में, केवल एक बार जब आप बहु-मेगाबाइट स्ट्रिंग्स को बदलना शुरू कर सकते हैं)।

तो, यह जावा के लिए एक भाषा डिजाइन निर्णय है। जब उन्होंने भाषा डिज़ाइन की तो उन्होंने C ++ तरीका (जैसे Std :: String) का अनुसरण किया, ताकि तार एक ऑब्जेक्ट हैं, जो कि IM को स्ट्रिंग को एक आदिम बनाने के बजाय एक वास्तविक स्ट्रिंग प्रकार की कमी की भरपाई करने के लिए एक IMHO है।

तो एक कारण के लिए, मैं केवल यह अनुमान लगा सकता हूं कि उन्होंने अपने पक्ष में आसान बनाने के लिए और ऑपरेटर को कोडिंग नहीं करने के लिए संकलक पर एक अपवाद बना दिया।


यह पूछे गए प्रश्न का उत्तर कैसे देता है?
gnat

अंतिम वाक्य देखें (जो मैं एक संपादन में एक उचित पैराग्राफ में अलग हो गया)।
फैब्रिकियो अराजू

1
IMHO, Stringजावा में एक आदिम प्रकार होना चाहिए था। अन्य प्रकारों के विपरीत, संकलक के बारे में जानना आवश्यक है String; इसके अलावा, इस पर परिचालन पर्याप्त रूप से सामान्य होगा कि कई प्रकार के आवेदन के लिए वे एक प्रदर्शन अड़चन पैदा कर सकते हैं (जिसे देशी समर्थन से कम किया जा सकता है)। एक विशिष्ट string[लोअरकेस] के पास अपनी सामग्री रखने के लिए ढेर पर आवंटित एक वस्तु होगी, लेकिन उस वस्तु के लिए कोई "सामान्य" संदर्भ कहीं भी मौजूद नहीं होगा; इस प्रकार यह किसी अन्य वस्तु के माध्यम से अप्रत्यक्ष होने के बजाय एकल-अप्रत्यक्ष Char[]या Byte[]हो सकता है Char[]
सुपरकाट

1

जावा में, कोई भी ऑपरेटर ओवरलोडिंग नहीं करता है, और यही कारण है कि तुलनात्मक ऑपरेटर केवल आदिम प्रकारों के लिए अतिभारित होते हैं।

'स्ट्रिंग' वर्ग एक आदिम नहीं है, इस प्रकार इसमें '==' के लिए अधिभार नहीं है और कंप्यूटर की मेमोरी में ऑब्जेक्ट के पते की तुलना करने के डिफ़ॉल्ट का उपयोग करता है।

मुझे यकीन नहीं है, लेकिन मुझे लगता है कि जावा 7 या 8 में ओरेकल को कंपाइलर में एक अपवाद के str1 == str2रूप में पहचानने के लिए बनाया गया हैstr1.equals(str2)


"मुझे यकीन नहीं है, लेकिन मुझे लगता है कि जावा में 7 या 8 ऑरेकल ने संकलक में एक अपवाद बना दिया str1 == str2 को str1.equals (str2) के रूप में पहचानने के लिए": मुझे आश्चर्य नहीं होगा: Oracle कम चिंतित लगता है सूर्य की तुलना में अतिसूक्ष्मवाद था।
जियोर्जियो

2
यदि सही है, तो यह एक बहुत ही बदसूरत हैक है क्योंकि इसका मतलब है कि अब एक वर्ग है जो भाषा अन्य सभी से अलग व्यवहार करता है और संदर्भों की तुलना करने वाले कोड को तोड़ता है। : - @
ब्लरफ्ल

1
@WillihamTotland: विपरीत मामले पर विचार करें। वर्तमान में, यदि मैं दो तार बनाता हूं, s1और s2उन्हें समान सामग्री देता हूं, तो वे समानता ( s1.equals(s2)) तुलना नहीं बल्कि समान-संदर्भ ( ==) तुलना करते हैं क्योंकि वे दो अलग-अलग वस्तुएं हैं। अर्थ के ==समानता को बदलने का कारण यह s1 == s2मूल्यांकन करना होगा trueकि यह कहां मूल्यांकन करता था false
ब्लरफ्ल

2
@Brlfl: जबकि यह सच है, कि पहली जगह पर भरोसा करने के लिए एक असाधारण बुरी चीज की तरह लगता है, क्योंकि तार अपरिवर्तनीय, आंतरिक वस्तुओं हैं।
विलीह टोटलैंड

2
@ जियोर्जियो: "जावा 7 या 8 ओरेकल ने संकलक में एक अपवाद बना दिया str1 == str2 को str1.equals (str2) के रूप में पहचानने के लिए" , नोप , जावा भाषा विनिर्देश कहता है: संदर्भ समानता ऑपरेटर : "यदि एक समानता ऑपरेटर के ऑपरेटर हैं दोनों संदर्भ प्रकार या अशक्त प्रकार, फिर ऑपरेशन ऑब्जेक्ट समानता है। " बस आज के लिए इतना ही। मुझे इस बारे में जावा 8 के शुरुआती मसौदे में कुछ भी नया नहीं मिला ।
डेविड टोनहोफर

0

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

यह नियम जावा के लिए शायद ही अनूठा है, लेकिन भाषा के अन्य प्रकार से संबंधित पहलुओं के डिजाइन पर इसके कुछ दूरगामी (और IMHO दुर्भाग्यपूर्ण) प्रभाव हैं। यह ==विशेष प्रकार के ऑपरेंड प्रकारों के संयोजन के साथ व्यवहार को निर्दिष्ट करने के लिए क्लीनर होगा , और प्रकार X और Y के निषिद्ध संयोजनों के लिए जहां x1==y1और x2==y1नहीं होगा x1==x2, लेकिन भाषाओं शायद ही कभी ऐसा करती है [उस दर्शन के तहत, double1 == long1या तो यह इंगित करना होगा कि क्या double1का सटीक निरूपण नहीं है long1, अन्यथा संकलन करने से मना कर दिया जाता है;int1==Integer1निषिद्ध होना चाहिए, लेकिन परीक्षण का एक सुविधाजनक और कुशल गैर-फेंकने वाला साधन होना चाहिए कि क्या एक वस्तु विशेष मूल्य के साथ एक बॉक्सिंग पूर्णांक है (किसी चीज की तुलना में जो बॉक्सर पूर्णांक नहीं है, बस वापस आ जाना चाहिए false)]।

==ऑपरेटर को स्ट्रिंग्स में लागू करने के संबंध में , यदि जावा ने टाइप के ऑपरेंड्स के बीच प्रत्यक्ष तुलना की मनाही की है Stringऔर Object, यह व्यवहार में आश्चर्यजनक रूप से आश्चर्यचकित कर सकता है ==, लेकिन ऐसा कोई व्यवहार नहीं है जो ऐसी तुलनाओं के लिए लागू हो सकता है जो आश्चर्यजनक नहीं होगा। प्रकार में रखे गए दो स्ट्रिंग संदर्भों को प्रकार में रखे गए Objectसंदर्भों से अलग तरह से व्यवहार करते Stringहैं, उन दोनों में से किसी भी व्यवहार की तुलना में एक कानूनी मिश्रित प्रकार की तुलना में भिन्न होने की तुलना में बहुत आश्चर्यजनक होगा। अगर String1==Object1कानूनी है, तो इसका मतलब यह होगा कि उनके व्यवहार String1==String2और Object1==Object2मैच के लिए एकमात्र तरीका String1==Object1एक दूसरे से मेल खाना होगा।


मुझे कुछ याद आ रहा होगा, लेकिन आइएमएचओ ==को वस्तुओं की पहचान के लिए बस (शून्य-सुरक्षित) समान और कुछ और (जैसे, ===या System.identityEqual) का उपयोग किया जाना चाहिए। मिश्रण आदिम और वस्तुओं को शुरू में निषिद्ध किया जाएगा (1.5 से पहले कोई ऑटोबॉक्सिंग नहीं था) और फिर कुछ सरल नियम पाए जा सकते हैं (जैसे शून्य-सुरक्षित अनबॉक्स, फिर डाली, फिर तुलना करें)।
माॅर्टिनस

@maaartinus: एक अच्छी भाषा डिजाइन में मूल्य और संदर्भ समानता के लिए अलग-अलग समानता ऑपरेटरों का उपयोग करना चाहिए। जबकि मैं मानता हूं कि वैचारिक रूप से यह संभव है कि यदि int==Integerऑपरेटर अशक्त है, और अन्यथा मूल्यों की तुलना करें, तो यह दृष्टिकोण अन्य सभी परिस्थितियों में व्यवहार के विपरीत होगा , जहां यह बिना शर्त दोनों ऑपरेंड को एक ही प्रकार से पहले करता है। उनकी तुलना करना। व्यक्तिगत रूप से मुझे आश्चर्य होता है कि क्या ऑटो- falseInteger==int==Integer
अनबॉक्सिंग

... चूंकि ऑटोबॉक्सिंग intऔर एक संदर्भ तुलना करना मूर्खतापूर्ण होता [लेकिन हमेशा विफल नहीं होता]। अन्यथा, मुझे एक निहित रूपांतरण की अनुमति देने का कोई कारण नहीं दिखता है जो कि एनपीई के साथ विफल हो सकता है।
सुपरकैट

मुझे लगता है कि मेरा विचार सुसंगत है। बस यह ध्यान रखें कि बेहतर दुनिया में, ==कुछ नहीं करना है identityEquals। +++ "मूल्य और संदर्भ समानता के लिए अलग-अलग समानता ऑपरेटर" - लेकिन कौन से? मैं संदर्भ के मूल्य को देखने वाले अर्थों में दोनों की तुलना में आदिम ==और मूल्य की तुलना equalsकर रहा हूं । +++ जब इसका मतलब है , तो ऑटोबॉक्सिंग करना चाहिए और अशक्त-सुरक्षित बराबरी का उपयोग करके संदर्भों की तुलना करें। +++ मुझे डर है, मेरा विचार वास्तव में मेरा नहीं है, लेकिन सिर्फ कोटलिन क्या करता है। equals==equalsint==Integer
माॅर्टिनस

@maaartinus: यदि ==कभी संदर्भ समानता का परीक्षण नहीं किया जाता है, तो यह समझदारी से अशक्त-सुरक्षित मूल्य-समानता परीक्षण कर सकता है। तथ्य यह है कि यह संदर्भ समानता का परीक्षण करता है , हालांकि, गंभीर रूप से सीमित करता है कि यह असंगतता के बिना मिश्रित संदर्भ / मूल्य तुलना को कैसे संभाल सकता है। यह भी ध्यान दें कि जावा इस धारणा पर तय किया गया है कि ऑपरेटर दोनों प्रकारों के संयोजन के आधार पर विशेष व्यवहार की उपज के बजाय दोनों ऑपरेंड को एक ही प्रकार को बढ़ावा देते हैं। उदाहरण के लिए, 16777217==16777216.0fरिटर्न , trueक्योंकि यह पहले ऑपरेंड का एक हानिपूर्ण रूपांतरण करता है float, जबकि एक ...
सुपरकैट

0

सामान्य तौर पर, दो ऑब्जेक्ट संदर्भ एक ही ऑब्जेक्ट को इंगित करने में सक्षम होने के लिए परीक्षण करने में सक्षम होने का बहुत अच्छा कारण है। मैंने बहुत बार लिखा है कि मैंने लिखा है

Address oldAddress;
Address newAddress;
... populate values ...
if (oldAddress==newAddress)
... etc ...

ऐसे मामलों में मेरे पास बराबरी का काम हो भी सकता है और नहीं भी। यदि मैं करता हूं, तो समान फ़ंक्शन दोनों ऑब्जेक्ट की संपूर्ण सामग्री की तुलना कर सकता है। अक्सर यह सिर्फ कुछ पहचानकर्ता की तुलना करता है। "ए और बी एक ही वस्तु के संदर्भ हैं" और "ए और बी एक ही सामग्री के साथ दो अलग-अलग वस्तुएं हैं", ज़ाहिर है, दो बहुत अलग विचार।

यह शायद सच है कि अपरिवर्तनीय वस्तुओं के लिए, स्ट्रिंग्स की तरह, यह एक मुद्दे से कम है। अपरिवर्तनीय वस्तुओं के साथ, हम वस्तु और मूल्य को एक ही चीज़ के रूप में सोचते हैं। ठीक है, जब मैं कहता हूं "हम", मेरा मतलब है "मैं", कम से कम।

Integer three=new Integer(3);
Integer triangle=new Integer(3);
if (three==triangle) ...

बेशक जो गलत है, लेकिन मैं किसी को यह सोचते हुए देख सकता हूं कि यह सच होना चाहिए।

लेकिन एक बार जब आप कहते हैं कि == संदर्भ हैंडल की तुलना करता है और सामान्य रूप से वस्तुओं के लिए सामग्री नहीं है, तो स्ट्रिंग्स के लिए एक विशेष मामला बनाना संभावित रूप से भ्रामक होगा। जैसा कि यहाँ पर किसी और ने कहा, क्या होगा यदि आप दो स्ट्रिंग वस्तुओं के हैंडल की तुलना करना चाहते हैं? क्या केवल स्ट्रिंग्स के लिए कुछ विशेष कार्य करना होगा?

और क्या इस बारे में ...

Object x=new String("foo");
Object y=new String("foo");
if (x==y) ...

क्या यह गलत है क्योंकि वे दो अलग-अलग वस्तुएं हैं, या सत्य हैं क्योंकि वे स्ट्रिंग्स हैं जिनकी सामग्री समान हैं?

तो हाँ, मैं समझता हूँ कि प्रोग्रामर इससे कैसे भ्रमित होते हैं। मैंने इसे स्वयं किया है, मेरा मतलब है कि अगर myString.equals ("फू") का मतलब है तो myString == "foo" लिखें। लेकिन सभी वस्तुओं के लिए == ऑपरेटर के अर्थ को नया स्वरूप देने से कम, मैं यह नहीं देखता कि इसे कैसे संबोधित किया जाए।


ध्यान दें कि जेवीएम पर अन्य आधुनिक भाषाएं, जैसे कि स्काला, का ==अर्थ "समान तार" है।
एंड्रेस एफ।

@AndresF। (श्रग) जावा में, "<" का अर्थ है "से कम", जबकि एक्सएमएल में यह "एक टैग खोलता है"। VB में "=" का अर्थ "बराबर" हो सकता है, जबकि जावा में इसका उपयोग केवल असाइनमेंट के लिए किया जाता है। आदि यह शायद ही आश्चर्य की बात है कि अलग-अलग भाषाएं अलग-अलग प्रतीकों का उपयोग एक ही चीज़, या अलग-अलग चीज़ों का मतलब करने के लिए एक ही प्रतीक का उपयोग करती हैं।
जय

यह आपके जवाब पर हर्ज नहीं था। यह सिर्फ एक टिप्पणी थी। मैं सिर्फ इशारा कर रहा था कि जावा की तुलना में अधिक आधुनिक भाषा ने अर्थ को फिर से डिज़ाइन करने का मौका लिया ==, जैसा कि आपने अंत में उल्लेख किया है।
एंड्रेस एफ।

@AndresF। और मेरा जवाब आपकी टिप्पणी पर हतप्रभ नहीं था, बस यह कह रहा था कि विभिन्न भाषाएं इन मुद्दों को अलग-अलग तरीकों से अपनाती हैं। :-) मैं वास्तव में जिस तरह से VB इसे संभालता हूं ... VB हैटर्स से hisses और boos के लिए रुकें ... "=" हमेशा मूल्य की तुलना करता है (सिस्टम-परिभाषित प्रकारों के लिए), चाहे वह आदिम हो या वस्तु। "है" दो वस्तुओं के हैंडल की तुलना करता है। वह मुझे अधिक सहज लगता है।
Jay

ज़रूर। लेकिन Scala विजुअल बेसिक की तुलना में जावा के करीब है। मुझे लगता है कि स्काला के डिजाइनरों को एहसास हुआ कि जावा का उपयोग ==त्रुटि प्रवण था।
एंड्रेस एफ।

0

इस के लिए एक वैध सवाल है Strings, और न केवल तार के लिए, बल्कि अन्य अपरिवर्तनीय कुछ "मूल्य" का प्रतिनिधित्व वस्तुओं, उदाहरण के लिए Double, BigIntegerऔर यहां तक कि InetAddress

==ऑपरेटर को स्ट्रिंग्स और अन्य मूल्य-वर्गों के साथ प्रयोग करने योग्य बनाने के लिए , मुझे तीन विकल्प दिखाई देते हैं:

  • संकलक को इन सभी मूल्य-वर्गों और उनकी सामग्री की तुलना करने के तरीके के बारे में पता है। यदि यह java.langपैकेज से केवल कुछ मुट्ठी भर कक्षाएं थीं , तो मैं इस पर विचार करूंगा, लेकिन यह InetAddress जैसे मामलों को कवर नहीं करता है।

  • ऑपरेटर को ओवरलोडिंग की अनुमति दें ताकि एक वर्ग उसके ==तुलनात्मक व्यवहार को परिभाषित करे ।

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

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

मेरे लिए, कोड पठनीयता सबसे महत्वपूर्ण है, और एक जावा प्रोग्रामर जानता है कि ऑपरेटरों का एक निश्चित अर्थ है, भाषा विनिर्देश में परिभाषित किया गया है, जबकि तरीकों को कुछ कोड द्वारा परिभाषित किया गया है, और उनके अर्थ को विधि के Javadoc में देखना होगा। मैं उस अंतर के साथ रहना चाहता हूं, भले ही इसका मतलब है कि स्ट्रिंग तुलना ==ऑपरेटर का उपयोग करने में सक्षम नहीं होगा ।

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

    int i=123456;
    Integer j=123456;
    Integer k=123456;
    System.out.println(i==j);  // true or false? Do you know without reading the specs?
    System.out.println(j==k);  // true or false? Do you know without reading the specs?
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.