29

जावा में, क्या सुपर कन्स्ट्रक्टर चलाने से पहले एक फ़ील्ड शुरू करने का कोई तरीका है?सुपर कन्स्ट्रक्टर रन से पहले क्षेत्र शुरू करें?

भी ugliest हैक्स के साथ मैं संकलक द्वारा अस्वीकार कर दिया जाता है ऊपर आ सकते हैं:

class Base 
{ 
    Base(String someParameter) 
    { 
     System.out.println(this); 
    } 
} 

class Derived extends Base 
{ 
    private final int a; 

    Derived(String someParameter) 
    { 
     super(hack(someParameter, a = getValueFromDataBase())); 
    } 

    private static String hack(String returnValue, int ignored) 
    { 
     return returnValue; 
    } 

    public String toString() 
    { 
     return "a has value " + a; 
    } 
} 

नोट: इस मुद्दे को गायब हो गया जब मैं प्रतिनिधिमंडल को विरासत से प्रयोग किया, लेकिन मैं अभी भी जानना चाहते हैं।

+1

क्या आप फ़ील्ड 'ए' को पूर्व-प्रारंभ करने की कोशिश कर रहे हैं? – Woot4Moo

+1

मुझे नहीं लगता कि आप यह कर सकते हैं। किसी भी कक्षा में जो भी प्रारंभिक होता है (भले ही यह कन्स्ट्रक्टर के बाहर है) 'सुपर' कॉल के बाद हर कन्स्ट्रक्टर में ले जाया जाता है। इसलिए, सुपर कन्स्ट्रक्टर हमेशा फील्ड प्रारंभ करने से पहले चलाया जाता है। –

+5

@FredOverflow 'ए' के बाद से' व्युत्पन्न 'में केवल पहुंच योग्य है, यह क्यों मायने रखता है कि इसे * सुपर()' कहा जाता है * से पहले शुरू किया जाता है? इसके बाद इसे शुरू करने के उदाहरण में आपके द्वारा प्रदान किए जाने वाले उदाहरण में कोई फर्क नहीं पड़ता है (जब तक कि आप बेस कन्स्ट्रक्टर से ओवरडिन विधि को कॉल न करें, जो काफी फिश गंध शुरू होता है)। – assylias

उत्तर

20

नहीं, ऐसा करने का कोई तरीका नहीं है।

language specs के अनुसार, super() कॉल किए जाने तक इंस्टेंस चर प्रारंभ नहीं किए जाते हैं।

ये वर्ग उदाहरण सृष्टि के निर्माता कदम है, लिंक से लिया के दौरान प्रदर्शन कदम हैं:

  1. इस निर्माता मंगलाचरण के लिए नव निर्मित पैरामीटर चर के निर्माता के लिए बहस असाइन करें।
  2. इस निर्माता एक स्पष्ट निर्माता मंगलाचरण (§8.8.7.1) एक ही कक्षा (इस का उपयोग) में एक और निर्माता की, तो तर्कों और प्रक्रिया है कि निर्माता मंगलाचरण रिकर्सिवली ये वही पांच चरणों का उपयोग कर मूल्यांकन से शुरू होता है। यदि वह कन्स्ट्रक्टर आमंत्रण अचानक समाप्त हो जाता है, तो यह प्रक्रिया को उसी कारण से पूरी तरह से पूरा करती है; अन्यथा, चरण 5 के साथ जारी रखें।
  3. यह कन्स्ट्रक्टर एक ही रचनात्मक कन्स्ट्रक्टर उसी वर्ग में किसी अन्य कन्स्ट्रक्टर के आमंत्रण (इस का उपयोग करके) के साथ शुरू नहीं होता है। यदि यह कन्स्ट्रक्टर ऑब्जेक्ट के अलावा किसी अन्य वर्ग के लिए है, तो यह कन्स्ट्रक्टर सुपरक्लास कन्स्ट्रक्टर (सुपर का उपयोग करके) के स्पष्ट या निहित आमंत्रण के साथ शुरू होगा। तर्कों का मूल्यांकन करें और प्रक्रिया जो सुपरक्लास कन्स्ट्रक्टर इनवोकेशन को का उपयोग करके इन पांच चरणों का पुन: उपयोग करते हैं। यदि वह कन्स्ट्रक्टर आमंत्रण अचानक पूर्ण करता है, तो यह प्रक्रिया कारण के लिए अचानक समाप्त हो जाती है। अन्यथा, कदम 4.
  4. साथ जारी रखने के इस वर्ग के लिए निष्पादित उदाहरण initializers और उदाहरण चर initializers , इसी उदाहरण चर के उदाहरण के मूल्यों चर initializers बताए, में बाएँ से सही जिस क्रम में वे दिखाई देते हैं वर्ग के लिए स्रोत कोड में पाठ। यदि इनमें से किसी भी प्रारंभिक के निष्पादन में अपवाद होता है, तो कोई और प्रारंभकर्ता संसाधित नहीं होता है और यह प्रक्रिया अचानक उसी अपवाद के साथ पूर्ण हो जाती है। अन्यथा, चरण 5 के साथ जारी रखें।
  5. इस कन्स्ट्रक्टर के बाकी हिस्सों का निष्पादन करें। यदि वह निष्पादन अचानक समाप्त हो जाता है, तो यह प्रक्रिया इसी कारण से अचानक समाप्त होती है। अन्यथा, यह प्रक्रिया सामान्य रूप से पूर्ण होती है।
