İki sınıftan genişletme


150

Bunu nasıl yapabilirim:

public class Main extends ListActivity , ControlMenu 

Ayrıca, bu yaklaşımın, menülerde ControlMenu olan sınıfta yaptığımın iyi olduğunu bilmek istiyorum ve aktivitelerin geri kalanında uzanıyorum.


4
Bir seferde iki veya daha fazla sınıfı genişletemezsiniz. Java'da çoklu kalıtıma izin verilmez.
yogsma

Yanıtlar:


156

Yalnızca tek bir sınıfı genişletebilirsiniz. Ve birçok kaynaktan arayüzler uygulayın.

Birden fazla sınıfı genişletmek mümkün değildir. Düşünebildiğim tek çözüm, her iki sınıfı da miras almak değil, her sınıfın dahili değişkenine sahip olmak ve isteklerinizi nesnenize gitmelerini istediğiniz nesneye yönlendirerek daha fazla proxy yapmaktır.

 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();
     }
 }

bu benim en iyi çözümüm. Her iki sınıftan da işlevsellik alabilirsiniz ve yine de yalnızca bir sınıf türünde olabilirsiniz.

Dezavantajı, bir döküm kullanarak Dahili sınıfın Kalıp içine sığamaz olmasıdır.


2
Daha hızlı davrandın :) Somut örneğinizle karşılaştırmak için bazı soyut başıboş cevap olarak cevabımı bırakacağım;)
Nicolas78 29:11

1
Bu çok güzel bir alternatif ve gelecekte çok daha fazla esneklik sağlıyor.
David Souther

1
Daha fazla OOP çözümü için @SCB çözümüne bakın
idish

Burada daha kesin bir örnek verebilirim. Anladığımdan emin değilim.
Neo42

54

Neden İç Sınıf Kullanmıyorsunuz (Yerleştirme)

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

4
Araya giren yaklaşım, uzmanlar bu teknik hakkında ne düşünüyor? Onu araştırmak istiyorum.
TechNyquist

1
Sözleşmelerde sorun yok mu?
totten

2
İç sınıf bir çalışmak için alınamadı Fragment. Etkinliğim uzatılmalı Fragment, yani kesinlikle ihtiyacım var getView(), bu iç sınıfta ise işe yaramaz ve içindeki koddan kod kullanmam gereken yer ListActivity, bu yüzden iki kez uzatamıyorum, VEYA bir iç sınıf yapıyorum bu örnekte.
Azurespot

Bu, yaklaşan sınıfın değişkenlerine erişmeniz gereken soyut sınıfları genişletmek için en iyi çözümdür.
tak3shi

45

Herkesin söylediği gibi. Hayır, yapamazsınız. Bununla birlikte, insanlar yıllar boyunca birçok kez birden fazla arayüz kullanmanız gerektiğini söylemiş olsalar da, gerçekten nasıl olduklarına girmediler. Umarım bu yardımcı olacaktır.

Sahip olduğunuzu class Foove class Barher ikinizin de a class FooBar. Tabii ki, dediğin gibi yapamazsın:

public class FooBar extends Foo, Bar

İnsanlar zaten bir dereceye kadar bunun nedenlerine girdiler. Bunun yerine, interfacesher ikisi için de yazın Foove Bartüm kamu yöntemlerini kapsar. Örneğin

public interface FooInterface {

    public void methodA();

    public int methodB();

    //...
} 

public interface BarInterface {

    public int methodC(int i);

    //...
}

Ve şimdi göreli arayüzleri yapın Foove Baruygulayın:

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

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

Şimdi, ile class FooBar, her iki uygulayabilirsiniz FooInterfaceve BarInterfacebir tutarken Foove Barnesne ve sadece içinden düz yöntemleri geçen:

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);
    }

    //...

}

Bu yöntemin avantajı, FooBarnesnenin hem FooInterfaceve hem de kalıplarına uymasıdır BarInterface. Bunun anlamı gayet iyi:

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);

Umarım bu, çoklu uzantılar yerine arayüzlerin nasıl kullanılacağını açıklar. Birkaç yıl geç kalsam bile.


6
bu en iyi cevaptır
user3290180

Bu çok iyi bir cevap, ancak daha ayrıntılı olarak ele alınması gereken birkaç sorun görüyorum. Birincisi, mevcut iki sınıftan biraz daha sorunlu olurdu ve geçmesi gereken bir takım ekstra engeller olacaktır, İkincisi, Foo ve Bar'ın her ikisinin de aynı işlevlere sahip olması durumunda, bir öncelik sırasına sahip olmanız gerekir. Sınıfınızı açıkça genişletmek sizi bu kararları ön plana çıkarmaya zorlar. Yine de, Mükemmel seçenek :) +1
Tembel Kodlayıcı

Yeni sınıflar "sık sık" oluşturmalı ve bu sınıfların her birini her iki arabirimi de uygulamalı yapsak ne olur? Daha sonra, her bir sınıftaki bu kazan plakası uygulamalarını tekrarlamak zorunda kalacağız. Bir sınıfı iki davranış kümesini "uygulamak" için daha iyi bir yol var mı?
MasterJoe2

1
@ MasterJoe2 Dürüst olmak gerekirse, bir süredir Java kullanarak çok fazla şey yapmadım (bu cevabı yazdığım sırada durdum). Her gün kaçınmamın nedenlerinden biri de gündeme getirdiğiniz konudur. Muhtemelen araştırabileceğiniz bir yön için bir önsezi, her iki arabirimi de uygulayan ve bunu genişleten soyut bir sınıf yazıyor. Ancak, geçerli bir Java varsa hiçbir fikrim yok ve gelecekte uygulayıcı sınıfta değişiklik yapmak istediğinizde aynı orijinal sorunla karşılaşacağınızı hissediyorum. Üzgünüm, daha fazla yardım edemem.
SCB

