जावा में कोई एकाधिक वंशानुक्रम क्यों नहीं है, लेकिन कई इंटरफेस को लागू करने की अनुमति है?


153

जावा कई उत्तराधिकार की अनुमति नहीं देता है, लेकिन यह कई इंटरफेस को लागू करने की अनुमति देता है। क्यों?


1
मैंने इसे अधिक वर्णनात्मक बनाने के लिए प्रश्न शीर्षक संपादित किया।
बूझो

4
दिलचस्प है, जेडीके 8 में, विस्तार विधियां होंगी जो इंटरफ़ेस विधियों के कार्यान्वयन की परिभाषा की अनुमति देगा। नियमों को व्यवहार के कई उत्तराधिकार को परिभाषित करने के लिए परिभाषित किया गया है, लेकिन राज्य के बारे में नहीं (जो मुझे लगता है कि अधिक समस्याग्रस्त है
एडविन डेलोरजो

1
इससे पहले कि आप लोग उन उत्तरों पर समय व्यर्थ करें जो आपको केवल यह बताते हैं कि "कैसे जावा कई विरासतों को स्वीकार करता है" ... मैं आपको सुझाव देता हूं कि आप @Prbal श्रीवास्तव के जवाब पर जाएं जो तार्किक रूप से आपको आंतरिक रूप से हो रहा होना चाहिए, ताकि वर्गों को यह अधिकार न मिल सके। । और केवल कई वंशानुक्रम की अनुमति देने के लिए इंटरफेस को अनुमति देता है।
यो एप्स

जवाबों:


228

क्योंकि इंटरफेस केवल यह बताता है कि वर्ग क्या कर रहा है, न कि यह कैसे कर रहा है।

मल्टीपल इनहेरिटेंस के साथ समस्या यह है कि दो वर्ग एक ही काम करने के विभिन्न तरीकों को परिभाषित कर सकते हैं , और उपवर्ग यह नहीं चुन सकता है कि किसको चुनना है।


8
मैं सी ++ करता था और काफी बार उसी सटीक मुद्दे में भाग जाता था। मैंने हाल ही में स्काला के "लक्षण" के बारे में पढ़ा, जो मुझे "सी ++" तरीके और "जावा" चीजों को करने के तरीके के बीच में कुछ प्रतीत होता है।
नील्स बस्जेस

2
इस तरह, आप "हीरे की समस्या" से बच रहे हैं: en.wikipedia.org/wiki/Diamond_problem#The_diamond_problem
Nick L.

6
जावा 8 के बाद से आप दो समान डिफ़ॉल्ट तरीकों को परिभाषित कर सकते हैं, प्रत्येक इंटरफ़ेस में एक। यदि आप अपनी कक्षा में दोनों इंटरफेस लागू करेंगे, तो आपको कक्षा में ही इस विधि को ओवरराइड करना होगा, देखें: docs.oracle.com/javase/tutorial/java/IandI/…
bobbel

6
यह उत्तर सटीक नहीं है। समस्या यह नहीं बता रही है कि कैसे और जावा 8 साबित करने के लिए है। जावा 8 में, दो सुपर इंटरफेस अलग-अलग कार्यान्वयनों के साथ एक ही विधि की घोषणा कर सकते हैं, लेकिन यह एक समस्या नहीं है क्योंकि इंटरफ़ेस विधियाँ आभासी हैं , इसलिए आप बस उन्हें अधिलेखित कर सकते हैं और समस्या हल हो गई है। वास्तविक समस्या विशेषताओं में अस्पष्टता के बारे में है , क्योंकि आप इस अस्पष्टता को विशेषता को अधिलेखित नहीं कर सकते हैं (विशेषताएँ आभासी नहीं हैं)।
एलेक्स ओलिवेरा

1
"गुण" से आपका क्या तात्पर्य है?
बूझो

96

मेरे कॉलेज के प्रशिक्षकों में से एक ने मुझे इस तरह समझाया:

मान लीजिए कि मेरे पास एक वर्ग है, जो एक टोस्टर है, और दूसरा वर्ग है, जो न्यूक्लियरबॉम्ब है। वे दोनों एक "अंधेरा" सेटिंग हो सकती है। वे दोनों एक () विधि है। (एक बंद है (), दूसरा नहीं।) अगर मैं एक वर्ग बनाना चाहता हूं जो इन दोनों का उपवर्ग हो ... जैसा कि आप देख सकते हैं, यह एक समस्या है जो वास्तव में मेरे चेहरे पर उड़ सकती है। ।

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

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


5
धन्यवाद, NomeN। उद्धरण का स्रोत ब्रेंडन बर्न्स नामक एक पीएचडी छात्र था, जो उस समय भी ओपन-सोर्स क्वेक 2 स्रोत भंडार का अनुचर था। जाओ पता लगाओ।
सिंथेटिक

4
इस सादृश्य के साथ समस्या यह है कि यदि आप एक परमाणु बम और टोस्टर का उपवर्ग बना रहे हैं, तो "परमाणु टोस्टर" का उपयोग किए जाने पर यथोचित रूप से उड़ा दिया जाएगा।
101100

20
अगर कोई परमाणु बम और टोस्टर को मिलाने का फैसला करता है, तो वह योग्य है कि बम उसके चेहरे पर उड़ गया। उद्धरण है मिथ्या तर्क
मसूद

1
एक ही प्रोग्रामिंग भाषा एकाधिक "इंटरफ़ेस" वंशानुक्रम की अनुमति देती है, इसलिए यह "औचित्य" लागू नहीं होता है।
जिज्ञासु

24

क्योंकि वंशानुक्रम का उपयोग तब भी किया जाता है जब आप यह नहीं कह सकते कि "अरे, यह तरीका उपयोगी लगता है, मैं उस वर्ग को भी बढ़ा दूंगा"।

public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter, 
             AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...

क्या आप बता सकते हैं कि आप यह क्यों कहते हैं कि विरासत का दुरुपयोग हुआ है? एक देव वर्ग बनाना बिल्कुल वही है जो मैं करना चाहता हूँ! मुझे ऐसे बहुत से लोग मिलते हैं जो "टूल" क्लास बनाकर सिंगल इनहेरिटेंस के आसपास काम करते हैं जिनमें स्टैटिक मेथड होते हैं।
डंकन कलवर्ट

9
@ डंकन कैवर्ट: नहीं, आप ऐसा नहीं करना चाहते हैं, न कि यदि उस कोड को कभी रखरखाव की आवश्यकता होगी। स्थैतिक तरीकों के बहुत से OO की बात याद आती है, लेकिन अत्यधिक एकाधिक वंशानुक्रम बहुत खराब होता है क्योंकि आप पूरी तरह से ट्रैक खो देते हैं कि किस कोड का उपयोग कहां किया जाता है, साथ ही साथ एक वर्ग क्या है। दोनों इस समस्या को हल करने की कोशिश कर रहे हैं "मैं इस कोड का उपयोग कैसे कर सकता हूं जहां मुझे इसकी आवश्यकता है", लेकिन यह एक सरल अल्पकालिक समस्या है। उचित OO डिज़ाइन द्वारा हल की जाने वाली बहुत कठिन दीर्घकालिक समस्या है "मैं इस कोड को 20 अलग-अलग जगहों पर अप्रत्याशित तरीके से तोड़ने के बिना इस कोड को कैसे बदल सकता हूं?
माइकल बोर्गवर्ड

2
@ डंकनकैलवर्ट: और आप इसे हल करते हैं कि उच्च सामंजस्य और कम युग्मन के साथ कक्षाएं होने का मतलब है कि उनके पास डेटा और कोड के टुकड़े होते हैं जो एक दूसरे के साथ गहनता से बातचीत करते हैं, लेकिन केवल एक छोटे से सरल प्रोग्राम एपीआई के माध्यम से बाकी कार्यक्रम के साथ बातचीत करते हैं। फिर आप आंतरिक विवरण के बजाय उस एपीआई के संदर्भ में उनके बारे में सोच सकते हैं, जो महत्वपूर्ण है क्योंकि लोग केवल एक ही समय में सीमित विवरणों को ध्यान में रख सकते हैं।
माइकल बोर्गवर्ड

18

इस प्रश्न का उत्तर जावा कंपाइलर (कंस्ट्रक्टर चेनिंग) के आंतरिक कामकाज में निहित है। यदि हम जावा कंपाइलर के आंतरिक कार्य को देखते हैं:

public class Bank {
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank{
 public void printBankBalance(){
    System.out.println("20k");
  }
}

इस रूप को संकलित करने के बाद:

public class Bank {
  public Bank(){
   super();
  }
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank {
 SBI(){
   super();
 }
 public void printBankBalance(){
    System.out.println("20k");
  }
}

जब हम कक्षा का विस्तार करते हैं और इसकी एक वस्तु बनाते हैं, तो एक निर्माण श्रृंखला Objectकक्षा तक चलेगी ।

ऊपर कोड ठीक चलेगा। लेकिन अगर हमारे पास एक और वर्ग है Carजो विस्तारित होता है Bankऔर एक हाइब्रिड (एकाधिक विरासत) वर्ग कहा जाता है SBICar:

class Car extends Bank {
  Car() {
    super();
  }
  public void run(){
    System.out.println("99Km/h");
  }
}
class SBICar extends Bank, Car {
  SBICar() {
    super(); //NOTE: compile time ambiguity.
  }
  public void run() {
    System.out.println("99Km/h");
  }
  public void printBankBalance(){
    System.out.println("20k");
  }
}

इस मामले में (SBICAR) कंस्ट्रक्टर चेन ( संकलन समय अस्पष्टता ) बनाने में विफल रहेगा ।

इंटरफेस के लिए इसे अनुमति दी जाती है क्योंकि हम इसका एक ऑब्जेक्ट नहीं बना सकते हैं।

नई अवधारणा defaultऔर staticविधि के लिए कृपया इंटरफ़ेस में डिफ़ॉल्ट देखें ।

आशा है कि यह आपकी क्वेरी को हल करेगा। धन्यवाद।


7

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


"मौत के हीरे" के साथ क्या समस्या है?
जिज्ञासु २०'१३

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

@ कुरसी: यदि कोई ढाँचा प्रदान करता है कि आधार-प्रकार के संदर्भ के लिए वस्तु संदर्भ की पहचान करना पहचान संरक्षण होगा, तो प्रत्येक वस्तु उदाहरण में किसी भी आधार-वर्ग विधि का ठीक एक कार्यान्वयन होना चाहिए। यदि ToyotaCarऔर HybridCarदोनों Carओवररोड से प्राप्त हुए हैं Car.Drive, और यदि PriusCarदोनों को विरासत में मिला है , लेकिन ओवरराइड नहीं किया हैDrive , तो सिस्टम को यह पहचानने का कोई तरीका नहीं होगा कि आभासी Car.Driveक्या करेंगे। उपरोक्त italicized स्थिति से बचने के लिए इंटरफेस इस समस्या से बचते हैं।
सुपरकैट

1
@supercat "सिस्टम के पास यह पहचानने का कोई तरीका नहीं होगा कि वर्चुअल Car.Drive को क्या करना चाहिए।" <- या यह केवल एक संकलित त्रुटि दे सकता है और आपको एक स्पष्ट रूप से चुन सकता है, जैसे कि सी ++ करता है।
क्रिस मिडलटन

1
@ क्रिसमिडलटन: एक विधि void UseCar(Car &foo); बहुविकल्पी के बीच शामिल करने के लिए की उम्मीद नहीं की जा सकती है ToyotaCar::Driveऔर HybridCar::Drive(है कि उन अन्य प्रकार के भी, क्योंकि यह अक्सर न पता होना चाहिए और न ही देखभाल मौजूद )। C ++ करता है, एक भाषा को उस कोड की आवश्यकता होती है, जिसे ToyotaCar &myCarपास करने की इच्छा के साथ उस कोड UseCarको पहले HybridCarया तो डाली जानी चाहिए ToyotaCar, लेकिन ((कार) (HybridCar) myCar) .Drive` और ((Car)(ToyotaCar)myCar).Drive अलग-अलग चीजें करेगा, जो कि अपस्टेक होगा। पहचान-संरक्षण नहीं थे।
सुपरकैट

6

आप एकाधिक विरासत के बारे में oracle प्रलेखन पृष्ठ में इस क्वेरी के लिए सटीक उत्तर पा सकते हैं

  1. राज्य की कई विरासत: कई वर्गों से खेतों को प्राप्त करने की क्षमता

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

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

    1. क्या होगा अगर विभिन्न सुपर क्लास के तरीके या कंस्ट्रक्टर एक ही क्षेत्र को तुरंत प्रभावित करते हैं?
    2. कौन सी विधि या निर्माणकर्ता पूर्वता लेगा?
  2. कार्यान्वयन का एकाधिक वंशानुक्रम: कई वर्गों से विधि परिभाषाएँ प्राप्त करने की क्षमता

    इस दृष्टिकोण के साथ समस्याएं: नाम ts और अस्पष्टता । यदि एक उपवर्ग और सुपरक्लास में समान विधि नाम (और हस्ताक्षर) होते हैं, तो संकलक यह निर्धारित नहीं कर सकता कि किस संस्करण को लागू करना है।

    लेकिन जावा डिफ़ॉल्ट तरीकों के साथ कई प्रकार की विरासत का समर्थन करता है , जिसे जावा 8 रिलीज के बाद से पेश किया गया है। जावा कंपाइलर यह निर्धारित करने के लिए कुछ नियम प्रदान करता है कि कोई विशेष वर्ग किस डिफ़ॉल्ट विधि का उपयोग करता है।

    हीरे की समस्या को हल करने के बारे में अधिक जानकारी के लिए एसई पोस्ट के नीचे देखें:

    जावा 8 में अमूर्त वर्गों और इंटरफेस के बीच अंतर क्या हैं?

  3. एक से अधिक वंशानुक्रम: एक से अधिक इंटरफ़ेस को लागू करने के लिए एक वर्ग की क्षमता।

    चूँकि इंटरफ़ेस में परिवर्तनशील क्षेत्र नहीं होते हैं, इसलिए आपको उन समस्याओं के बारे में चिंता करने की ज़रूरत नहीं है जो यहाँ राज्य के कई उत्तराधिकार से उत्पन्न होती हैं।


4

यह कहा जाता है कि वस्तुओं के राज्य को इसमें खेतों के संबंध में संदर्भित किया जाता है और यह बहुत अस्पष्ट हो जाएगा यदि बहुत सारी कक्षाएं विरासत में मिलीं। लिंक यहां दिया गया है

http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html


4

जावा केवल इंटरफेस के माध्यम से कई विरासत का समर्थन करता है। एक वर्ग किसी भी संख्या में इंटरफेस को लागू कर सकता है लेकिन केवल एक वर्ग का विस्तार कर सकता है।

एकाधिक वंशानुक्रम का समर्थन नहीं किया जाता है क्योंकि यह घातक हीरे की समस्या की ओर जाता है। हालाँकि, इसे हल किया जा सकता है, लेकिन यह जटिल प्रणाली की ओर जाता है इसलिए जावा संस्थापकों द्वारा कई विरासत को गिरा दिया गया है।

फरवरी १ ९९ ५ में जेम्स गोस्लिंग द्वारा "जावा: ए ओवरव्यू" नामक श्वेत पत्र में ( लिंक ) एक विचार देता है कि जावा में एकाधिक वंशानुक्रम का समर्थन क्यों नहीं किया गया है।

गोस्लिंग के अनुसार:

"JAVA ने C ++ की कई भ्रामक, खराब समझी जाने वाली भ्रामक विशेषताओं को छोड़ दिया है, जो हमारे अनुभव में bene b t की तुलना में अधिक दु: ख पहुंचाती हैं। इसमें मुख्य रूप से ऑपरेटर ओवरलोडिंग (हालांकि इसमें ओवरलोडिंग का तरीका होता है), मल्टीपल इनहेरेंडेंस, और व्यापक ऑटोमैटिक कॉर्शन होते हैं।"


लिंक सुलभ नहीं है। कृपया इसे जांचें और अपडेट करें।
माशूकखान

3

उसी कारण से C # एकाधिक उत्तराधिकार की अनुमति नहीं देता है लेकिन आपको कई इंटरफ़ेस लागू करने की अनुमति देता है।

C ++ w / multiple inheritence से सीखा गया पाठ यह था कि यह मूल्य की तुलना में अधिक मुद्दों को जन्म देता है।

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

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


10
C # में एक से अधिक वंशानुक्रम नहीं है क्योंकि जावा इसकी अनुमति नहीं देता है। यह जावा की तुलना में बहुत बाद में डिजाइन किया गया था। मुझे लगता है कि जिस तरह से कई लोगों के साथ मुख्य समस्या यह थी कि लोगों को इसे बाएं और दाएं का उपयोग करने के लिए सिखाया गया था। यह अवधारणा कि ज्यादातर मामलों में प्रतिनिधिमंडल एक बेहतर विकल्प है, बस नब्बे के दशक की शुरुआत में नहीं था। इसलिए मुझे उदाहरण याद है, पाठ्यपुस्तकों में, जब कार एक पहिया और एक दरवाजा और एक विंडशील्ड है, बनाम कार में व्हील, दरवाजे और विंडशील्ड शामिल हैं। तो जावा में एकल वंशानुक्रम उस वास्तविकता के लिए एक घुटने का झटका था।
अलेक्जेंडर पोगरेबनेक

2
@AlexanderPogrebnyak: निम्नलिखित तीन में से दो चुनें: (1) एक उपप्रकार संदर्भ के लिए उप-संदर्भ संदर्भ से पहचान-संरक्षण की अनुमति दें; (2) एक वर्ग को व्युत्पन्न वर्गों को फिर से जमा किए बिना आभासी सार्वजनिक सदस्यों को जोड़ने की अनुमति दें; (3) स्पष्ट रूप से निर्दिष्ट किए बिना एक वर्ग को कई आधार वर्गों से अंतर्निहित आभासी सदस्यों को निहित करने की अनुमति दें। मुझे विश्वास नहीं है कि उपरोक्त तीनों का प्रबंधन किसी भी भाषा के लिए संभव है। जावा ने # 1 और # 2, और C # के बाद सूट का विकल्प चुना। मेरा मानना ​​है कि C ++ # 3 को ही अपनाता है। व्यक्तिगत रूप से, मुझे लगता है कि # 3 की तुलना में # 1 और # 2 अधिक उपयोगी हैं, लेकिन अन्य भिन्न हो सकते हैं।
सुपरकैट

@supercat "मुझे विश्वास नहीं है कि उपरोक्त तीनों को प्रबंधित करना किसी भी भाषा के लिए संभव है" - यदि संकलन के समय के बजाय डेटा सदस्यों के ऑफ़सेट रनटाइम पर निर्धारित किए जाते हैं, (जैसा कि वे ऑब्जेक्टिव-सी के "नॉन-फ्रेगरेंस एबीआई" में हैं। "), और या एक प्रति-वर्ग आधार (अर्थात प्रत्येक ठोस वर्ग की अपनी सदस्य तालिका होती है), तो मुझे लगता है कि सभी 3 लक्ष्यों को प्राप्त किया जा सकता है।
पैरामैग्नेटिक क्रोइसैंट

@ TheParamagneticCroissant: प्रमुख अर्थ समस्या # 1 है। यदि D1और D2से दोनों इनहेरिट B, और प्रत्येक ओवरराइड एक समारोह fहै, और अगर objएक प्रकार का एक उदाहरण है Sजो दोनों से विरासत में मिली D1और D2लेकिन हावी नहीं होता fहै, तो एक संदर्भ के लिए कास्टिंग Sके लिए D1कुछ जिसका उपज चाहिए fका उपयोग करता है D1ओवरराइड, और करने के लिए कास्टिंग Bनहीं करना चाहिए उसे बदलो। इसी तरह एक संदर्भ कास्टिंग Sके लिए D2एक कुछ जिसका उपज चाहिए fका उपयोग करता है D2ओवरराइड, और करने के लिए कास्टिंग Bकि परिवर्तन नहीं होना चाहिए। यदि किसी भाषा को आभासी सदस्यों को जोड़ने की अनुमति देने की आवश्यकता नहीं है ...
सुपरकैट

1
@ TheParamagneticCroissant: यह, और मेरी पसंद की सूची को कुछ हद तक एक टिप्पणी में फिट करने के लिए सरलीकृत किया जा सकता था, लेकिन रन-टाइम के संदर्भ में डी 1, डी 2, या एस के लेखक के लिए यह असंभव बना देता है कि वे यह जान सकें कि वे बिना बदलाव के क्या कर सकते हैं। उनके वर्ग के उपभोक्ता।
सुपरकाट

2

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

निम्नलिखित वर्ग पर विचार करें:

public class Abc{

    public void doSomething(){

    }

}

इस मामले में वर्ग एबीसी सही कुछ भी नहीं बढ़ाता है? इतनी जल्दी नहीं, इस वर्ग के निहितार्थ से क्लास ऑब्जेक्ट, बेस क्लास का विस्तार होता है जो जावा में सब कुछ काम करने की अनुमति देता है। सब कुछ एक वस्तु है।

आप वर्ग का उपयोग करने के ऊपर आप देखेंगे कि आपके आईडीई तुम जैसे तरीकों का उपयोग करने की अनुमति की कोशिश करते हैं: equals(Object o), toString(), आदि, लेकिन आप उन तरीकों की घोषणा नहीं किया, वे आधार वर्ग से आयाObject

तुम कोशिश कर सकते हो:

public class Abc extends String{

    public void doSomething(){

    }

}

यह ठीक है, क्योंकि आपका वर्ग निहित नहीं होगा, Objectलेकिन विस्तारित होगा Stringक्योंकि आपने कहा था। निम्नलिखित बदलाव पर विचार करें:

public class Abc{

    public void doSomething(){

    }

    @Override
    public String toString(){
        return "hello";
    }

}

अब आपकी कक्षा हमेशा "हैलो" लौटाएगी यदि आप स्ट्रींग () को कॉल करते हैं।

अब निम्न वर्ग की कल्पना करें:

public class Flyer{

    public void makeFly(){

    }

}

public class Bird extends Abc, Flyer{

    public void doAnotherThing(){

    }

}

फिर से वर्ग Flyerनिहित वस्तु का विस्तार होता है जो विधि है toString(), किसी भी वर्ग के पास यह विधि होगी क्योंकि वे सभी Objectअप्रत्यक्ष रूप से विस्तारित होते हैं , इसलिए, यदि आप कॉल करते toString()हैं Bird, तो किस toString()जावा का उपयोग करना होगा? से Abcया Flyer? यह किसी भी वर्ग के साथ होगा जो दो या अधिक वर्गों को विस्तारित करने का प्रयास करता है, इस तरह की "विधि टक्कर" से बचने के लिए उन्होंने इंटरफ़ेस का विचार बनाया , मूल रूप से आप उन्हें एक सार वर्ग के रूप में सोच सकते हैं जो परोक्ष रूप से ऑब्जेक्ट का विस्तार नहीं करता है । चूंकि वे अमूर्त हैं, इसलिए उन्हें एक वर्ग द्वारा लागू करना होगा, जो एक वस्तु है (आप अकेले एक इंटरफेस नहीं बना सकते हैं, उन्हें एक वर्ग द्वारा लागू किया जाना चाहिए), इसलिए सब कुछ ठीक काम करना जारी रखेगा।

इंटरफेस से कक्षाओं को अलग करने के लिए, कीवर्ड इंप्लाइमेंट केवल इंटरफेस के लिए आरक्षित किया गया था।

आप अपनी पसंद के किसी भी इंटरफ़ेस को एक ही कक्षा में लागू कर सकते हैं क्योंकि वे डिफ़ॉल्ट रूप से कुछ भी नहीं बढ़ाते हैं (लेकिन आप एक इंटरफ़ेस बना सकते हैं जो दूसरे इंटरफ़ेस का विस्तार करता है, लेकिन फिर से, "पिता" इंटरफ़ेस ऑब्जेक्ट नहीं बढ़ाएगा "), इसलिए एक इंटरफ़ेस है बस एक इंटरफ़ेस और वे " विधियों हस्ताक्षर कॉलिशन " से पीड़ित नहीं होंगे , यदि वे करते हैं तो कंपाइलर आपको चेतावनी देगा और आपको इसे ठीक करने के लिए विधि हस्ताक्षर को बदलना होगा (हस्ताक्षर = विधि का नाम + params + वापसी प्रकार) ।

public interface Flyer{

    public void makeFly(); // <- method without implementation

}

public class Bird extends Abc implements Flyer{

    public void doAnotherThing(){

    }

    @Override
    public void makeFly(){ // <- implementation of Flyer interface

    }

    // Flyer does not have toString() method or any method from class Object, 
    // no method signature collision will happen here

}

1

क्योंकि एक इंटरफ़ेस सिर्फ एक अनुबंध है। और एक वर्ग वास्तव में डेटा के लिए एक कंटेनर है।


मल्टीपल इनहेरिटेंस के साथ मूलभूत कठिनाई यह संभावना है कि एक वर्ग एक सदस्य को कई रास्तों के माध्यम से विरासत में प्राप्त कर सकता है जो इसे अलग तरीके से लागू करते हैं, बिना अपने स्वयं के ओवरराइड कार्यान्वयन प्रदान करते हैं। इंटरफ़ेस वंशानुक्रम इससे बचा जाता है क्योंकि केवल स्थान इंटरफ़ेस सदस्यों को लागू किया जा सकता है, कक्षाओं में होता है, जिनके वंशज एकल वंशानुक्रम तक सीमित होंगे।
19

1

उदाहरण के लिए दो वर्ग A, B में एक ही विधि m1 () है। और कक्षा C, A, B दोनों का विस्तार करता है।

 class C extends A, B // for explaining purpose.

अब, वर्ग C m1 की परिभाषा खोजेगा। सबसे पहले, यह कक्षा में खोज करेगा यदि यह नहीं मिला तो यह माता-पिता की कक्षा में जाँच करेगा। दोनों A, B की परिभाषा है इसलिए यहाँ अस्पष्टता होती है कि कौन सी परिभाषा चुननी चाहिए। तो जावेद ने बहुउद्देश्यीय समर्थन नहीं किया।


जावा कंपाइलर बनाने के बारे में कैसे संकलक देता है अगर दोनों पैरेंट क्लास में समान तरीके या वैरिएबल को परिभाषित किया जाए ताकि हम कोड को बदल सकें ...
siluveru kiran kumar

1

जावा दो कारणों से एकाधिक वंशानुक्रम का समर्थन नहीं करता है:

  1. जावा में, हर वर्ग कक्षा का एक बच्चा है Object। जब यह एक से अधिक सुपर क्लास से विरासत में मिलता है, तो सब क्लास को ऑब्जेक्ट क्लास की संपत्ति हासिल करने की अस्पष्टता मिलती है।
  2. जावा में हर वर्ग का एक कंस्ट्रक्टर है, अगर हम इसे स्पष्ट रूप से लिखते हैं या बिल्कुल नहीं। पहला बयान super()समर्थक वर्ग निर्माता को आह्वान करने के लिए बुला रहा है। यदि कक्षा में एक से अधिक सुपर क्लास हैं, तो यह भ्रमित हो जाता है।

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


0

उदाहरण के लिए उदाहरण लीजिए कि क्लास ए में गेटसमॉर्टिंग मेथड है और क्लास बी में गेट्सोमेटिंग मेथड है और क्लास सी में ए और बी का विस्तार होता है। अगर कोई सी। सॉटसोमेटिंग कहलाता है तो क्या होगा? यह निर्धारित करने का कोई तरीका नहीं है कि किस पद्धति को कॉल करना है।

मूल रूप से इंटरफेस केवल यह निर्दिष्ट करता है कि एक कार्यान्वयन वर्ग को किन तरीकों की आवश्यकता है। एक वर्ग जो कई इंटरफेस को लागू करता है, इसका मतलब है कि कक्षा को उन सभी इंटरफेस से तरीकों को लागू करना है। जैसा कि ऊपर वर्णित किसी भी मुद्दे पर कोई भी नहीं करेगा।


2
" यदि कोई व्यक्ति C.getSomething कहलाता है तो क्या होगा। " C ++ में यह एक त्रुटि है। समस्या सुलझ गयी।
जिज्ञासु

यह वह बिंदु था ... जो एक काउंटर उदाहरण था जो मुझे लगा कि स्पष्ट था। मैं इंगित कर रहा था कि यह निर्धारित करने का कोई तरीका नहीं है कि किस विधि को प्राप्त किया जाए। एक साइड नोट के रूप में, यह प्रश्न जावा से संबंधित नहीं था c + +
जॉन केन ने

मुझे खेद है कि मुझे आपकी बात नहीं मिली। जाहिर है, एमआई के साथ कुछ मामलों में अस्पष्टता है। यह एक काउंटर उदाहरण कैसे है? किसने दावा किया कि एमआई में कभी भी अस्पष्टता नहीं होती है? " इसके अलावा एक साइड नोट के रूप में, सवाल जावा से संबंधित नहीं था c ++ " तो?
उत्सुकता

मैं सिर्फ यह दिखाने की कोशिश कर रहा था कि यह अस्पष्टता क्यों है और यह इंटरफेस के साथ क्यों नहीं है।
जॉन केन

हां, एमआई के परिणामस्वरूप अस्पष्ट कॉल हो सकते हैं। इसलिए ओवरलोडिंग हो सकती है। तो जावा को ओवरलोडिंग को दूर करना चाहिए?
जिज्ञासु

0

एक परिदृश्य पर विचार करें जहां टेस्ट 1, टेस्ट 2 और टेस्ट 3 तीन कक्षाएं हैं। टेस्ट 3 वर्ग को टेस्ट 2 और टेस्ट 1 कक्षाएं विरासत में मिली हैं। यदि Test1 और Test2 वर्गों में समान विधि है और आप इसे चाइल्ड क्लास ऑब्जेक्ट से कहते हैं, तो Test1 या Test2 वर्ग की कॉल विधि के लिए अस्पष्टता होगी, लेकिन इंटरफ़ेस के लिए ऐसी कोई अस्पष्टता नहीं है क्योंकि इंटरफ़ेस में कोई कार्यान्वयन नहीं है।


0

अस्पष्टता समस्या के कारण जावा बहु विरासत, बहुपथ और संकर विरासत का समर्थन नहीं करता है:

 Scenario for multiple inheritance: Let us take class A , class B , class C. class A has alphabet(); method , class B has also alphabet(); method. Now class C extends A, B and we are creating object to the subclass i.e., class C , so  C ob = new C(); Then if you want call those methods ob.alphabet(); which class method takes ? is class A method or class B method ?  So in the JVM level ambiguity problem occurred. Thus Java does not support multiple inheritance.

कई विरासत

संदर्भ लिंक: https://plus.google.com/u/0/communities/102217496457095083679


0

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


1
आप यहाँ उन उदाहरणों को पोस्ट कर सकते हैं। इसके बिना यह पाठ का एक खंड जैसा दिखता है 9 साल पुराने प्रश्न का उत्तर सौ बार दिया गया।
पोचमर्निक

-1

* यह एक सरल उत्तर है क्योंकि मैं जावा में एक शुरुआत हूँ *

विचार करें कि तीन वर्ग हैं X, Yऔर Z

तो हम जैसे विरासत में कर रहे हैं X extends Y, Z और दोनों Yऔर Zएक विधि चल रहा है alphabet()एक ही वापसी प्रकार और तर्क के साथ। इस विधि alphabet()में Yकरने के लिए कहते हैं पहले वर्णमाला प्रदर्शित और विधि वर्णमाला में Zकहते हैं प्रदर्शन पिछले वर्णमाला । तो यहाँ जब alphabet()बुलाया जाता है तो अस्पष्टता आती है X। चाहे वह पहले या अंतिम वर्णमाला को प्रदर्शित करने के लिए कहता है ??? इसलिए जावा मल्टीपल इनहेरिटेंस का समर्थन नहीं कर रहा है। इंटरफेस के मामले में, विचार करें Yऔर Zइंटरफेस के रूप में। तो दोनों में विधि की घोषणा शामिल होगी alphabet()लेकिन परिभाषा नहीं। यह नहीं बताएगा कि पहले वर्णमाला या अंतिम वर्णमाला या कुछ भी प्रदर्शित करना है लेकिन सिर्फ एक विधि की घोषणा करेंगेalphabet()। इसलिए अस्पष्टता बढ़ाने का कोई कारण नहीं है। हम कक्षा के अंदर जो कुछ भी चाहते हैं उसके साथ विधि को परिभाषित कर सकते हैं X

तो एक शब्द में, इंटरफेस में परिभाषा को लागू करने के बाद किया जाता है ताकि कोई भ्रम न हो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.