जावा में अंतिम विधि को क्यों शामिल किया गया है?


44

इस पोस्ट के अनुसार , हमें कभी भी अंतिम पद्धति पर भरोसा नहीं करना चाहिए। तो जावा ने इसे प्रोग्रामिंग भाषा में आखिर क्यों शामिल किया?

यह किसी भी प्रोग्रामिंग भाषा को एक फ़ंक्शन में शामिल करने के लिए एक भयानक निर्णय की तरह लगता है जिसे कहा जा सकता है

जवाबों:


41

जोशुआ बलोच के प्रभावी जावा (द्वितीय संस्करण) के अनुसार, finalize()उपयोगी होने पर दो परिदृश्य हैं :

  1. यदि किसी वस्तु का मालिक अपनी स्पष्ट समाप्ति पद्धति को कॉल करना भूल जाता है तो "सुरक्षा जाल" के रूप में कार्य करना है। हालांकि इस बात की कोई गारंटी नहीं है कि फाइनल को तुरंत लागू किया जाएगा, संसाधन को देर से मुक्त करने के लिए बेहतर हो सकता है, उन (उम्मीद दुर्लभ) मामलों में जब क्लाइंट स्पष्ट समाप्ति पद्धति को कॉल करने में विफल रहता है। लेकिन अंतिम रूप से एक चेतावनी को लॉग करना चाहिए यदि यह पाता है कि संसाधन समाप्त नहीं हुआ है

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

आगे पढ़ने के लिए, आइटम 7, पृष्ठ 27 का संदर्भ लें।


4
मूल सहकर्मी की तरह # 2 ध्वनियों के साथ एक देशी संसाधन है जिसे सुरक्षा जाल की आवश्यकता होती है और इसमें समाप्ति की विधि होनी चाहिए, और इस तरह एक अलग बिंदु नहीं होना चाहिए।
मूइंग डक

2
@MooDDuck: # 2 एक अलग बिंदु है क्योंकि, यदि देशी पीयर महत्वपूर्ण संसाधन नहीं रखता है (जैसे कि यह विशुद्ध रूप से इन-मेमोरी ऑब्जेक्ट है), तो एक स्पष्ट समाप्ति विधि को उजागर करने की कोई आवश्यकता नहीं है। # 1 से सुरक्षा जाल स्पष्ट रूप से समाप्ति की विधि के बारे में है।
झोमिनल

55

मूल संसाधनों के प्रबंधन के लिए अंतिम रूप महत्वपूर्ण हैं। उदाहरण के लिए, आपकी ऑब्जेक्ट को गैर-जावा एपीआई का उपयोग करके ऑपरेटिंग सिस्टम से एक विजेटहैंडल आवंटित करने की आवश्यकता हो सकती है। यदि आप उस विजेट को रिलीज़ नहीं करते हैं, जब आपकी ऑब्जेक्ट GC'd है, तो आप WidgetHandles को लीक करने जा रहे हैं।

यह महत्वपूर्ण है कि "फ़ाइनलीज़र को कभी नहीं बुलाया जाता है" मामले केवल नीचे नहीं टूटते हैं:

  1. कार्यक्रम जल्दी से बन्द हो जाता है
  2. कार्यक्रम के जीवनकाल के दौरान ऑब्जेक्ट "हमेशा के लिए रहता है"
  3. कंप्यूटर बंद हो जाता है / आपकी प्रक्रिया ओएस / आदि द्वारा मार दी जाती है

