Подовження від двох класів


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

це найкраще рішення, яке я придумав. Ви можете отримати функціонал з обох класів і все-таки лише фактично одного класу.

Недолік полягає в тому, що ви не можете вписатись у форму Mould of Internal, використовуючи касти.


2
ви були швидшими :) Я відповіду на це, як порівняння з вашим конкретним прикладом, я залишу;)
Nicolas78

1
Це дуже приємна альтернатива і забезпечує набагато більше гнучкості в майбутньому.
Девід Сутер

1
Дивіться рішення @SCB для більш детального рішення OOP
ідіш

Я міг би використати тут більш точний приклад. Не впевнений, що розумію.
Neo42

54

Чому б не використовувати внутрішній клас (вкладення)

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

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

Сподіваємось, це пояснює, як використовувати інтерфейси замість кількох розширень. Навіть якщо я спізнююсь на кілька років.


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 Ви, ймовірно, захочете дотримуватися цього, перш ніж зануритися в нюанси в Android API.


24
Я ніколи не розумів, чому проблема з алмазами насправді є проблемою, яка перешкоджає багатократному успадкуванню. Чому компілятор не може поскаржитися, якщо існують суперечливі методи з тим самим іменем?
піт

1
Для досить інтелектуальних компіляторів це не так. Вирішити це на рівні компілятора можливо, і справді C ++ робить це за допомогою virtual class. Це стосується багатьох попереджень та застережень як для компілятора, так і для розробника.
Девід Сутер

1
Як щодо однакових методів за замовчуванням у двох інтерфейсах? Це ще один приклад проблеми з алмазами, з якою може впоратися Java.
Лайош Мессарос

1
@ MészárosLajos Але ви не зателефонували superза методом успадкування. Ну, ви можете, але для виклику потрібно вказати метод інтерфейсу (і він повинен використовувати ключове слово defaultпри реалізації інтерфейсу) . Приклад: MyIFace.super.foo()де MyIFace є інтерфейсом. Як ви бачите, метод інтерфейсу для виконання визначений і уникає проблеми Diamond повністю. Якщо ви продовжите MyClass1і MyClass2, обидва класи мають a foo(), і виклик, super.foo()тоді компілятор викидається Diamond Problem.
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.


Це найбільш розбірливе і легке для розуміння пояснення. Будь ласка, більше оновлень, будь ласка.
Алгоріні

12

Зробіть інтерфейс. Java не має багаторазового успадкування.

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


9
aww навіщо downvote? Я не маю на увазі, я просто думаю, що він міг би дозволити собі почитати і подумати над проблемою спочатку, перш ніж ми побудуємо для нього заняття
slandau

6

Java не підтримує багатократне успадкування, але ви можете спробувати реалізувати два та більше інтерфейсу.


4

Так. slandau правильно. Java не дозволяє поширюватися на кілька класів.

Те, що ти хочеш, мабуть 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невідомі, тому я припускаю, що вони не є 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 {}
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.