जावा में अपरिभाषित व्यवहार


14

मैं SO पर इस प्रश्न को पढ़ रहा था जिसमें C ++ में कुछ सामान्य अपरिभाषित व्यवहार की चर्चा है, और मैंने सोचा: क्या जावा में भी अपरिभाषित व्यवहार होता है?

यदि ऐसा है, तो जावा में अपरिभाषित व्यवहार के कुछ सामान्य कारण क्या हैं?

यदि नहीं, तो जावा की कौन सी विशेषताएँ इसे ऐसे व्यवहारों से मुक्त बनाती हैं और इन गुणों के साथ C और C ++ के नवीनतम संस्करण क्यों नहीं लागू किए गए हैं?


4
जावा को बहुत कठोरता से परिभाषित किया गया है। जावा लैंग्वेज स्पेसिफिकेशन की जांच करें।


4
@ user1249, "अपरिभाषित व्यवहार" वास्तव में बहुत कठोरता से परिभाषित किया गया है।
पचेरियर

SO पर संभावित समान: stackoverflow.com/questions/376338/…
Ciro Santilli 中心:::

जब आप "अनुबंध" का उल्लंघन करते हैं, तो जावा क्या कहता है? जब आप ओवरलोड हो जाते हैं, जैसे कि .hashCode के साथ असंगत होना? docs.oracle.com/javase/7/docs/api/java/lang/… क्या वह बोलचाल की भाषा अपरिभाषित है, लेकिन तकनीकी रूप से उसी तरह से नहीं है जैसे C ++ है?
मूइंग डक

जवाबों:


18

जावा में, आप गलत तरीके से सिंक्रनाइज़ प्रोग्राम के व्यवहार को अपरिभाषित मान सकते हैं।

जावा 7 जेएलएस 17.4.8 में एक बार "अपरिभाषित" शब्द का उपयोग करता है अपवाद और कारण आवश्यकताएँ :

हम का उपयोग f|dसमारोह के डोमेन सीमित कर दिया निरूपित करने के लिए fकरने के लिए d। सभी के लिए xमें d, f|d(x) = f(x)है, और सभी के लिए xनहीं d, f|d(x)है अपरिभाषित ...

जावा API दस्तावेज़ निर्दिष्ट करता है कुछ मामलों जब परिणाम अपरिभाषित कर रहे हैं - उदाहरण के लिए, में (बहिष्कृत) निर्माता की तारीख (पूर्णांक साल, पूर्णांक महीने, पूर्णांक दिन) :

यदि कोई दिया गया तर्क सीमा से बाहर है तो परिणाम अपरिभाषित है ...

ExecutorService.invokeAll (संग्रह) स्थिति के लिए Javadocs :

यदि यह ऑपरेशन प्रगति पर है, तो इस पद्धति के परिणाम अपरिभाषित हैं ।

उदाहरण के लिए समवर्ती "अपरिभाषित" व्यवहार का कम औपचारिक प्रकार पाया जा सकता है , जहां एपीआई डॉक्स "सर्वश्रेष्ठ प्रयास" शब्द का उपयोग करते हैं:

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


अनुबंध

सवाल टिप्पणियों में से एक एरिक लिपर्ट के एक लेख को संदर्भित करता है जो विषय मामलों में उपयोगी परिचय प्रदान करता है: कार्यान्वयन-परिभाषित व्यवहार

मैं इस लेख को भाषा-अज्ञेय तर्क के लिए सुझाता हूं, हालांकि यह ध्यान में रखने योग्य है कि लेखक सी # को लक्षित करता है, जावा को नहीं।

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

