दो वर्गों से विस्तार


150

मैं यह कैसे कर सकता हूँ:

public class Main extends ListActivity , ControlMenu 

इसके अलावा, मैं जानना चाहूंगा कि क्या यह दृष्टिकोण ठीक है कि मैंने मेनू को कक्षा में बनाया है जो कि कंट्रोलमेनू है और मैं बाकी गतिविधियों में विस्तार कर रहा हूं।


4
आप एक समय में दो या अधिक कक्षाओं का विस्तार नहीं कर सकते। जावा में एकाधिक वंशानुक्रम की अनुमति नहीं है।
योगमास

जवाबों:


156

आप केवल एकल वर्ग का विस्तार कर सकते हैं। और कई स्रोतों से इंटरफेस लागू करें।

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

 public class CustomActivity extends Activity {

     private AnotherClass mClass;

     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mClass = new AnotherClass(this);
     }

     //Implement each method you want to use.
     public String getInfoFromOtherClass()
     {
        return mClass.getInfoFromOtherClass();
     }
 }

यह सबसे अच्छा समाधान है जो मैं लेकर आया हूं। आप दोनों वर्गों से कार्यक्षमता प्राप्त कर सकते हैं और फिर भी वास्तव में केवल एक वर्ग प्रकार के हो सकते हैं।

दोष यह है कि आप कास्ट का उपयोग करके आंतरिक वर्ग के मोल्ड में फिट नहीं हो सकते हैं।


2
आप जल्दी थे :) मैं अपने ठोस उदाहरण की तुलना करने के लिए कुछ अमूर्त
जुए के

1
यह एक बहुत अच्छा विकल्प है, और भविष्य में बहुत अधिक लचीलापन प्रदान करता है।
डेविड सौथर

1
अधिक एक और अधिक OOP समाधान के लिए @SCB समाधान देखें
idish

मैं यहां अधिक सटीक उदाहरण का उपयोग कर सकता हूं। पक्का नहीं मै समझ गया।
2042 पर Neo42

54

इनर क्लास (नेस्टिंग) का उपयोग क्यों नहीं

class A extends B {
    private class C extends D {
        //Classes A , B , C , D accessible here 
    }
}

4
इंटरस्टिंग दृष्टिकोण, विशेषज्ञ इस तकनीक के बारे में क्या सोचते हैं? मैं इसमें खुदाई करना चाहता हूं।
TechNyquist

1
क्या यह सम्मेलनों के साथ ठीक है?
जूल 25'14

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

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

45

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

कहो कि तुम्हारे पास है class Fooऔर class Barतुम दोनों एक में विस्तार करने की कोशिश करना चाहते हो class FooBar। बेशक, जैसा कि आपने कहा, आप ऐसा नहीं कर सकते:

public class FooBar extends Foo, Bar

लोग कुछ हद तक इसके कारणों में पहले ही जा चुके हैं। इसके बजाय, interfacesदोनों को लिखें Fooऔर Barअपने सभी सार्वजनिक तरीकों को कवर करें। उदाहरण के लिए

public interface FooInterface {

    public void methodA();

    public int methodB();

    //...
} 

public interface BarInterface {

    public int methodC(int i);

    //...
}

और अब सापेक्ष इंटरफेस बनाते हैं Fooऔर Barलागू करते हैं:

public class Foo implements FooInterface { /*...*/ }

public class Bar implements BarInterface { /*...*/ }

अब, के साथ class FooBar, आप दोनों को लागू कर सकते FooInterfaceहैं और BarInterfaceजबकि एक रखने Fooऔर Barवस्तु और बस के माध्यम से सीधे तरीकों से गुजर रहा:

public class FooBar implements FooInterface, BarInterface {

    Foo myFoo;
    Bar myBar;

    // You can have the FooBar constructor require the arguments for both
    //  the Foo and the Bar constructors
    public FooBar(int x, int y, int z){
        myFoo = new Foo(x);
        myBar = new Bar(y, z);
    }

    // Or have the Foo and Bar objects passed right in
    public FooBar(Foo newFoo, Bar newBar){
        myFoo = newFoo;
        myBar = newBar;
    }

    public void methodA(){
        myFoo.methodA();
    }

    public int methodB(){
        return myFoo.methodB();
    }

    public int methodC(int i){
        return myBar.methodC(i);
    }

    //...

}

इस विधि के लिए बोनस, यह है कि FooBarवस्तु दोनों के सांचे में फिट बैठता है FooInterfaceऔर BarInterface। इसका मतलब है कि यह पूरी तरह से ठीक है:

