क्या कंस्ट्रक्टर में सुपर () से पहले गणना करना संभव है?


81

यह देखते हुए कि मेरे पास एक क्लास बेस है जिसमें टेक्स्ट बॉक्स ऑब्जेक्ट के साथ एकल तर्क निर्माता है जैसा कि यह तर्क है। यदि मेरे पास निम्न फ़ॉर्म का एक वर्ग सरल है:

public class Simple extends Base {
  public Simple(){
    TextBox t = new TextBox();
    super(t);
    //wouldn't it be nice if I could do things with t down here?
  }
}

मुझे यह बताने में एक त्रुटि मिलेगी कि सुपर टू कॉल एक निर्माता में पहला कॉल होना चाहिए। हालांकि, अजीब तरह से पर्याप्त है, मैं यह कर सकता हूं।

public class Simple extends Base {
  public Simple(){
    super(new TextBox());
  }
}

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

क्या इस सीमा के आसपास आने का कोई रास्ता है? क्या उन चीज़ों के लिए चर रखने का एक अच्छा और सुरक्षित तरीका है जो आप सुपर कॉलिंग से पहले बना सकते हैं, लेकिन क्या आपने कंस्ट्रक्टर में प्रवेश किया है? या, अधिक उदारता से, सुपर से पहले गणना करने की अनुमति वास्तव में कहा जाता है, लेकिन निर्माणकर्ता के भीतर?

धन्यवाद।


3
किस कारण से इसे gwt के रूप में चिह्नित किया गया है? क्योंकि आप इसे gwt में आज़मा रहे थे ??

2
टेक्स्टबॉक्स एक GWT वर्ग था, लेकिन नहीं, यह प्रासंगिक नहीं है कि मुझे लगता है।
स्टीफन कैगल

जवाबों:


89

हां, आपके साधारण केस के लिए वर्कअराउंड है। आप एक निजी कंस्ट्रक्टर बना सकते हैं जो TextBoxएक तर्क के रूप में लेता है और आपके सार्वजनिक कंस्ट्रक्टर से कॉल करता है।

public class Simple extends Base {
    private Simple(TextBox t) {
        super(t);
        // continue doing stuff with t here
    }

    public Simple() {
        this(new TextBox());
    }
}

अधिक जटिल सामान के लिए, आपको एक कारखाने या एक स्थिर कारखाने विधि का उपयोग करने की आवश्यकता है।


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

3
यह एक बहुत ही आसान पैटर्न है, और बहुत कुछ आपको आवश्यकता को पूरी तरह से दरकिनार कर देता है जो कि super()कंस्ट्रक्टर में किसी अन्य चीज के बाद दिखाई नहीं देता है। चरम मामलों में आप कई निजी कंस्ट्रक्टरों को एक साथ चेन कर सकते हैं, हालांकि मैं किसी भी स्थिति के बारे में नहीं सोच सकता हूं जहां मुझे ऐसा करने की आवश्यकता है, और अगर मैंने किया तो मैं शायद यह सोचना शुरू कर दूंगा कि क्या मैं पूरा करने का एक बेहतर तरीका था। कर रहा था।
लॉरेंस गोन्साल्व्स

हाँ। अन्य लोगों ने पहले ही उत्तर दे दिया था कि यह जावा में इस तरह क्यों काम करता है, मैं सिर्फ एक विशेष समाधान को इंगित करना चाहता था। मुझे लगता है कि अधिकांश अन्य मान्य मामलों के लिए आप एक स्वीकार्य समाधान के साथ आ सकते हैं। अब, अपने आप को विरोधाभास करने के लिए, एक मामला है जहां यह मुझे थोड़ा सा है: मैं एक वर्ग का विस्तार कर रहा था, जिसके निर्माता के पास एक कक्षा पैरामीटर था। मैं कॉल करना चाहता था super(this.getClass()), लेकिन चूंकि आपको संदर्भ की अनुमति नहीं है this, इसलिए यह कोड अवैध था, भले ही यह पूरी तरह से उचित लगता है कि मुझे इस बिंदु पर वास्तविक वर्ग को जानने में सक्षम होना चाहिए।
मोम

@waxwing - यह "पूरी तरह से उचित" लग सकता है, लेकिन यह getClass()JLS में एक विशेष मामले के रूप में विधि का इलाज करेगा । <classname>.classइसके बजाय उपयोग करें ।
स्टीफन सी

<classname>.classइस मामले में उपयोग करना एक विकल्प नहीं था, क्योंकि मैं एक अमूर्त वर्ग लिख रहा था जिसे लोग विस्तारित कर सकते थे और मुझे उदाहरण की वास्तविक कक्षा की आवश्यकता थी।
मोम