इसके विपरीत, एक मुहावरा जिसमें कार्यान्वयन-परिभाषित व्यवहार होता है वह व्यवहार होता है जहां संकलक लेखक के पास सुविधा को लागू करने के तरीके के बारे में कई विकल्प होते हैं, और उसे चुनना चाहिए। जैसा कि नाम का तात्पर्य है, कार्यान्वयन-परिभाषित व्यवहार कम से कम परिभाषित है। उदाहरण के लिए, जब कोई पूर्णांक विभाजन ओवरफ्लो होता है, तो C # एक अपवाद को लागू करने या एक मान उत्पन्न करने के लिए कार्यान्वयन की अनुमति देता है, लेकिन कार्यान्वयन को चुनना चाहिए। यह आपकी हार्ड डिस्क को नहीं मिटा सकता ...

ऐसे कुछ कारक हैं जो एक भाषा डिजाइन समिति को कुछ भाषा मुहावरों को अपरिभाषित या कार्यान्वयन-परिभाषित व्यवहार के रूप में छोड़ने के लिए नेतृत्व करते हैं?

पहला प्रमुख कारक है: क्या बाज़ार में भाषा के दो मौजूदा कार्यान्वयन हैं जो किसी विशेष कार्यक्रम के व्यवहार पर असहमत हैं? ...

अगला प्रमुख कारक है: क्या सुविधा स्वाभाविक रूप से कार्यान्वयन के लिए कई अलग-अलग संभावनाएं प्रस्तुत करती है, जिनमें से कुछ स्पष्ट रूप से दूसरों की तुलना में बेहतर हैं? ...

एक तीसरा कारक है: क्या सुविधा इतनी जटिल है कि उसके सटीक व्यवहार का विस्तृत विराम निर्दिष्ट करना मुश्किल या महंगा होगा? ...

एक चौथा कारक है: क्या विश्लेषण करने के लिए फीचर कंपाइलर पर अधिक बोझ डालता है? ...

एक पाँचवाँ कारक है: क्या सुविधा रनटाइम वातावरण पर एक उच्च बोझ लादती है? ...

एक छठा कारक है: व्यवहार को कुछ प्रमुख अनुकूलन को परिभाषित करने से रोकता है? ...

वे सिर्फ कुछ कारक हैं जो दिमाग में आते हैं; निश्चित रूप से कई, कई अन्य कारक हैं जो एक विशेषता "कार्यान्वयन परिभाषित" या "अपरिभाषित" बनाने से पहले भाषा डिजाइन समितियों पर बहस करते हैं।

ऊपर केवल एक बहुत ही संक्षिप्त कवरेज है; पूर्ण लेख में इस अंश में वर्णित बिंदुओं के लिए स्पष्टीकरण और उदाहरण हैं; यह है बहुत लायक पढ़ने। उदाहरण के लिए, "छठे कारक" के लिए दिए गए विवरण जावा मेमोरी मॉडल ( जेएसआर 133 ) में कई बयानों के लिए प्रेरणा में एक अंतर्दृष्टि दे सकते हैं , यह समझने में मदद करते हैं कि कुछ अनुकूलन की अनुमति क्यों है, अपरिभाषित व्यवहार के लिए अग्रणी जबकि अन्य निषिद्ध हैं, अग्रणी सीमाएँ जैसे -पहले और कार्य - कारण की आवश्यकताएँ

लेख सामग्री में से कोई भी मेरे लिए विशेष रूप से नया नहीं है, लेकिन अगर मैं कभी भी इसे इतने सुरुचिपूर्ण, आकर्षक और समझने योग्य तरीके से प्रस्तुत करता हूं तो मुझे बहुत परेशानी होगी। गजब का।


मैं जोड़ता हूँ कि JMM! = अंतर्निहित हार्डवेयर और संगामिति के संबंध में एक निष्पादन कार्यक्रम का अंतिम परिणाम एक WinIntel बनाम Solaris
Martijn Verburg

2
@MartijnVerburg यह एक बहुत अच्छा बिंदु है। केवल यही कारण है कि मैं इसे "अपरिभाषित" के रूप में टैग करने में संकोच करता हूं, यह है कि मेमोरी मॉडल घटित-पहले की तरह अड़चनें पैदा करता है और सही ढंग से सिंक किए गए कार्यक्रम के निष्पादन पर कारण
gnat

