Расширение от двух классов

150

Как я могу это сделать:

public class Main extends ListActivity , ControlMenu 

Кроме того, я хотел бы знать, что с этим подходом все в порядке, что я создал меню в классе, который называется ControlMenu, и я расширяю остальные действия.

Умар
источник
4
Вы не можете продлить два или более классов одновременно. Множественное наследование не допускается в Java.
Йогма

Ответы:

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

это лучшее решение, которое я придумал. Вы можете получить функциональность от обоих классов, и все же только на самом деле быть одного типа класса.

Недостатком является то, что вы не можете вписаться в класс Mold of Internal, используя приведение.

Ленивый Кодер
источник
2
Вы были быстрее :) Я оставлю свой ответ как какой-то отвлеченный случай, чтобы сравнить его с вашим конкретным примером;)
Nicolas78
1
Это очень хорошая альтернатива, и она обеспечивает большую гибкость в будущем.
Дэвид Саутер
1
Посмотрите решение @SCB для более подробного решения ООП
идиш
Я мог бы использовать более точный пример здесь. Не уверен, что понимаю.
Neo42
54

Почему бы не использовать внутренний класс (вложение)

class A extends B {
    private class C extends D {
        //Classes A , B , C , D accessible here 
    }
}
Ifte
источник
4
Интересный подход, что эксперты думают об этой технике? Я хотел бы покопаться в этом.
TechNyquist
1
Это нормально с конвенциями?
сегодня,
2
Не удалось получить внутренний класс для работы в Fragment. Моя деятельность должна расширяться Fragment, а это значит, что мне это абсолютно необходимо getView(), что не будет работать, если оно находится внутри внутреннего класса, и код там, где мне нужно использовать код ListActivity, поэтому я не могу расширяться дважды, ИЛИ делать внутренний класс в этом примере.
Azurespot
Это лучшее решение для расширения абстрактных классов, где вам нужен доступ к переменным класса.
tak3shi
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);

Надеюсь, что это проясняет, как использовать интерфейсы вместо нескольких расширений. Даже если я опоздал на несколько лет.

SCB
источник
6
это лучший ответ
user3290180
Это очень хороший ответ, однако я вижу в нем пару проблем, которые необходимо рассмотреть более подробно. Во-первых, расширение из двух существующих классов было бы немного более проблематичным, и было бы множество дополнительных препятствий, которые нужно преодолеть. Во-вторых, если бы интерфейс Foo и Bar имели одинаковые функции, вам необходимо иметь порядок приоритетов. Явное расширение вашего класса заставит вас принимать эти решения заранее. Еще отличный вариант :) +1
Ленивый кодер
Что если нам нужно «часто» создавать новые классы и заставлять каждый из этих классов реализовывать оба интерфейса? Затем мы должны будем повторить эти стандартные реализации в каждом классе. Есть ли лучший способ заставить класс «реализовать» два набора поведения?
MasterJoe2
1
@ MasterJoe2 Честно говоря, я уже давно не очень много пользуюсь Java (я остановился, когда писал этот ответ). Одна из причин, по которой я избегаю этого сейчас, - это та самая проблема, которую вы поднимаете. Предсказание направления, которое вы могли бы исследовать, - написание абстрактного класса, который реализует оба интерфейса и расширяет его. Однако я понятия не имею, верна ли это Java, и чувствую, что вы просто столкнетесь с той же самой первоначальной проблемой, когда захотите внести изменения в реализующий класс в будущем. Извините, я не могу больше помочь.
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(); }

но Java использует только интерфейсы.

В Java Trails есть отличное введение в интерфейсы: http://download.oracle.com/javase/tutorial/java/concepts/interface.html Возможно, вы захотите следовать этому, прежде чем углубляться в нюансы в API Android.

Дэвид Соутер
источник
24
Я никогда не понимал, почему проблема алмазов на самом деле является проблемой, которая предотвращает множественное наследование. Почему компилятор не может просто жаловаться, если есть конфликтующие методы с тем же именем?
Пит
1
Для достаточно умных компиляторов это не так. Решение на уровне компилятора возможно, и в действительности C ++ делает это с помощью virtual class. Это сопровождается множеством предупреждений и предостережений как для компилятора, так и для разработчика.
Дэвид Саутер
1
Как насчет тех же методов по умолчанию в двух интерфейсах? Это еще один пример алмазной проблемы, с которой может справиться Java.
Лайош Месарос
1
@ MészárosLajos Но вы не вызываете superиз метода в наследовании. Ну, вы можете, но вы должны указать метод интерфейса для вызова (и он должен использовать ключевое слово defaultв реализации интерфейса) . Пример: MyIFace.super.foo()где MyIFace является интерфейсом. Как вы можете видеть, интерфейсный метод, который нужно выполнить, определен и полностью исключает проблему Diamond. Если вы расширяете MyClass1и MyClass2, оба класса имеют foo(), и вызов, super.foo()то компилятор выбрасывается Алмазной проблемой.
JDSweetBeat
Вы не можете вернуть "bar"или "baz"с методом типа void. В любом случае, хорошее объяснение xD
xdevs23
22

Да, как и все остальные, вы не можете делать множественное наследование в Java. Если у вас есть два класса, из которых вы хотите использовать код, вы обычно просто подкласс один (скажем, класс A). Для класса Bвы абстрагируете его важные методы в интерфейс BInterface(некрасивое имя, но вы поняли), а затем говорите Main extends A implements BInterface. Внутри вы можете создать экземпляр объекта класса Bи реализовать все методы BInterface, вызывая соответствующие функции B.

Это меняет отношение «есть» на отношение «есть», которое есть у вас Mainсейчас A, но есть B. В зависимости от вашего варианта использования, вы можете даже сделать это изменение явным, удалив BInterfaceиз вашего Aкласса и вместо этого предоставив метод для прямого доступа к вашему объекту B.

Nicolas78
источник
Это наиболее разборчивое и понятное объяснение. Больше голосов, пожалуйста.
Альгорини,
12

Сделай интерфейс. У Java нет множественного наследования.

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

slandau
источник
9
ауу почему понизить? Я не был злым, я просто думаю, что он мог позволить себе немного почитать и подумать о проблеме самостоятельно, прежде чем мы построим его уроки для него
slandau
6

Java не поддерживает множественное наследование, но вы можете попробовать реализовать два или более интерфейса.


источник
4

Да. Сландау прав. Java не позволяет расширяться из нескольких классов.

То, что вы хотите, это, вероятно, public class Main extends ListActivity implements ControlMenu . Я предполагаю, что вы пытаетесь составить список.

Надеюсь, это поможет.

whirlwin
источник
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неизвестны, поэтому я предполагаю, что они не являются SDK-классами. Так что это не работает для меня (и, следовательно, этот ответ показывает ошибки). Что такое ParallaxController? Это специфическая зависимость? Пожалуйста, уточните
Зоя
1

Создатели Java решили, что проблемы множественного наследования перевешивают преимущества, поэтому они не включали множественное наследование. Вы можете прочитать об одной из самых больших проблем множественного наследования (проблема двойного ромба) здесь .

Двумя наиболее похожими концепциями являются реализация интерфейса и включение объектов других классов в члены текущего класса. Использование методов по умолчанию в интерфейсах почти такое же, как множественное наследование, однако считается плохой практикой использовать интерфейс только с методами по умолчанию.

Пика Волшебник китов
источник
0

Вы не можете сделать множественное наследование в Java. рассмотреть возможность использования интерфейсов:

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

или внутренние классы:

class Outer {
    class Inner1 extends Class1 {}
    class Inner2 extends Class2 {}
}

источник