इन तीनों मामलों में, आपके पास या तो देशी रिसाव नहीं है (इस तथ्य के आधार पर कि आपका कार्यक्रम अब नहीं चल रहा है), या आपके पास पहले से ही एक गैर-देशी रिसाव है (यदि आप प्रबंधित वस्तुओं को उनके बिना आवंटित करते रहते हैं GC'd)।

"चेतावनी कहे जाने वाले फाइनलर पर भरोसा न करें" वास्तव में प्रोग्राम लॉजिक के लिए फाइनलर्स का उपयोग नहीं करने के बारे में है। उदाहरण के लिए, आप अपने प्रोग्राम में सभी चीजों के कितने उदाहरण मौजूद हैं, इस पर नज़र नहीं रखना चाहते हैं कि निर्माण के दौरान किसी फ़ाइल में एक काउंटर बढ़ाकर और इसे एक अंतिम रूप में घटाकर - क्योंकि आपकी वस्तुओं की कोई गारंटी नहीं है। अंतिम रूप दिया जाए, यह फ़ाइल काउंटर शायद कभी भी वापस 0 पर नहीं जाएगा। यह वास्तव में अधिक सामान्य सिद्धांत का एक विशेष मामला है जिसे आपको सामान्य रूप से समाप्त होने वाले अपने कार्यक्रम पर निर्भर नहीं होना चाहिए (पावर विफलताएं, आदि)।

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


बहुत बढ़िया जवाब। मैं ऐसा था जैसे इसे बुलाया जा सकता है .. फिर भी इसे शामिल किया जाना चाहिए। मैं थोड़ी देर के लिए उलझन में था और StackOverflow पर लिंक किया गया।
सूचित किया गया

3
यह प्रश्न में नहीं था, लेकिन "अंतिम रूप दिए जाने पर अंतिम रूप देने वाले पर भरोसा न करें" के संदर्भ में चर्चा करने लायक है: अंतिम रूप से बुलाया जा सकता है, लेकिन केवल एक लंबे समय तक देरी के बाद वस्तु अनुपलब्ध हो जाती है। यह "मूल संसाधनों" के लिए मायने रखता है जो स्मृति की तुलना में बहुत अधिक दुर्लभ हैं (जो उनमें से अधिकांश हैं, यह पता चला है)।

26
"मूल संसाधनों के प्रबंधन के लिए अंतिम रूप महत्वपूर्ण हैं।" - nooooooooo, अहम क्षमा करें। देशी संसाधनों के प्रबंधन के लिए फाइनल का उपयोग करना एक भयानक विचार है (यही कारण है कि हमारे पास अब स्वायत्त और सह है)। जीसी केवल मेमोरी की परवाह करता है, किसी अन्य संसाधन की नहीं। इसका मतलब है कि आप मूल संसाधनों से बाहर भाग सकते हैं लेकिन फिर भी जीसी को ट्रिगर नहीं करने के लिए पर्याप्त मेमोरी है - हम वास्तव में ऐसा नहीं चाहते हैं। इसके अलावा अंतिम रूप से GC अधिक महंगे हैं जो कि एक अच्छा विचार नहीं है।
वू

12
मैं मानता हूँ आप अभी भी एक स्पष्ट देशी संसाधन प्रबंधन finalizers के अलावा अन्य रणनीति होनी चाहिए, लेकिन अपने वस्तु अगर करता है उन्हें आवंटित और finalizer में उन्हें मुक्त नहीं है, आप अपने आप को एक देशी रिसाव के मामले में खोल रहे हैं जहां किसी चीज़ है संसाधन के स्पष्ट मुक्त होने के बिना GC'd। दूसरे शब्दों में, फाइनल एक मूल संसाधन प्रबंधन रणनीति का एक महत्वपूर्ण हिस्सा है, सामान्य रूप से समस्या का समाधान नहीं है।
रयान कैवानुआग

1
@ यह कहना शायद अधिक सही है कि यदि वस्तु के अनुबंध का पालन नहीं किया close()जाता है, तो यह अंतिम रूप से कमबैक है (इसे अनुपलब्ध होने से पहले कभी नहीं बुलाया गया)
शाफ़्ट सनकी

5

इस विधि का उद्देश्य एपीआई प्रलेखन में बताया गया है:

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

finalize... का सामान्य उद्देश्य यह है कि ऑब्जेक्ट को गलत तरीके से त्यागने से पहले सफाई कार्रवाई करना । उदाहरण के लिए, एक इनपुट / आउटपुट कनेक्शन का प्रतिनिधित्व करने वाली किसी वस्तु के लिए अंतिम विधि स्पष्ट रूप से ऑब्जेक्ट को स्थायी रूप से छोड़ने से पहले कनेक्शन को तोड़ने के लिए स्पष्ट I / O लेनदेन कर सकती है ...


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

स्वचालित कचरा संग्रह ... प्रोग्रामिंग त्रुटियों के पूरे वर्गों को समाप्त करता है जो कि बेडवेइल सी और सी ++ प्रोग्रामर हैं। आप जावा कोड को इस विश्वास के साथ विकसित कर सकते हैं कि सिस्टम को कई त्रुटियां जल्दी मिलेंगी और जब तक आपका उत्पादन कोड समाप्त नहीं हो जाता है, तब तक बड़ी समस्याएं निष्क्रिय नहीं होंगी।

उपरोक्त उद्धरण, बदले में, जावा डिजाइन लक्ष्यों के बारे में आधिकारिक दस्तावेज से लिया गया था , यह है कि यह आधिकारिक संदर्भ समझा जा सकता है कि जावा भाषा डिजाइनरों ने इस तरह से क्यों फैसला किया।

इस वरीयता की अधिक विस्तृत और भाषा अज्ञेय चर्चा के लिए, OOSC खंड 9.6 स्वचालित स्मृति प्रबंधन का संदर्भ लें (वास्तव में, न केवल यह खंड बल्कि पूरे अध्याय 9 बहुत पढ़ने योग्य है यदि आप उस तरह के सामान में रुचि रखते हैं)। यह खंड असंदिग्ध कथन के साथ खुलता है:

एक अच्छा OO पर्यावरण को एक स्वचालित मेमोरी प्रबंधन तंत्र की पेशकश करनी चाहिए जो अप्राप्य वस्तुओं का पता लगाएगा और पुनः प्राप्त कर सकता है, जिससे एप्लिकेशन डेवलपर्स को अपनी नौकरी - एप्लिकेशन विकास पर ध्यान केंद्रित करने की अनुमति मिलेगी।

पूर्ववर्ती चर्चा यह दिखाने के लिए पर्याप्त होनी चाहिए कि इस तरह की सुविधा उपलब्ध होना कितना महत्वपूर्ण है। माइकल श्वित्जर और लैंबर्ट स्ट्रेथर के शब्दों में:

स्वचालित मेमोरी प्रबंधन के बिना एक वस्तु-उन्मुख कार्यक्रम लगभग एक सुरक्षा कुकर के बिना प्रेशर कुकर के समान है: जितनी जल्दी या बाद में बात उड़ा देना सुनिश्चित है!


4

अंतिम रूप से मौजूद हैं क्योंकि उन्हें यह सुनिश्चित करने का एक प्रभावी साधन होने की उम्मीद थी कि चीजें साफ हो जाएं (भले ही वे व्यवहार में न हों), और क्योंकि जब उनका आविष्कार किया गया था, तो सफाई सुनिश्चित करने के बेहतर साधन (जैसे कि प्रेत संदर्भ और कोशिश के साथ) -सूत्र) अभी तक मौजूद नहीं थे। यदि आपकी शुरुआत में "अंतिम रूप" की सुविधा को लागू करने के लिए खर्च किए गए थे, तो जावा बेहतर होगा, सफाई के अन्य साधनों पर खर्च किया गया था, लेकिन जावा शुरू में विकसित होने के समय शायद ही स्पष्ट था।


