2009-07-29 9 views
84

मैं एक कुछ सरल जावा कोड है कि इसकी संरचना में इस के समान दिखता है:जावा त्रुटि: अंतर्निहित सुपर निर्माता डिफ़ॉल्ट निर्माता के लिए अपरिभाषित है

abstract public class BaseClass { 
    String someString; 
    public BaseClass(String someString) { 
     this.someString = someString; 
    } 
    abstract public String getName(); 
} 

public class ACSubClass extends BaseClass { 
    public ASubClass(String someString) { 
     super(someString); 
    } 
    public String getName() { 
     return "name value for ASubClass"; 
    } 
} 

मैं BaseClass से काफी कुछ उपवर्गों होगा, प्रत्येक को लागू करने getName() विधि अपने तरीके से (template method pattern)।

यह अच्छी तरह से काम करता है, लेकिन मुझे उप-वर्गों में अनावश्यक कन्स्ट्रक्टर पसंद नहीं है। यह टाइप करने के लिए और अधिक है और इसे बनाए रखना मुश्किल है। अगर मैं BaseClass कन्स्ट्रक्टर के विधि हस्ताक्षर को बदलना चाहता था, तो मुझे सभी उप-वर्गों को बदलना होगा।

जब मैं उपवर्गों से निर्माता निकालने के लिए, मैं इस संकलन समय त्रुटि मिलती है:

Implicit super constructor BaseClass() is undefined for default constructor. Must define an explicit constructor

मैं क्या संभव करने के लिए कोशिश कर रहा हूँ है?

+1

कृपया, 'अनावश्यक' निर्माता छोड़ दें! यह आपके कोड की पठनीयता को बनाए रखता है और सभी आधुनिक आईडीई इसे स्वचालित रूप से बना सकते हैं, इसलिए आपको केवल एक शॉर्टकट कुंजी रखना होगा। –

+3

एक साल बाद अपना खुद का प्रश्न दोबारा पढ़ना और यह मेरे लिए होता है कि मैं कन्स्ट्रक्टर (बेस क्लास में शामिल) को हटा सकता था जैसे कि मैट बी सुझाव दिया गया था, और फिर उदाहरण बनाने के लिए एक स्थिर फैक्ट्री विधि का उपयोग करें। – Joel

उत्तर

138

आप क्योंकि एक वर्ग जो कोई निर्माता है एक डिफ़ॉल्ट निर्माता है, जो तर्क-कम है और निम्न कोड के बराबर है है इस त्रुटि मिलती है:

public ACSubClass() { 
    super(); 
} 
हालांकि अपने BaseClass के बाद से

एक निर्माता (वाणी और इसलिए डिफ़ॉल्ट, नो-एर्ग कन्स्ट्रक्टर नहीं है जो संकलक अन्यथा प्रदान करेगा) यह गैरकानूनी है - बेस क्लास को विस्तारित करने वाली कक्षा super(); पर कॉल नहीं कर सकती क्योंकि बेसक्लास में कोई तर्क-तर्ककर्ता नहीं है।

यह शायद थोड़ा सा काउंटर-अंतर्ज्ञानी है क्योंकि आपको लगता है कि एक उप-वर्ग में स्वचालित रूप से कोई भी रचनाकार है जो बेस क्लास है।

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

+16

"यह संभवतः थोड़ा सा अंतर्ज्ञानी है क्योंकि आप सोच सकते हैं कि एक उप-वर्ग में स्वचालित रूप से कोई भी रचनाकार होता है जो बेस क्लास है।" +1 –

+1

वंशावली के लिए, मैं भविष्य के पाठकों के लिए अपना समाधान सुझाऊंगा: 'बेस क्लास' में नो-एर्ग कन्स्ट्रक्टर बनाएं लेकिन इसे आसानी से 'असमर्थित ऑपरेशन अपवाद' या कुछ फेंक दें। यह सबसे अच्छा समाधान नहीं है (यह झूठा सुझाव देता है कि कक्षा नो-एर्ग कन्स्ट्रक्टर का समर्थन कर सकती है), लेकिन यह सबसे अच्छा है जिसे मैं सोच सकता हूं। – JMTyler

7

यह संभव है लेकिन आपके पास यह तरीका नहीं है।

आपको बेस क्लास में नो-एर्ग कन्स्ट्रक्टर जोड़ना होगा और यही वह है!