37

Arayüzler kullanmak isteyeceksiniz. Genel olarak, Elmas Sorunu nedeniyle çoklu kalıtım kötüdür:

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 ++ ve diğerlerinin bunu çözmek için birkaç yolu vardır, örn.

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

ancak Java yalnızca arabirimler kullanır.

Java Parkurları arayüzler hakkında harika bir giriş yapar: http://download.oracle.com/javase/tutorial/java/concepts/interface.html Android API'sındaki nüanslara dalmadan önce muhtemelen bunu takip etmek isteyeceksiniz.


24
Pırlanta sorununun neden birden fazla kalıtımı önleyen bir problem olduğunu asla anlamadım. Derleyici neden aynı ada sahip çakışan yöntemler varsa şikayet etmiyor?
pete

1
Yeterince akıllı derleyiciler için öyle değil. Derleyici düzeyinde çözmek mümkündür ve gerçekten de C ++ bunu yapar virtual class. Bunu yapmak, derleyici ve geliştirici için birçok uyarı ve uyarı ile birlikte gelir.
David Souther

1
İki arayüzde aynı varsayılan yöntemlere ne dersiniz? Bu, java'nın ele alabileceği elmas sorununun bir başka örneğidir.
Lajos Meszaros

1
@ MészárosLajos Ancak super, miras kalan bir yöntemden çağrı yapmazsınız. Evet, ancak çağırılacak arabirim yöntemini belirtmeniz gerekir (ve defaultarabirim uygulamasında anahtar sözcüğü kullanması gerekir ) . Bir örnek: MyIFace.super.foo()burada MyIFace bir arayüzdür. Gördüğünüz gibi yürütmek için arabirim yöntemi tanımlanmış ve Elmas Sorunu tamamen önler. Genişletirseniz MyClass1ve MyClass2her iki sınıfta da a foo()ve çağrı super.foo()varsa derleyici Elmas Sorunu tarafından atılır.
JDSweetBeat

Dönemez "bar"veya "baz"yöntem türü ile void. Neyse, iyi bir açıklama xD
xdevs23

22

Evet, herkesin yazdığı gibi, Java'da çoklu kalıtım yapamazsınız. Kodunu kullanmak istediğiniz iki sınıfınız varsa, genellikle yalnızca bir alt sınıf (sınıf diyelim A) olur. Sınıf için B, bunun önemli yöntemlerini bir arayüze BInterface(çirkin ad, ama fikri anlıyorsunuz) soyutlarsınız , sonra söyleyin Main extends A implements BInterface. İçeride, bir sınıf nesnesini başlatabilir ve ilgili işlevlerini çağırarak Btüm yöntemlerini uygulayabilirsiniz .BInterfaceB

Bu, Mainşu anki gibi bir "has-a" ilişkisini "has-a" ilişkisiyle değiştirir A, ancak bir B. Kullanımı durumda bağlı olarak, hatta kaldırarak bu değişiklik açık hale getirebileceğini BInterfacesizin gelen Asınıf ve yerine doğrudan B nesnesi erişmek için bir yöntem sağlar.


Bu en okunaklı ve anlaşılması kolay bir açıklamadır. Daha fazla oy verin lütfen.
Algorini


6

Java, birden fazla kalıtımı desteklemez, ancak iki veya daha fazla arabirimi uygulamayı deneyebilirsiniz.


4

Evet. slandau haklı. Java birkaç sınıftan genişletmeye izin vermez.

Ne istiyorsun muhtemelen public class Main extends ListActivity implements ControlMenu. Bir liste yapmaya çalıştığınızı tahmin ediyorum.

Umarım yardımcı olur.


3

Başka bir alternatif gibi, belki de bir yöntemin varsayılan uygulaması olan bir arabirim kullanabilirsiniz. Bu elbette ne yapmak istediğinize bağlıdır.

Örneğin, soyut bir sınıf ve bir arayüz oluşturabilirsiniz:

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.
    }
}

Bundan sonra, her iki sınıfı genişletebilir ve uygulayabilir ve her iki yöntemi de kullanabilirsiniz.

public class extends FatherClass implements InterfaceWithDefaultsMethods {

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

Umarım bu sana yardımcı olur ...



2

bu mümkün

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

//blah
}

Parallaxorve ParallaxControllerbilinmiyor, bu yüzden SDK sınıfı olmadığını düşünüyorum. Bu benim için işe yaramıyor (ve dolayısıyla bu cevap hataları gösteriyor). ParallaxController nedir? Bu belirli bir bağımlılık mı? Lütfen detaylandırın
Zoe

1

Java'nın yaratıcıları, çoklu miras sorunlarının faydalardan daha ağır bastığına karar verdiler, bu nedenle çoklu miras içermediler. Burada çoklu kalıtımın en büyük sorunlarından birini (çift elmas sorunu) okuyabilirsiniz .

En benzer iki kavram, arabirim uygulamasıdır ve mevcut sınıfın üyeleri olarak diğer sınıfların nesnelerini içerir. Arabirimlerde varsayılan yöntemleri kullanmak, çoklu kalıtımla neredeyse aynıdır, ancak yalnızca varsayılan yöntemlerle bir arabirim kullanmak kötü bir uygulama olarak kabul edilir.


0

java'da çoklu kalıtım yapamazsınız. arayüzleri kullanmayı düşünün:

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

veya iç sınıflar:

class Outer {
    class Inner1 extends Class1 {}
    class Inner2 extends Class2 {}
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.