FooInterface testFoo;
testFoo = new FooBar(a, b, c);
testFoo = new Foo(a);

BarInterface testBar;
testBar = new FooBar(a, b, c);
testBar = new Bar(b, c);

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


6
यह सबसे अच्छा जवाब है
user3290180

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

क्या होगा यदि हमें नई कक्षाएं "बार-बार" बनानी पड़ें और उन कक्षाओं में से प्रत्येक को दोनों इंटरफेस लागू करें? फिर, हमें प्रत्येक वर्ग में इन बॉयलरप्लेट कार्यान्वयन को दोहराना होगा। क्या व्यवहार के दो सेटों को "लागू" करने का एक बेहतर तरीका है?
मास्टरजेओ 2

1
@ MasterJoe2 ईमानदार होने के लिए, मैंने अभी कुछ समय के लिए जावा का उपयोग करके बहुत कुछ नहीं किया है (मैंने यह उत्तर लिखने के समय के आसपास रोक दिया)। जिन कारणों से मैं इससे बचता हूं, उनमें से एक अब आपके द्वारा उठाए जाने वाले मुद्दे हैं। एक दिशा के लिए एक कूबड़ जिसकी आप संभवतः जांच कर सकते हैं, एक अमूर्त वर्ग लिख रहा है जो दोनों इंटरफेस को लागू करता है, और इसे विस्तारित करता है। हालाँकि, यदि मेरे पास वैध जावा है, तो मुझे कोई सुराग नहीं है, और मुझे लगता है कि जब आप भविष्य में कार्यान्वयन वर्ग में बदलाव करना चाहते हैं, तो आप एक ही मूल समस्या के साथ समाप्त करेंगे। क्षमा करें, मैं मदद के लिए अधिक नहीं हो सकता।
SCB

37

आप इंटरफेस का उपयोग करना चाहेंगे। आमतौर पर, डायमंड की समस्या के कारण कई विरासत खराब होती हैं:

abstract class A {
 abstract string foo();
}

class B extends A {
 string foo () { return "bar"; }
}

class C extends A  {
 string foo() {return "baz"; }
}

class D extends B, C {
 string foo() { return super.foo(); } //What do I do? Which method should I call?
}

C ++ और अन्य के पास इसे हल करने के लिए कुछ तरीके हैं, जैसे

string foo() { return B::foo(); }

लेकिन जावा केवल इंटरफेस का उपयोग करता है।

जावा ट्रेल्स इंटरफेस पर एक महान परिचय है: http://download.oracle.com/javase/tutorial/java/concepts/interface.html आप Android एपीआई में बारीकियों में गोता लगाने से पहले शायद इसका पालन करना चाहते हैं।


24
मुझे यह कभी समझ में नहीं आया कि हीरे की समस्या वास्तव में एक समस्या क्यों है जो कई विरासतों को रोकती है। कंपाइलर सिर्फ शिकायत नहीं कर सकता है अगर एक ही नाम के साथ परस्पर विरोधी विधियां हैं?
पीट

1
पर्याप्त रूप से बुद्धिमान संकलक के लिए, यह नहीं है। संकलक स्तर पर इसे हल करना संभव है, और वास्तव में सी ++ इसके साथ करता है virtual class। ऐसा करना कंपाइलर और डेवलपर दोनों के लिए कई चेतावनियों और चेतावनी के साथ आता है।
डेविड सूटर

1
कैसे दो इंटरफेस में एक ही डिफ़ॉल्ट तरीकों के बारे में? यह हीरे की समस्या का एक और उदाहरण है, जिसे जावा संभाल सकता है।
लाजोस मेस्सरोस

1
@ MészárosLajos लेकिन आपको superविरासत में मिली विधि से कॉल नहीं आता है । ठीक है, आप कर सकते हैं, लेकिन आपको आह्वान करने के लिए इंटरफ़ेस विधि को निर्दिष्ट करना होगा (और इसे defaultइंटरफ़ेस कार्यान्वयन में कीवर्ड का उपयोग करना होगा ) । एक उदाहरण है: MyIFace.super.foo()जहां MyIFace एक इंटरफ़ेस है। जैसा कि आप देख सकते हैं कि निष्पादित करने के लिए इंटरफ़ेस विधि परिभाषित है और पूरी तरह से डायमंड समस्या से बचा जाता है। यदि आप विस्तार करते हैं MyClass1और MyClass2दोनों वर्गों में ए foo(), और कॉल है super.foo()तो संकलक को डायमंड समस्या द्वारा फेंक दिया जाता है।
JDSweetBeat

