2013-12-09 7 views
42

से बचने के लिए मैं से 'जावा संगामिति अभ्यास में' निम्न को समझने में मदद की सराहना करेंगे:की अनुमति दे इस संदर्भ

एक ओवरराइड उदाहरण विधि (एक है कि है न निजी और न ही अंतिम) निर्माता से कर सकते हैं कॉलिंग से बचने के लिए इस संदर्भ को भी अनुमति दें।

  1. करता है 'भागने' यहाँ का मतलब यह है कि हम शायद एक उदाहरण विधि कॉल कर रहे हैं, इससे पहले कि उदाहरण के लिए पूरी तरह से निर्माण किया है?
    मुझे किसी अन्य तरीके से उदाहरण के दायरे से बचने वाला 'यह' नहीं दिख रहा है।
  2. 'अंतिम' इसे कैसे होने से रोकता है? उदाहरण के लिए 'अंतिम' का कुछ पहलू है जिसमें मुझे याद आ रही है?
+2

अच्छा और अच्छी तरह से पूछे जाने वाले प्रश्न। – Maroun

उत्तर

26
  1. यह कक्षा के बाहर कोड आह्वान करने और this गुजर मतलब है।
    वह कोड मान लेगा कि उदाहरण पूरी तरह से प्रारंभ किया गया है, और यदि यह नहीं है तो तोड़ सकता है।
    इसी तरह, आपकी कक्षा यह मान सकती है कि इंस्टेंस पूरी तरह से प्रारंभ होने के बाद कुछ विधियों को ही बुलाया जाएगा, लेकिन बाहरी कोड उन धारणाओं को तोड़ने की संभावना है।

  2. final विधियों को ओवरराइड नहीं किया जा सकता है, इसलिए आप उन्हें this पास करने के लिए भरोसा नहीं कर सकते हैं।
    यदि आप गैर-final कक्षा के लिए कन्स्ट्रक्टर में किसी भी गैर-final विधि को कॉल करते हैं, तो व्युत्पन्न क्लास उस विधि को ओवरराइड कर सकती है और कहीं भी this पास कर सकती है।
     
    यहां तक ​​कि जब आप final तरीकों कहते हैं, तुम अब भी लगता है कि वे सुरक्षित रूप से लिखे गए हैं – कि वे this कहीं भी उत्तीर्ण नहीं होते हैं, और खुद को किसी भी गैर final तरीकों कॉल नहीं करते कि बनाने की जरूरत है।

+0

कोड "मई" मान लेता है कि कक्षा पूरी तरह से प्रारंभ की गई है, लेकिन विधि का अनुबंध स्पष्ट रूप से इस तरह के अनुमान को रोक सकता है। कुछ मामलों में, बेस-क्लास कन्स्ट्रक्टर को व्युत्पन्न वर्ग के बारे में जानकारी की आवश्यकता हो सकती है, और उस जानकारी को प्राप्त करने के लिए सबसे व्यावहारिक तरीका उस वर्चुअल विधि को कॉल करने के लिए हो सकता है जिसका * दस्तावेज उद्देश्य * बेस- वर्ग निर्माण। ऐसे मामलों में, बेस-क्लास कन्स्ट्रक्टर के लिए किसी प्रकार की ऑब्जेक्ट को स्वीकार करने के लिए सहायक हो सकता है, और वर्चुअल विधि के माध्यम से इसे पास कर सकता है; इससे व्युत्पन्न-श्रेणी के निर्माता के लिए यह संभव हो जाएगा ... – supercat

+0

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

11

मेरा मानना ​​है कि उदाहरण की तरह

public class Foo { 
    public Foo() { 
     doSomething(); 
    } 

    public void doSomething() { 
     System.out.println("do something acceptable"); 
    } 
} 

public class Bar extends Foo { 
    public void doSomething() { 
     System.out.println("yolo"); 
     Zoom zoom = new Zoom(this); // at this point 'this' might not be fully initialized 
    } 
} 

कुछ क्योंकि सुपर निर्माता हमेशा पहले कहा जाता है (अनुमान से या स्पष्ट), doSomething हमेशा एक बच्चे वर्ग के लिए कहा जाता हो जाएगा है। चूंकि उपरोक्त विधि न तो final और न ही private है, तो आप इसे एक बच्चे वर्ग में ओवरराइड कर सकते हैं और जो कुछ भी आप चाहते हैं, जो Foo#doSomething() के साथ संघर्ष कर सकता था।

5
प्रति secure coding

उदाहरण

खराब कोड:

final class Publisher { 
    public static volatile Publisher published; 
    int num; 

    Publisher(int number) { 
    published = this; 
    // Initialization 
    this.num = number; 
    // ... 
    } 
} 

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

final class Publisher { 
    public static Publisher published; 
    int num; 

    Publisher(int number) { 
    // Initialization 
    this.num = number; 
    // ... 
    published = this; 
    } 
} 

क्योंकि क्षेत्र nonvolatile और nonfinal है, निर्माता के भीतर बयान इस तरह से कि इस संदर्भ प्रारंभ बयान निष्पादित से पहले प्रकाशित किया जाता है में संकलक द्वारा पुनर्क्रमित जा सकता है।

सही कोड:

final class Publisher { 
    static volatile Publisher published; 
    int num; 

    Publisher(int number) { 
    // Initialization 
    this.num = number; 
    // ... 
    published = this; 
    } 
} 

इस संदर्भ में जब यह अपने मौजूदा दायरे से बाहर उपलब्ध कराया गया है बच गए कहा जाता है। बाद आम तरीके से इस संदर्भ बच सकते हैं कर रहे हैं:

Returning this from a non-private, overridable method that is invoked from the constructor of a class whose object is being 

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

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

सामान्यतः, उन मामलों का पता लगाना महत्वपूर्ण है जिनमें यह संदर्भ वर्तमान संदर्भ के दायरे से बाहर निकल सकता है। विशेष रूप से, सार्वजनिक चर और विधियों को ध्यान से जांचना चाहिए।

+0

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

+0

@ जेफरी यह मेरी प्रकाशक कक्षा नहीं है, इसे सीधे सुरक्षित कोडिंग साइट से लिया गया था। – Woot4Moo

+0

यह उत्तर बहुत स्पष्ट है! उदाहरण के लिए – asgs

19

"एस्केप" का अर्थ है कि आंशिक रूप से निर्मित this ऑब्जेक्ट का संदर्भ सिस्टम में किसी अन्य ऑब्जेक्ट को पास किया जा सकता है।इस परिदृश्य पर विचार करें:

public Foo { 
    public Foo() { 
     setup(); 
    } 

    protected void setup() { 
     // do stuff 
    } 
} 

public Bar extends Foo implements SomeListener { 
    @Override protected void setup() { 
     otherObject.addListener(this); 
    } 
} 

समस्या यह है कि नई Bar वस्तु otherObject के साथ पंजीकृत किया जा रहा है इसके निर्माण पूर्ण होने से पहले है। अब otherObjectbarObject पर कॉलिंग विधियों को प्रारंभ करना शुरू कर देता है, फ़ील्ड प्रारंभ नहीं हो सकते हैं, या barObject अन्यथा एक असंगत स्थिति में हो सकता है। barObject (this खुद के लिए) का संदर्भ इसके तैयार होने से पहले शेष सिस्टम में "बच निकला" है।

इसके बजाय, यदि setup() विधि finalFoo पर है, Bar वर्ग नहीं कोड वहाँ में डाल सकते हैं कि वस्तु Foo निर्माता खत्म होने से पहले जाहिर कर देंगे।

+1

+1 धन्यवाद – IUnknown

संबंधित मुद्दे