+0

में समाधान का उपयोग कर सकते हैं क्या आप इस पर निश्चित हैं? मैं इस पर आया: _...यह मामला हो सकता है कि बी इन घटनाओं को निम्नलिखित क्रम में देखता है (और संकलक इस तरह के निर्देशों को पुन: व्यवस्थित करने के लिए भी स्वतंत्र है): स्मृति आवंटित करें, संसाधन को संदर्भित करें, कॉल कन्स्ट्रक्टर। मान लीजिए कि स्मृति बी आवंटित होने के बाद थ्रेड बी आता है और संसाधन क्षेत्र सेट किया गया है, लेकिन डीसीएल लेख पर @BrianGoetz से कन्स्ट्रक्टर कहलाता है .. इसलिए संकलक स्पष्ट रूप से कुछ अनुकूलन कर सकता है जिसमें संदर्भ और कॉल असाइन करना भी शामिल है उसके बाद निर्माता! – mkilic

1

यह Java language specification (section 8.8.7) द्वारा प्रतिबंधित है:

एक निर्माता शरीर के पहले बयान एक ही कक्षा की या सीधे सुपर क्लास की एक और निर्माता की एक स्पष्ट मंगलाचरण हो सकता है।

निर्माता शरीर इस तरह दिखना चाहिए:

ConstructorBody:

{ ExplicitConstructorInvocationopt BlockStatementsopt } 
4

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

लेकिन कामकाज हैं। एक कारखाना वर्ग बनाना है जो मूल्य प्राप्त करता है और इसे व्युत्पन्न वर्ग के निर्माता को पास करता है।

class DerivedFactory { 
    Derived makeDerived(String someParameter) { 
     int a = getValueFromDataBase(); 
     return new Derived(someParameter, a); 
    } 
} 


class Derived extends Base 
{ 
    private final int a; 

    Derived(String someParameter, int a0) { 
     super(hack(someParameter, a0)); 
     a = a0; 
    } 
    ... 
} 
10

सुपर निर्माता किसी भी मामले में चलाया जाएगा, लेकिन क्योंकि हम "ugliest हैक्स" के बारे में बात कर रहे हैं, हम इस

public class Base { 
    public Base() { 
     init(); 
    } 

    public Base(String s) { 
    } 

    public void init() { 
    //this is the ugly part that will be overriden 
    } 
} 

class Derived extends Base{ 

    @Override 
    public void init(){ 
     a = getValueFromDataBase(); 
    } 
} 

का लाभ लेने मैं हैक्स इस तरह उपयोग करने का सुझाव कभी नहीं कर सकते हैं।

+0

मुझे नहीं लगता कि जावा में काम करता है, और अच्छे कारण के लिए। संदर्भ के लिए खोज रहे हैं ... –

+0

यह काम करता है, परीक्षण ... –

+1

+1 - आप सही हैं। Ick। मैं सी ++ के बारे में सोच रहा था। फिर भी - मुझे नहीं लगता कि हैक आवश्यक है - मेरा जवाब देखें। –

4

मुझे ऐसा करने का कोई तरीका मिला।

class Derived extends Base 
{ 
    private final int a; 

    // make this method private 
    private Derived(String someParameter, 
        int tmpVar /*add an addtional parameter*/) { 
     // use it as a temprorary variable 
     super(hack(someParameter, tmpVar = getValueFromDataBase())); 
     // assign it to field a 
     a = tmpVar; 
    } 

    // show user a clean constructor 
    Derived(String someParameter) 
    { 
     this(someParameter, 0) 
    } 

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