public abstract class A { 
    private String name; 
    public A(){ 
     this.name = getName(); 
    } 
    public abstract String getName(); 


    public String toString(){ 
     return "simple class name: " + this.getClass().getSimpleName() + " name:\"" + this.name + "\""; 
    } 
} 
class B extends A { 
    public String getName(){ 
     return "my name is B"; 
    } 
    public static void main(String [] args) { 
     System.out.println(new C()); 
    } 
} 
class C extends A { 
    public String getName() { 
     return "Zee"; 
    } 
} 

जब आप कक्षा में कोई कन्स्ट्रक्टर (कोई भी) नहीं जोड़ते हैं तो संकलक डिफ़ॉल्ट रूप से आपके लिए कोई तर्क नियंत्रक नहीं जोड़ता है।

जब कोई अपमान सुपर(); और चूंकि आपके पास सुपर क्लास में नहीं है, इसलिए आपको वह त्रुटि संदेश मिलता है।

यह सवाल स्वयं के बारे में है।

अब, इस सवाल का जवाब का विस्तार:

आप जानते हैं कि एक उपवर्ग (व्यवहार) बनाने अलग एक अलग मूल्य (डेटा) निर्दिष्ट करने के लिए कर रहे हैं कोई मतलब नहीं है ?? !!! मुझे उम्मीद है कि तुम करोगे।

यदि परिवर्तन की एकमात्र चीज "नाम" है तो एक वर्ग पैरामीट्रिज्ड पर्याप्त है!

तो आप इस की जरूरत नहीं है:

MyClass a = new A("A"); 
MyClass b = new B("B"); 
MyClass c = new C("C"); 
MyClass d = new D("D"); 

या

MyClass a = new A(); // internally setting "A" "B", "C" etc. 
MyClass b = new B(); 
MyClass c = new C(); 
MyClass d = new D(); 

आप इस बारे में हो सकते हैं:

MyClass a = new MyClass("A"); 
MyClass b = new MyClass("B"); 
MyClass c = new MyClass("C"); 
MyClass d = new MyClass("D"); 

If I were to change the method signature of the BaseClass constructor, I would have to change all the subclasses.

खैर इसलिए विरासत विरूपण साक्ष्य है जो उच्च युग्मन बनाता है, जो अंडे है ओओ सिस्टम में sirable। इसे टाला जाना चाहिए और शायद संरचना के साथ बदल दिया जाना चाहिए।

सोचें कि क्या आपको वास्तव में वास्तव में उन्हें उप-वर्ग के रूप में आवश्यकता है।

public interface NameAware { 
    public String getName(); 
} 



class A implements NameAware ... 
class B implements NameAware ... 
class C ... etc. 

यहाँ बी और सी एक जो उन के बीच में एक बहुत ही उच्च युग्मन बनाया होगा से विरासत में मिला हो सकता था, इंटरफेस युग्मन कम हो जाता है का उपयोग करके, अगर एक निर्णय लेता है यह होगा: देखें क्यों तुम बहुत बार insted इस्तेमाल किया इंटरफ़ेस है अब "नेमअवेयर" नहीं होगा अन्य वर्ग तोड़ नहीं जाएंगे।

बेशक, यदि आप व्यवहार का पुन: उपयोग करना चाहते हैं तो यह काम नहीं करेगा।

+2

हां, सिवाय इसके कि आप अब यह सुनिश्चित नहीं कर सकते कि आपके उदाहरण ठीक से शुरू हो गए हैं (उदाहरण के लिए इस विशेष मामले में नाम हैं) – ChssPly76

+0

@ ChssPly76: हां, लेकिन शायद ऐसा इसलिए है क्योंकि विरासत को खराब तरीके से उपयोग किया जा रहा है। मैंने इसे कवर करने के लिए अपना जवाब बढ़ाया। – OscarRyz

0

आपके बेस क्लास को कुछ स्ट्रिंग की आवश्यकता है इसलिए एक वितरित करें।
इस प्रयास करें:

abstract public class BaseClass { 
    String someString; 
    public BaseClass(String someString) { 
     this.someString = someString; 
    } 
    abstract public String getName(); 
} 

public class ACSubClass extends BaseClass { 
    public ASubClass() { 
     super("someString"); // or a meaningfull value, same as getName()? 
    } 
    public String getName() { 
     return "name value for ASubClass"; 
    } 
} 

या