3

गुफा: मैं पुराना हो सकता हूं, लेकिन यह कुछ साल पहले की मेरी समझ है:

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

और कुछ GCs को स्पष्ट रूप से देरी या GC'ing ऑब्जेक्ट्स से बचने के लिए जाना जाता था जिनके पास अंतिम रूप था, इस उम्मीद में कि यह बेंचमार्क में बेहतर प्रदर्शन का उत्पादन करेगा।

इन व्यवहारों से दुर्भाग्य से मूल कारणों के साथ संघर्ष की सिफारिश की गई थी, और इसके बजाय स्पष्ट रूप से शटडाउन विधियों के उपयोग को प्रोत्साहित किया गया था।

यदि आपके पास एक ऐसी वस्तु है जिसे वास्तव में त्यागने से पहले साफ करना है, और यदि आप वास्तव में ऐसा करने के लिए उपयोगकर्ताओं पर भरोसा नहीं कर सकते हैं, तो एक अंतिम रूप अभी भी विचार करने योग्य हो सकता है। लेकिन सामान्य तौर पर, वहाँ अच्छे कारण हैं कि आप उन्हें अक्सर आधुनिक जावा कोड में नहीं देखते हैं जैसा कि आपने कुछ शुरुआती उदाहरणों में किया था।


1

