जावा में एक विधि कॉल स्वीकार अभ्यास में 'यह' गुजर रहा है


93

क्या किसी विधि कॉल में करंट ऑब्जेक्ट को पास करना अच्छा / बुरा / स्वीकार्य अभ्यास है। जैसे की:

public class Bar{
    public Bar(){}

    public void foo(Baz baz){
        //  modify some values of baz
    }
}

public class Baz{
    //constructor omitted

    public void method(){
        Bar bar = new Bar();
        bar.foo(this);
    }
}

विशेष रूप से, क्या रेखा bar.foo(this)स्वीकार्य है?


60
यह स्वीकार्य क्यों नहीं होगा? यह आम है।
सेज्यूरेट जूल

3
तो ... यह 8 हाँ का :) (और हाँ, मैं इसे अद्यतन रख रहा हूँ।)
एलेक्स 18

2
गैर-स्थिर अनाम वर्ग स्वचालित रूप से सुपर क्लास के इस संदर्भ को पारित करता है, इसलिए यह स्वीकार्य होगा। परिपत्र संदर्भों के बारे में सावधानी बरतना एकमात्र सावधानी होगी।
मेहुल राठौड़

5
हालांकि एक चेतावनी है: आपको इसे कंस्ट्रक्टर में पास नहीं करना चाहिए क्योंकि यह आपकी वस्तु को असंगत स्थिति में उजागर करेगा। लोग आम तौर पर ऐसा करते हैं कि जब वे कॉलबैक बनाते हैं (उदाहरण के लिए ActionListener) अनाम आंतरिक वर्गों के रूप में और फिर किसी अन्य ऑब्जेक्ट को पास करते हैं।
तमसा रेव।

3
@ डायस्ट्रो हालांकि मैं मानता हूं कि यह स्वीकार्य है, इसका मतलब यह है कि यह स्वीकार्य है क्योंकि यह वास्तव में बुरा तर्क है। कुछ करना क्योंकि इसका आम आपको बहुत परेशानी में डाल सकता है
कैरी केंडल

जवाबों:


155

इसका उपयोग न करने का कोई कारण नहीं thisहै, वर्तमान उदाहरण है और यह उपयोग करने के लिए पूरी तरह से वैध है। वास्तव में वहाँ अक्सर कोई रास्ता नहीं है इसे छोड़ देना है।

इसलिए इसका उपयोग करें।

जैसा कि उदाहरण के बिना इसे स्वीकार करना कठिन है (इस तरह के सवाल का एक नकारात्मक उत्तर हमेशा तर्क करना आसान होता है), मैंने अभी सबसे आम java.langवर्गों में से Stringएक खोला है , और निश्चित रूप से मुझे इस उपयोग के उदाहरण मिले हैं, उदाहरण के लिए

1084        // Argument is a String
1085        if (cs.equals(this))
1086            return true;