आप वापसी नहीं कर सकते हैं "bar"या "baz"विधि के प्रकार के साथ नहीं कर सकते हैं void। वैसे भी, अच्छी व्याख्या xD
xdevs23

22

हाँ, जैसा कि बाकी सभी ने लिखा है, आप जावा में कई उत्तराधिकार नहीं कर सकते। यदि आपके पास दो कक्षाएं हैं जिनसे आप कोड का उपयोग करना चाहते हैं, तो आप आम तौर पर केवल एक (वर्ग कहते हैं A) उपवर्ग का उपयोग करेंगे । कक्षा के लिए B, आप एक इंटरफ़ेस BInterface(बदसूरत नाम, लेकिन आपको यह विचार मिलता है) के महत्वपूर्ण तरीकों का सार करते हैं , फिर कहते हैं Main extends A implements BInterface। अंदर, आप कक्षा के किसी ऑब्जेक्ट को तुरंत कर सकते हैं Bऔर BInterfaceउसी के कार्यों को कॉल करके सभी तरीकों को लागू कर सकते हैं B

यह "a-a" रिलेशनशिप टू "ए-ए" रिलेशनशिप को बदल देता है क्योंकि आपका Mainअब एक है A, लेकिन ए है B। आपके उपयोग के मामले के आधार पर, आप BInterfaceअपनी Aकक्षा से हटाकर उस परिवर्तन को स्पष्ट भी कर सकते हैं और इसके बजाय अपनी B ऑब्जेक्ट को सीधे एक्सेस करने की विधि प्रदान करते हैं।


यह स्पष्टीकरण के लिए सबसे सुपाठ्य और आसान है। अधिक upvotes कृपया।
अल्गोरिनि

12

एक इंटरफ़ेस बनाओ। जावा में एकाधिक उत्तराधिकार नहीं है।

http://csis.pace.edu/~bergin/patterns/multipleinheritance.html


9
क्यों नीच? मेरा मतलब यह नहीं था, मुझे लगता है कि वह कुछ पढ़ने का खर्च उठा सकता है और इससे पहले कि हम उसके लिए अपनी कक्षाओं का निर्माण करें, उसके बारे में
सोचें

6

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


4

हाँ। बदनामी सही है। जावा कई वर्गों से विस्तार करने की अनुमति नहीं देता है।

आप जो चाहते हैं वह शायद है public class Main extends ListActivity implements ControlMenu। मैं अनुमान लगा रहा हूं कि आप एक सूची बनाने की कोशिश कर रहे हैं।

उम्मीद है की वो मदद करदे।


3

एक अन्य विकल्प की तरह, शायद आप एक विधि के डिफ़ॉल्ट कार्यान्वयन के साथ एक इंटरफ़ेस का उपयोग कर सकते हैं। यह इस बात पर निर्भर करता है कि आप क्या करना चाहते हैं।

उदाहरण के लिए, आप एक सार वर्ग और एक इंटरफ़ेस बना सकते हैं:

public abstract class FatherClass {

    abstract void methodInherit() {
        //... do something
    }
}

public interface InterfaceWithDefaultsMethods {
    default void anotherMethod() {
        //... do something
        //... maybe a method with a callable for call another function.
    }
}

तो, उसके बाद, आप दोनों वर्गों का विस्तार और कार्यान्वयन कर सकते हैं और दोनों विधियों का उपयोग कर सकते हैं।

public class extends FatherClass implements InterfaceWithDefaultsMethods {

    void methode() {
        methodInherit();
        anotherMethod();
    }
}

आशा है कि यह आपकी मदद करेगा ...



2

यह संभव है

public class ParallaxViewController<T extends View & Parallaxor> extends ParallaxController<T> implements AbsListView.OnScrollListener {

//blah
}

Parallaxorऔर ParallaxControllerअज्ञात हैं, इसलिए मुझे लगता है कि वे एसडीके-कक्षाएं नहीं हैं। तो यह मेरे लिए काम नहीं करता है (और इस तरह यह उत्तर त्रुटियों को दर्शाता है)। ParallaxController क्या है? क्या यह एक विशिष्ट निर्भरता है? कृपया विस्तृत करें
झो

1

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

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


0

आप जावा में कई उत्तराधिकार नहीं कर सकते। इंटरफेस का उपयोग करने पर विचार करें:

interface I1 {}
interface I2 {}
class C implements I1, I2 {}

या भीतरी वर्ग:

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