सच है, कल्पना यह परिभाषित करती है कि इसे जेएमएम के तहत कैसे व्यवहार करना चाहिए, हालांकि, इंटेल एट अल हमेशा सहमत नहीं होता
;;

@MartijnVerburg मुझे लगता है कि JMM का मुख्य बिंदु "असहमत" प्रोसेसर निर्माताओं से लीक से अधिक अनुकूलन को रोकना है । जहां तक ​​मैं समझता हूं कि 5.0 से पहले जावा को डीईसी अल्फा के साथ इस तरह का सिरदर्द था, जब हुड के तहत सट्टा लिखता है "पतली हवा से बाहर" जैसे कार्यक्रम में लीक हो सकता है - इसलिए, जेएसआर 133 (जेएमएम) में कारणता की आवश्यकता हुई
सूक्ति

9
@MartinVerburg - यह सुनिश्चित करना JVM कार्यान्वयनकर्ता का काम है कि JVM किसी समर्थित हार्डवेयर प्लेटफ़ॉर्म पर JLS / JMM युक्ति के अनुसार व्यवहार करता है। यदि अलग हार्डवेयर अलग तरीके से व्यवहार करता है, तो इससे निपटने के लिए जेवीएम कार्यान्वयनकर्ता का काम है ... और इसे काम करें।
स्टीफन सी।

10

मेरे सिर के ऊपर से, मुझे नहीं लगता कि जावा में कोई अपरिभाषित व्यवहार है, कम से कम सी ++ के समान अर्थ में नहीं।

इसका कारण यह है कि सी ++ के पीछे जावा के पीछे एक अलग दर्शन है। जावा का एक मुख्य डिजाइन लक्ष्य कार्यक्रमों को प्लेटफार्मों पर अपरिवर्तित रखने की अनुमति देना था, इसलिए विनिर्देशन सब कुछ बहुत स्पष्ट रूप से परिभाषित करता है।

इसके विपरीत, C और C ++ का एक मुख्य डिजाइन लक्ष्य दक्षता है: कोई भी विशेषताएं (प्लेटफ़ॉर्म इंडिपेंडेंस सहित) नहीं होनी चाहिए, भले ही आपको उनकी आवश्यकता न हो। इसके लिए, विनिर्देश जानबूझकर कुछ व्यवहारों को परिभाषित नहीं करता है क्योंकि उन्हें परिभाषित करने से कुछ प्लेटफार्मों पर अतिरिक्त काम होता है और इस प्रकार उन लोगों के लिए भी प्रदर्शन कम हो जाता है जो विशेष रूप से एक मंच के लिए कार्यक्रम लिखते हैं और इसके सभी अज्ञातताओं के बारे में जानते हैं।

यहां तक ​​कि एक उदाहरण भी है जहां जावा को सटीक रूप से उस कारण के लिए अपरिभाषित व्यवहार का एक सीमित रूप पेश करने के लिए मजबूर किया गया था: फ्लोटिंग पॉइंट गणनाओं को ठीक से IEEE 754 मानक का पालन करने की अनुमति देने के लिए जावा 1.2 में सख्त कीवर्ड पेश किया गया था जैसा कि पहले से मांग की गई थी। , क्योंकि ऐसा करने के लिए अतिरिक्त काम करना पड़ता है और कुछ सामान्य सीपीयू पर सभी फ्लोटिंग-पॉइंट गणनाओं को धीमा कर दिया जाता है, जबकि वास्तव में कुछ मामलों में खराब परिणाम उत्पन्न करते हैं।


2
मुझे लगता है कि जावा के अन्य मुख्य लक्ष्य को ध्यान में रखना महत्वपूर्ण है: सुरक्षा और अलगाव। मुझे लगता है कि यह भी 'अपरिभाषित' व्यवहार की कमी का एक कारण है (जैसा कि C ++ में)।