के लिए देखो (thisबड़ी "स्वीकार किए जाते हैं" परियोजनाओं में, आप इसे खोजने के लिए असफल नहीं होंगे।


6
एकदम सही जवाब।
मैक्स 330 '313

15
-1 क्योंकि इस तथ्य का कोई उल्लेख नहीं है कि द्वि-दिशात्मक वर्ग के रिश्ते यूनी-दिशात्मक संबंधों की तुलना में अधिक जटिल हैं। यह सुनिश्चित करना महत्वपूर्ण है कि सॉफ्टवेयर संभव के रूप में स्पष्ट है। ऊपर के विशिष्ट उदाहरण में दो वर्गों के बीच द्वि-दिशात्मक संदर्भ होने और व्यवहार और डेटा को एक साथ लाने से बचने के लिए बाज़ क्लास में ले जाना विधि फू को अधिक समझदार होगा ।
जेडब्ल्यू।

35
-1 का जवाब क्योंकि आपने प्रश्न में एक अतिरिक्त मामूली विस्तार पाया है जिस पर आप टिप्पणी कर सकते हैं? वास्तव में ?
डेनसिटी सेगुरेट

13
@ डिस्ट्रॉय हां मैं आपके शुरुआती वाक्यांश से असहमत हूं: "इसका उपयोग नहीं करने का कोई कारण नहीं है"।
जेडब्ल्यू।

4
व्यवहार में, वास्तविक कोड में (ओपी के सरलीकृत उदाहरण के विपरीत), पास होने का thisमतलब यह नहीं है कि उदाहरण के लिए विरासत और इंटरफेस के कारण, आप एक अप्रत्यक्ष लिंक जोड़ सकते हैं।
डेनिस सेगुरेट

165

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

यहां इसी तरह की एक पोस्ट है: जावा ने इसे कंस्ट्रक्टर में लीक किया है जहां वे इस बात का स्पष्टीकरण देते हैं कि उत्तरार्द्ध एक बुरा अभ्यास क्यों है।


18
+1: निर्माणकर्ताओं में 'इस' के संदर्भ में खतरे को इंगित करने के लिए अच्छा है।
बाथशीबा

यह जरूरी नहीं कि एक बुरा अभ्यास हो। उदाहरण के लिए, एक Carकंस्ट्रक्टर Wheelउदाहरण बना सकता है , इसके Carबिना एक Wheelअपूर्ण रूप से आरंभिक होगा, जबकि एक के Wheelबिना Carभी अपूर्ण रूप से आरंभिक होगा। इस मामले में, यह कार के कंस्ट्रक्टर thisमें व्हील के कंस्ट्रक्टर के पास जाने के लिए स्वीकार्य हो सकता है । दूसरा विकल्प यह होगा कि कार और व्हील दोनों में निजी कंस्ट्रक्टर हों और कार, व्हील का निर्माण करने वाले फ़ैक्टरी फ़ंक्शन का उपयोग करें और कार पर व्हील इंस्टॉल करें; लेकिन यह कार पर स्थिर विधि या व्हील पर स्थिर विधि होना चाहिए?
रयान

जाहिर है, आपको एक CarFactoryWheelInstallerProxyऐसा निर्माण करना चाहिए जो आपके लिए पहियों को स्थापित करे।
केविन

6
@LieRyan Wheelपूरी तरह से अधीनस्थ है Car, और IMO को इसके बारे Carमें बिल्कुल भी नहीं जानना चाहिए ।
इजाकाता

3
thisएक कंस्ट्रक्टर के भीतर से उपयोग करने के बारे में केवल बुरी बात यह है कि अगर thisएक विधि या संदर्भ में पारित किया जाता है, जिसमें से अभी तक पूरी तरह से-दूषित वस्तु संदर्भ को अविश्वसनीय या अज्ञात ग्राहकों (या क्लाइंट कोड जो इसे मानता है, के लिए प्रकाशित नहीं है) पूरी तरह से निर्मित वस्तु)। पासिंग thisएक निर्माता से एक पैकेज-निजी विधि है कि प्रदर्शन एक आम आरंभीकरण मेरी राय में, है, न केवल स्वीकार्य लेकिन वांछनीय है।
स्कॉटलैंड

42

हां , लेकिन आपको दो चीजों के बारे में सावधान रहना चाहिए

  1. इसे पास करना जब वस्तु का निर्माण अभी तक नहीं किया गया है (अर्थात इसके निर्माता में)
  2. इसे एक लंबे समय तक जीवित वस्तु में पारित करना, जो संदर्भ को जीवित रखेगा और इस वस्तु को कचरा एकत्र होने से रोकेगा ।

1
ध्यान दें कि जावा में एक कंस्ट्रक्टर वास्तव में एक कंस्ट्रक्टर नहीं है, संभवतः जावा के कंस्ट्रक्टर को "इनिशलाइज़र" कहना अधिक उपयुक्त है। जावा कंस्ट्रक्टर के भीतर, ऑब्जेक्ट को वास्तव में मेमोरी आवंटित किया गया है, यह ऑब्जेक्ट वास्तव में पहले से ही मौजूद है / कंस्ट्रक्टर के भीतर निर्माण किया गया है।
रेयान

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