गूगल जावा स्टाइल गाइड इस विषय पर कुछ ऋषि सलाह है:

यह है अत्यंत दुर्लभ ओवरराइड करने के लिए Object.finalize

युक्ति : यह मत करो। यदि आप पूरी तरह से, पहले प्रभावी जावा आइटम 7 को पढ़ें और समझें , "फाइनल से बचें," बहुत सावधानी से, और फिर ऐसा न करें।


5
मैं समस्या की देखरेख की प्रशंसा क्यों करता हूं, "यह मत करो" "यह मौजूद क्यों है" का जवाब नहीं है।
पियरे अरलाउंड

1
मुझे लगता है कि मैंने इसे अपने उत्तर में अच्छी तरह से वर्तनी नहीं दी थी, लेकिन (IMO) "इसका अस्तित्व क्यों है?" "यह नहीं होना चाहिए"। उन दुर्लभ मामलों के लिए जहां आपको अंतिम रूप से संचालन की आवश्यकता होती है, आप शायद इसके साथ PhantomReferenceऔर ReferenceQueueइसके बजाय खुद को बनाना चाहते हैं ।
डैनियल प्राइडेन

मेरा मतलब है जबकि * जाहिर है, हालांकि मैं तुम्हें निराश नहीं किया। सबसे अधिक उत्तोलित उत्तर हालांकि यह बताता है कि विधि कितनी उपयोगी है, आपकी बात को अमान्य करता है।
पियरे अरलाउद

1
यहां तक ​​कि मूल सहकर्मी मामले में, मुझे लगता PhantomReferenceहै कि एक बेहतर समाधान है। फाइनलर्स एक मस्सा है जिसे जावा के शुरुआती दिनों से छोड़ दिया जाता है, और जैसे Object.clone()और कच्चे प्रकार, सबसे अच्छी तरह से भूल गए भाषा का हिस्सा हैं।
डैनियल प्राइडेन

1
फाइनल के खतरों को C # में अधिक सुलभ (डेवलपर्स द्वारा समझने योग्य) तरीके से वर्णित किया गया है। , हालांकि, किसी को यह नहीं समझना चाहिए कि जावा और सी # पर अंतर्निहित तंत्र समान हैं; उनके विनिर्देशों में ऐसा कुछ भी नहीं है जो ऐसा कहते हैं।
रोंगोंग

1

जावा भाषा विशिष्टता (जावा SE 7) कहती है:

फाइनलर्स उन संसाधनों को मुक्त करने का मौका प्रदान करते हैं जिन्हें स्वचालित स्टोरेज मैनेजर द्वारा स्वचालित रूप से मुक्त नहीं किया जा सकता है। ऐसी स्थितियों में, बस किसी ऑब्जेक्ट द्वारा उपयोग की जाने वाली मेमोरी को पुनः प्राप्त करने की गारंटी नहीं होगी कि इसके द्वारा आयोजित संसाधनों को पुनः प्राप्त किया जाएगा।

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