3
@ K.Steff: हाइपर-मॉडर्न C / C ++ सुरक्षा संबंधी किसी भी चीज के लिए पूरी तरह अनुपयुक्त है। यह देखते हुए int x=-1; foo(); x<<=1;अति आधुनिक दर्शन को फिर से लिखने एहसान होगा fooताकि किसी भी पथ जो बाहर निकलने नहीं पहुँच योग्य नहीं होना चाहिए। यह है, अगर fooहै if (should_launch_missiles) { launch_missiles(); exit(1); }एक संकलक (और कुछ लोगों के अनुसार होना चाहिए) बस को आसान बनाने में कर सकता है कि launch_missiles(); exit(1);। पारंपरिक यूबी यादृच्छिक कोड निष्पादन था, लेकिन यह समय और कारण के नियमों से बंधा हुआ था। नई बेहतर यूबी न तो बाध्य है।
सुपरकैट

3

जावा अपरिभाषित व्यवहार को समाप्त करने के लिए काफी प्रयास करता है, ठीक इससे पहले की भाषाओं के पाठों के कारण। उदाहरण के लिए, वर्ग-स्तरीय चर स्वचालित रूप से आरंभिक होते हैं; स्थानीय चर प्रदर्शन कारणों के लिए स्वत: आरंभिक नहीं हैं, लेकिन किसी को प्रोग्राम लिखने से रोकने के लिए परिष्कृत डेटा-प्रवाह विश्लेषण है जो इस का पता लगाने में सक्षम होगा। संदर्भ इंगित नहीं कर रहे हैं, इसलिए अमान्य संदर्भ मौजूद नहीं हो सकते हैं, और dereferencing nullएक विशिष्ट अपवाद का कारण बनता है।

बेशक कुछ व्यवहार ऐसे हैं जो पूरी तरह से निर्दिष्ट नहीं हैं, और यदि आप मान लेते हैं कि आप अविश्वसनीय कार्यक्रम लिख सकते हैं। उदाहरण के लिए, यदि आप एक सामान्य (गैर-सॉर्ट किए गए) पर पुनरावृति Setकरते हैं, तो भाषा गारंटी देती है कि आप प्रत्येक तत्व को एक बार देखेंगे, लेकिन उस क्रम में नहीं, जिस क्रम में आप उन्हें देखेंगे। क्रमिक रन पर आदेश समान हो सकता है, या यह बदल सकता है; या जब तक कोई अन्य आवंटन नहीं होता है, या जब तक आप अपने JDK को अपडेट नहीं करते हैं, आदि के रूप में यह वही रह सकता है, तो ऐसे सभी प्रभावों से छुटकारा पाना लगभग असंभव है ; उदाहरण के लिए, आपको स्पष्ट रूप से सभी संग्रह कार्यों को क्रमबद्ध या यादृच्छिक करना होगा, और यह केवल छोटे अतिरिक्त अन-अपरिभाषित-नेस के लायक नहीं है।


संदर्भ एक और नाम के तहत संकेत हैं
जिज्ञासु

@ क्यूरियसगोई - "संदर्भ" आम तौर पर माना जाता है कि उनके संख्यात्मक मूल्य के अंकगणितीय हेरफेर के उपयोग की अनुमति नहीं है, जिसे अक्सर "संकेत" के लिए अनुमति दी जाती है। पूर्व इसलिए बाद की तुलना में एक सुरक्षित निर्माण है; एक स्मृति प्रबंधन प्रणाली के साथ संयुक्त है जो किसी ऑब्जेक्ट के भंडारण को पुन: उपयोग करने की अनुमति नहीं देता है जबकि इसका एक वैध संदर्भ मौजूद है, संदर्भ स्मृति उपयोग त्रुटियों को रोकते हैं। उपयुक्त स्मृति प्रबंधन का उपयोग किए जाने पर भी पॉइंटर्स ऐसा नहीं कर सकते हैं।
जूल्स