फिर भी, जब तक कि दूसरी वस्तु इस बात से अवगत है कि पारित वस्तु को आरंभीकृत नहीं किया जाता है, और इसे एक अपारदर्शी वस्तु के रूप में मानता है, या केवल कॉल विधियों को ऐसे राज्य में सुरक्षित घोषित किया गया है, तो इससे इसे पारित thisकरने में कोई समस्या नहीं होगी । ऐसा करना असंभव है यदि वस्तु आवंटित नहीं की गई है।
रेयान

13

यह पूरी तरह से सामान्य और पूरी तरह से स्वीकार्य है।


5

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


2
उदाहरण कोड में, Baz.method () एक आवृत्ति विधि है जो Baz के उदाहरण के साथ Bar.foo () को एक पैरामीटर के रूप में बुलाती है। इसलिए ओपी उसी कक्षा में एक विधि नहीं कह रहा है।
एक CVn

@ माइकलकॉग्लिंग मुझे लगता है कि जुनैद कह रहा है कि, बाज क्लास में फू () पद्धति को स्थानांतरित करके, thisदो वर्गों के बीच से गुजरने की कोई आवश्यकता नहीं होगी । तो, अतिरिक्त जटिलता को जोड़ने की कोई आवश्यकता नहीं है।
जेडब्ल्यू।

4

यदि एक ही व्यवहार को प्राप्त करने के लिए कम जटिल विकल्प हैं, तो एक मौजूदा कॉल में वर्तमान ऑब्जेक्ट को पास करना बुरा अभ्यास है।

परिभाषा के अनुसार, thisएक वस्तु से दूसरी वस्तु के पास जाते ही एक द्विदिश संघ बनता है ।

मार्टिन फॉवलर द्वारा रिफैक्टरिंग को उद्धृत करने के लिए:

द्विदिश एसोसिएशन को यूनिडायरेक्शनल (200) में बदलें

द्विदिश संघ उपयोगी होते हैं, लेकिन वे एक मूल्य रखते हैं। मूल्य दो-तरफ़ा लिंक को बनाए रखने और यह सुनिश्चित करने की अतिरिक्त जटिलता है कि ऑब्जेक्ट ठीक से बनाए और निकाले गए हैं। कई प्रोग्रामर के लिए द्विदिश संघ स्वाभाविक नहीं हैं, इसलिए वे अक्सर त्रुटियों का स्रोत होते हैं

...

जब आप की जरूरत नहीं है, लेकिन जब आप की जरूरत है, तो आप द्विदिश संघों का उपयोग करना चाहिए। जैसे ही आप देखते हैं कि एक द्विदिश एसोसिएशन अब अपना वजन नहीं बढ़ा रहा है, अनावश्यक अंत छोड़ दें।

इसलिए, सैद्धांतिक रूप से, हमें अलार्म घंटियाँ सुननी चाहिए जब हम पाते हैं कि हमें पास करने की ज़रूरत है thisऔर हाथ में समस्या को हल करने के अन्य तरीकों के बारे में सोचने के लिए वास्तव में कठिन प्रयास करना चाहिए । बेशक, ऐसे समय, जब अंतिम उपाय पर, यह करने के लिए समझ में आता है।

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

व्यवहार में मैंने पाया है कि प्लेग जैसे द्विदिश लिंक से बचकर मेरे कोड में व्यापक सुधार हुआ है ।


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

@dystroy टिप्पणी करने के लिए धन्यवाद कि आप यह क्यों समझाते हैं। यह हमेशा पता करने के लिए अच्छा है। मैं अपना उत्तर स्पष्ट करने के लिए संशोधित करूँगा कि, परिभाषा के अनुसार, एक अप्रत्यक्ष एसोसिएशन thisपास होते ही बन जाता है।
जेडब्ल्यू।

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