abstract public class BaseClass { 
    String someString; 
    protected BaseClass() { // for subclasses 
     this.someString = null; // or a meaningfull value 
    } 
    public BaseClass(String someString) { 
     this.someString = someString; 
    } 
    abstract public String getName(); 
} 

public class ACSubClass extends BaseClass { 
    public String getName() { 
     return "name value for ASubClass"; 
    } 
} 
41

जो लोग इस त्रुटि के लिए और यहाँ आने गूगल के लिए: वहाँ इसे प्राप्त करने के लिए एक और कारण हो सकता है। ग्रहण इस त्रुटि को देता है जब आपके पास प्रोजेक्ट सेटअप होता है - सिस्टम कॉन्फ़िगरेशन मेल नहीं खाता है।

उदाहरण के लिए, यदि आप एक्लिप्स में जावा 1.7 प्रोजेक्ट आयात करते हैं और आपके पास 1.7 सही ढंग से सेट नहीं है तो आपको यह त्रुटि मिल जाएगी। फिर आप Project - Preference - Java - Compiler और switch to 1.6 or earlier पर जा सकते हैं; या Window - Preferences - Java - Installed JREs पर जाएं और अपनी जेआरई 1.7 स्थापना जोड़ें/ठीक करें।

+1

ग्रहण में किसी स्पष्ट कारण के लिए बस यह त्रुटि नहीं मिली। फिर मैंने वर्कस्पेस साफ़ किया (मेनू प्रोजेक्ट -> क्लीन ...) और यह चला गया। – erickrf

-1

आप बेस क्लास में एक तर्कहीन कन्स्ट्रक्टर जोड़कर इस त्रुटि को हल कर सकते हैं (जैसा कि नीचे दिखाया गया है)।

चीयर्स।

abstract public class BaseClass { 
     // ADD AN ARGUMENTLESS CONSTRUCTOR TO THE BASE CLASS 
     public BaseClass(){ 
     } 

     String someString; 
     public BaseClass(String someString) { 
      this.someString = someString; 
     } 
     abstract public String getName(); 
    } 

public class ACSubClass extends BaseClass { 
    public ASubClass(String someString) { 
     super(someString); 
    } 
    public String getName() { 
     return "name value for ASubClass"; 
    } 
} 
+0

इससे अमान्य ऑब्जेक्ट्स ('someString' के बिना) सेट करना आसान हो जाता है और इसलिए पूरी तरह से कन्स्ट्रक्टर के उद्देश्य को हरा देता है। – Robert

0

एक और तरीका है कॉल सुपर() व्युत्पन्न वर्ग निर्माता में एक पहला विवरण आवश्यक तर्क के साथ है।

public class Sup { 
    public Sup(String s) { ...} 
} 

public class Sub extends Sup { 
    public Sub() { super("hello"); .. } 
} 
0

ग्रहण करता है, तो आप उपवर्ग निर्माता में एक पहला विवरण सुपर वर्ग निर्माता करने के लिए कॉल की जरूरत नहीं है इस त्रुटि दे देंगे।

-1

मैं इस त्रुटि थी और एक आज़माएं/कैच ब्लॉक

उदाहरण के लिए करने के लिए विधि के बगल में से एक फेंक दिया अपवाद को निकाल कर उसे ठीक किया: से:

public static HashMap<String, String> getMap() throws SQLException 
{ 

} 

के लिए:

public static Hashmap<String,String> getMap() 
{ 
    try{ 

    }catch(SQLException) 
    { 
    } 
} 
+0

इस उत्तर में लापता कन्स्ट्रक्टर के लिए कंपाइलर त्रुटियों के साथ कुछ लेना देना नहीं है। – Robert

1

यह त्रुटि जेआरई के कारण नहीं आई थी इसलिए कृपया इन चरणों का पालन करें:


1. दाहिनी क्लिक के प्रोजेक्ट -> गुण -> जावा बिल्ड पथ -> लाइब्रेरी टैब पर क्लिक करें
2. लाइब्रेरी जोड़ें
3. जेआरई सिस्टम लाइब्रेरी का चयन करें -> अगला
पर क्लिक करें 4. वर्कस्पेस डिफ़ॉल्ट जेआर या वैकल्पिक स्थापित जेरे चुनें
5. समाप्त

+0

गोश, ओपी ने यह भी नहीं कहा कि कौन सी आईडीई (यदि कोई है) वह उपयोग कर रहा है ... – Robert

0

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

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