@ जूल्स तब शब्दावली की बात है: आप एक बात को पॉइंटर या एक संदर्भ कह सकते हैं, और उन भाषाओं में "सुरक्षित" भाषाओं और "पॉइंटर" का उपयोग करने का निर्णय लेते हैं जो पॉइंटर अंकगणितीय और मैनुअल मेमोरी प्रबंधन के उपयोग की अनुमति देते हैं। (AFAIK "सूचक अंकगणित" केवल C / C ++ में किया जाता है।)
जिज्ञासु

2

आपको "अपरिभाषित व्यवहार" और इसके मूल को समझना होगा।

अपरिभाषित व्यवहार का अर्थ है ऐसा व्यवहार जो मानकों द्वारा परिभाषित नहीं है। C / C ++ में कई अलग-अलग संकलक कार्यान्वयन और अतिरिक्त विशेषताएं हैं। इन अतिरिक्त विशेषताओं ने कोड को कंपाइलर से जोड़ दिया। इसका कारण यह था कि कोई केंद्रीयकृत भाषा विकास नहीं था। इसलिए कुछ संकलकों में से कुछ उन्नत सुविधाएँ "अपरिभाषित व्यवहार" बन गईं।

जबकि जावा में लैंग्वेज स्पेसिफिकेशन सन-ओरेकल द्वारा नियंत्रित किया जाता है और स्पेसिफिकेशन्स बनाने की कोशिश करने वाला कोई और नहीं है और इस तरह कोई अपरिभाषित व्यवहार नहीं करता है।

प्रश्न का उत्तर विशेष रूप से संपादित करें

  1. जावा अपरिभाषित व्यवहार से मुक्त है क्योंकि कंपाइलर से पहले मानक बनाए गए थे
  2. आधुनिक सी / सी ++ संकलक ने कार्यान्वयन को अधिक / कम मानकीकृत किया है, लेकिन मानकीकरण से पहले लागू की गई विशेषताओं को अभी भी "अपरिभाषित व्यवहार" के रूप में टैग किया गया है क्योंकि आईएसओ ने इन पहलुओं पर ध्यान रखा।

2
आप सही हो सकते हैं कि जावा में कोई यूबी नहीं है, लेकिन यहां तक ​​कि जब एक इकाई सब कुछ नियंत्रित करती है, तो यूबी होने के कारण भी हो सकते हैं, इसलिए आपके द्वारा दिए गए कारण से निष्कर्ष नहीं निकलता है।
एपीग्रामग्राम

2
इसके अलावा, सी और सी ++ दोनों आईएसओ द्वारा मानकीकृत हैं। जबकि कई संकलक हो सकते हैं, एक समय में सिर्फ एक मानक होता है।
मसलक

1
@SarvexJatasra, मैं इस बात से सहमत नहीं हूं कि यह यूबी का एकमात्र स्रोत है। उदाहरण के लिए, एक UB डैन्फ्रेंसिंग डैंगलिंग पॉइंटर है और इसे किसी भी भाषा में UB छोड़ने के अच्छे कारण हैं, जो GC नहीं है, भले ही आप अपना कल्पना शुरू करें। और उन कारणों का मौजूदा अभ्यास या मौजूदा संकलक से कोई लेना-देना नहीं है।
एपीग्रामग्राम

2
@SarvexJatasra, हस्ताक्षरित अतिप्रवाह यूबी है क्योंकि मानक स्पष्ट रूप से कहता है (यह यूबी की परिभाषा के साथ दिया गया उदाहरण भी है)। अमान्य सूचक को Dereferencing भी उसी कारण से UB है, मानक ऐसा कहता है।
एपीग्रामग्राम