चलो असहमत होने के लिए सहमत हैं। मेरा जीवन बहुत आसान हो गया है क्योंकि मैंने thisअपने कोड में पास होने से बचा है , जहाँ संभव हो। मैं दूसरों को ऐसा करने की सलाह दूंगा।
जेडब्ल्यू।

2
@JW: इस उत्तर में दिया गया तर्क अप्रासंगिक है। यह हमेशा एक बुरा विचार है एक्स करने के लिए अगर कुछ और है जो सरल है, एक्स के किसी भी मूल्य के लिए।
रयान

4

हाँ। आप इसका उपयोग कर सकते हैं। बस पास करने के लिए प्रोग्रामिंग में आम है this। लेकिन इसके उपयोग के बारे में पेशेवरों और विपक्ष हैं। ऐसा करने के लिए यह खतरनाक नहीं है।


इसके बहुत सारे साइड इफेक्ट्स हैं। यह जटिलता जोड़ता है।
जेडब्ल्यू।

यदि वे कई साइड इफेक्ट्स हैं, तो हम अपने जावा सोर्स कोड में एक भी सबूत नहीं पा सकते हैं। स्रोत कोड से .destroys उदाहरण।
सुरेश अत्ता

2

बस एक और उदाहरण जोड़ने के लिए जहां पासिंग thisसही है और अच्छे डिजाइन का अनुसरण करता है: विज़िटर पैटर्न । विज़िटर डिज़ाइन पैटर्न में, विधि accept(Visitor v)को आमतौर पर इस तरह से लागू किया जाता है जैसे कि यह कॉल करता है v.visit(this)


1

स्वीकार्य

Oracle JAVA डॉक्स से स्निपेट:

एक आवृत्ति विधि या एक निर्माता के भीतर, यह वर्तमान वस्तु का संदर्भ है - वह वस्तु जिसका विधि या निर्माता कहा जा रहा है। आप वर्तमान वस्तु के किसी भी सदस्य को उदाहरण विधि या निर्माणकर्ता से इसका उपयोग करके संदर्भित कर सकते हैं।

एक फ़ील्ड के साथ इसका उपयोग करना

इस कीवर्ड का उपयोग करने का सबसे आम कारण है क्योंकि एक क्षेत्र एक विधि या कंस्ट्रक्टर पैरामीटर द्वारा छाया हुआ है।


2
"आप वर्तमान वस्तु के किसी भी सदस्य को संदर्भित कर सकते हैं " - जो प्रश्न का उत्तर नहीं देता है "क्या यह एक पैरामीटर के रूप में पारितthis करने के लिए स्वीकार्य है ? "।
एक CVn

2
यह कह रहा है कि आप this.some_variableस्थानीय चर के बजाय कक्षा चर को कैसे संदर्भित कर सकते हैं । यह thisएक पैरामीटर के रूप में पारित करने के साथ कुछ नहीं करना है ।
जोस साल्वेटिअरा जूल

0

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


9
यह विषय दिखता है।
सेज्यूरेट जूल

4
"जावा में सब कुछ मूल्य द्वारा पारित किया गया है।" - यह एक बहुत ही भ्रामक प्रारंभिक टिप्पणी है। वास्तव में सभी वस्तुओं को संदर्भ द्वारा पारित किया जाता है और सभी आदिम प्रकार मूल्य द्वारा पारित किए जाते हैं। आपके पास एक thisआदिम प्रकार का संदर्भ है, और इसलिए मुझे लगता है कि आपकी "अधिक जानकारी" भ्रम की स्थिति है।
स्टीवर्ट

1
@ स्टीवर्ट: वह तुरंत स्पष्ट कर देता है कि उसका मतलब यह नहीं है कि पूरी वस्तुओं की नकल की जाती है।
लार्स

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

2
@Stewart yoda.arachsys.com/csharp/parameters.html एक अच्छा लेख है जो C # के संदर्भ में मूल्य के संदर्भ में पासिंग और पासिंग रेफरेंस के बीच के अंतर को बताता है, जो दोनों का समर्थन करता है।
इयान रॉबर्ट्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.