33

मुझे सुपर कॉल से पहले गणना के साथ एक ही समस्या थी। कभी-कभी आप कॉल करने से पहले कुछ शर्तों की जांच करना चाहते हैं super()। उदाहरण के लिए, आपके पास एक ऐसा वर्ग है जो निर्मित होने पर बहुत सारे संसाधनों का उपयोग करता है। सुपर-कंस्ट्रक्टर को कॉल करने से पहले उप-वर्ग कुछ अतिरिक्त डेटा चाहता है और पहले उन्हें जांचना चाहता है। इस समस्या के आसपास एक सरल तरीका है। थोड़ा अजीब लग सकता है, लेकिन यह अच्छी तरह से काम करता है:

अपनी कक्षा के अंदर एक निजी स्थिर पद्धति का उपयोग करें जो सुपर-कंस्ट्रक्टर के तर्क को लौटाती है और आपके चेक को अंदर बनाती है:

public class Simple extends Base {
  public Simple(){
    super(createTextBox());
  }

  private static TextBox createTextBox() {
    TextBox t = new TextBox();
    t.doSomething();
    // ... or more
    return t;
  }
}

8

यह है के लिए आवश्यक क्रम में भाषा के आधार पर सुनिश्चित करना है कि सुपर क्लास मज़बूती से निर्माण किया है पहले । विशेष रूप से, "यदि कोई कंस्ट्रक्टर सुपरक्लास कंस्ट्रक्टर को स्पष्ट रूप से आमंत्रित नहीं करता है, तो जावा कंपाइलर सुपरक्लास के नो-लॉजिक कंस्ट्रक्टर को स्वचालित रूप से एक कॉल सम्मिलित करता है।"

आपके उदाहरण में, सुपरक्लास tनिर्माण के समय की स्थिति पर भरोसा कर सकता है । आप हमेशा बाद में कॉपी मांग सकते हैं।

यहाँ और यहाँ एक व्यापक चर्चा है


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

@ सुपरकैट: आपको इनहेरिटेंस के लिए डिज़ाइन करना होगा या इसे शामिल करना होगा [बलोच, इफेक्टिववा , ;17]; इस प्रश्नोत्तर को भी देखें ।
ट्रैशगॉड

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

मेरे पास सुपरक्लास को ठीक करने या रचना का उपयोग करने की लक्जरी है; यदि आप इसे एक प्रश्न के रूप में रखते हैं तो मुझे पिंग करें।
ट्रैशगॉड

1

आप एक स्थैतिक आपूर्तिकर्ता लैम्ब्डा को परिभाषित कर सकते हैं जिसमें अधिक जटिल तर्क हो सकते हैं।

public class MyClass {

    private static Supplier<MyType> myTypeSupplier = () -> {
        return new MyType();
    };

    public MyClass() {
        super(clientConfig, myTypeSupplier.get());
    }
}

0

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

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


0

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

आपके मामले में, अधिकांश समय एक गटर होता है जो आपको सुपर को दिए गए पैरामीटर को एक्सेस करने की अनुमति देता है ()। तो आप इसका उपयोग करेंगे:

सुपर (नया टेक्स्टबॉक्स ());
अंतिम टेक्स्टबॉक्स बॉक्स = getWidget ();
... अपना काम करो...

2
"सभी फ़ील्ड सही ढंग से आरंभिक हैं" वास्तव में जावा (विपरीत, IIUC, C ++) में गारंटी नहीं है क्योंकि एक सुपरक्लास कंस्ट्रक्टर एक गैर- finalउदाहरण विधि कह सकता है जो एक उपवर्ग ओवरराइड करता है। ओवरराइड तब उपवर्ग से आरंभिक फ़ील्ड नहीं देखेगा ( finalउदाहरण के लिए इनिशियलाइज़र वाले भी !)। कुछ स्थैतिक विश्लेषण उपकरण इस स्थिति के बारे में सही चेतावनी देंगे।
जेसी ग्लिक

0

यह मेरा समाधान है जो अतिरिक्त ऑब्जेक्ट बनाने की अनुमति देता है, अतिरिक्त कक्षाओं, फ़ील्ड, विधियों आदि को बनाए बिना इसे संशोधित करता है।

class TextBox {
    
}

class Base {

    public Base(TextBox textBox) {
        
    }
}

public class Simple extends Base {

    public Simple() {
        super(((Supplier<TextBox>) () -> {
            var textBox = new TextBox();
            //some logic with text box
            return textBox;        
        }).get());
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.