2
@ bames53: उद्धृत लाभों में से किसी को भी यूबी के साथ अक्षांश हाइपरमोडर्न कंपाइलरों के स्तर की आवश्यकता नहीं होगी। आउट-ऑफ-बाउंड मेमोरी एक्सेस और स्टैक ओवरफ्लो के अपवादों के साथ, जो "स्वाभाविक रूप से" यादृच्छिक कोड निष्पादन को प्रेरित कर सकते हैं, मैं किसी भी उपयोगी अनुकूलन के बारे में नहीं सोच सकता हूं, जो यह कहने की तुलना में व्यापक अक्षांश की आवश्यकता होगी कि अधिकांश यूबी-ईश ऑपरेशन अनिश्चित काल के लिए मूल्यों (जो "अतिरिक्त बिट्स" के रूप में व्यवहार कर सकते हैं) और केवल इसके परिणाम हो सकते हैं यदि किसी कार्यान्वयन के डॉक्स स्पष्ट रूप से ऐसे लगाने का अधिकार सुरक्षित रखते हैं; डॉक्स "
असंबद्ध

1

जावा अनिवार्य रूप से C / C ++ में पाए गए सभी अपरिभाषित व्यवहार को समाप्त कर देता है। (उदाहरण के लिए: हस्ताक्षर किए गए पूर्णांक अतिप्रवाह, शून्य से विभाजन, असमानकृत चर, अशक्त सूचक गति, बिट चौड़ाई से अधिक स्थानांतरण, डबल-मुक्त, यहां तक ​​कि "स्रोत कोड के अंत में कोई नई पंक्ति नहीं"।) लेकिन जावा में कुछ अस्पष्ट अपरिभाषित व्यवहार हैं। प्रोग्रामर द्वारा शायद ही कभी सामना किया जाता है।

  • जावा मूल इंटरफ़ेस (JNI), जावा के लिए C या C ++ कोड को कॉल करने का एक तरीका है। जेएनआई में पेंच कसने के कई तरीके हैं, जैसे फंक्शन सिग्नेचर को गलत करना, जेवीएम सेवाओं को अमान्य कॉल करना, मेमोरी को दूषित करना, सामान को गलत तरीके से आवंटित करना, और बहुत कुछ। मैंने पहले भी ये गलतियाँ की हैं, और आमतौर पर पूरा JVM तब क्रैश होता है जब JNI कोड को निष्पादित करने वाला कोई एक थ्रेड कोई त्रुटि करता है।

  • Thread.stop(), जो पदावनत है। उद्धरण:

    क्यों Thread.stopनिकाला जाता है?

    क्योंकि यह स्वाभाविक रूप से असुरक्षित है। एक धागे को रोकने से यह सभी मॉनिटरों को अनलॉक करने का कारण बनता है जो इसे बंद कर दिया है। (मॉनिटर को अनलॉक किया जाता है क्योंकि ThreadDeathअपवाद स्टैक को प्रचारित करता है।) यदि इन मॉनीटरों द्वारा पहले संरक्षित कोई भी वस्तु असंगत स्थिति में थी, तो अन्य थ्रेड्स अब इन ऑब्जेक्ट्स को असंगत स्थिति में देख सकते हैं। ऐसी वस्तुओं को नुकसान बताया जाता है। जब धागे क्षतिग्रस्त वस्तुओं पर काम करते हैं, तो मनमाना व्यवहार हो सकता है। यह व्यवहार सूक्ष्म और पता लगाने में मुश्किल हो सकता है, या इसका उच्चारण किया जा सकता है। अन्य अनियंत्रित अपवादों के विपरीत, ThreadDeathधागे को चुपचाप मारता है; इस प्रकार, उपयोगकर्ता को कोई चेतावनी नहीं है कि उसका कार्यक्रम दूषित हो सकता है। भविष्य में घंटों या दिनों तक वास्तविक क्षति होने के बाद भ्रष्टाचार किसी भी समय प्रकट हो सकता है।

    https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

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