Estendendo de duas classes

150

Como posso fazer isso:

public class Main extends ListActivity , ControlMenu 

Além disso, gostaria de saber que, se essa abordagem for aceitável, criei os menus na classe ControlMenu e estarei estendendo o restante das atividades.

umar
fonte
4
Você não pode estender duas ou mais aulas ao mesmo tempo. Herança múltipla não é permitida em java.
Yogma

Respostas:

156

Você pode estender apenas uma única classe. E implemente interfaces de várias fontes.

A extensão de várias classes não está disponível. A única solução em que consigo pensar é não herdar nenhuma das classes, mas sim ter uma variável interna de cada classe e fazer mais proxy, redirecionando as solicitações ao seu objeto para o objeto que você deseja que elas acessem.

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

esta é a melhor solução que eu encontrei. Você pode obter a funcionalidade de ambas as classes e ainda ser realmente apenas de um tipo de classe.

A desvantagem é que você não pode se encaixar no molde da classe Interna usando um molde.

The Lazy Coder
fonte
2
você estava mais rápido :) Vou deixar a minha resposta como alguns caminhadas abstrato para comparar com o seu exemplo concreto;)
Nicolas78
1
Essa é uma alternativa muito boa e oferece muito mais flexibilidade no futuro.
David Souther
1
Veja a solução @SCB para obter mais soluções OOP
idish 27/05
Eu poderia usar um exemplo mais preciso aqui. Não tenho certeza se entendi.
Neo42
54

Por que não usar uma classe interna (aninhamento)

class A extends B {
    private class C extends D {
        //Classes A , B , C , D accessible here 
    }
}
Ifte
fonte
4
Abordagem interessante, o que os especialistas pensam dessa técnica? Eu gostaria de cavar.
TechNyquist
1
Tudo bem com as convenções?
obtido em 25/07/2014
2
Não foi possível obter a classe interna para trabalhar em um Fragment. Minha atividade deve se estender Fragment, o que significa que eu absolutamente preciso getView(), o que não funcionará se estiver dentro da classe interna, e o código é o local de onde eu preciso usar o código ListActivity, então não posso estender duas vezes OU faça uma classe interna neste exemplo.
Azurespot 13/03/2015
Esta é a melhor solução para estender as classes abstratas nas quais você precisa acessar as variáveis ​​da classe que está implementando.
Tak3shi
45

Como todo mundo já disse. Não, você não pode. No entanto, mesmo que as pessoas tenham dito muitas vezes ao longo dos anos que você deve usar várias interfaces, elas realmente não entenderam como. Espero que isso ajude.

Digamos que você tenha class Fooe class Barque ambos desejam tentar estender-se para a class FooBar. Obviamente, como você disse, você não pode fazer:

public class FooBar extends Foo, Bar

As pessoas já se debruçaram sobre as razões disso até certo ponto. Em vez disso, escreva interfacespara ambos Fooe Barcubra todos os seus métodos públicos. Por exemplo

public interface FooInterface {

    public void methodA();

    public int methodB();

    //...
} 

public interface BarInterface {

    public int methodC(int i);

    //...
}

E agora faça Fooe Barimplemente as interfaces relativas:

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

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

Agora, com class FooBar, você pode implementar tanto FooInterfacee BarInterfaceao mesmo tempo manter um Fooe Barobjeto e apenas passando os métodos em linha reta através:

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

    //...

}

O bônus para esse método é que o FooBarobjeto se encaixa nos moldes de ambos FooInterfacee BarInterface. Isso significa que está perfeitamente bem:

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

Espero que isso esclareça como usar interfaces em vez de várias extensões. Mesmo se eu estiver atrasado alguns anos.

SCB
fonte
6
esta é a melhor resposta
user3290180
Esta é uma resposta muito boa, no entanto, vejo alguns problemas que precisariam ser abordados com mais detalhes. A primeira extensão de duas classes existentes seria um pouco mais problemática e haveria vários obstáculos extras a serem enfrentados. Segundo, se a interface Foo e Bar tiverem as mesmas funções, você precisará ter uma ordem de precedência. Estender explicitamente sua classe o forçaria a tomar essas decisões com antecedência. Ainda assim, excelente opção :) +1
The Lazy Coder
E se tivermos que criar novas classes "frequentemente" e fazer com que cada uma dessas classes implemente ambas as interfaces? Então, teríamos que repetir essas implementações padrão em cada classe. Existe uma maneira melhor de fazer uma classe "implementar" dois conjuntos de comportamentos?
MasterJoe2
1
@ MasterJoe2 Para ser sincero, não uso muito o Java há algum tempo (parei na época em que escrevi esta resposta). Uma das razões pelas quais evito isso hoje em dia é o próprio problema que você levanta. Um palpite para uma direção que você poderia investigar é escrever uma classe abstrata que implemente as duas interfaces e estenda isso. No entanto, não tenho idéia se o Java é válido e sinto que você acabará com o mesmo problema original quando quiser fazer alterações na classe de implementação no futuro. Desculpe, não posso ajudar mais.
SCB
37

Você vai querer usar interfaces. Geralmente, a herança múltipla é ruim por causa do problema do diamante:

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 ++ e outros têm algumas maneiras de resolver isso, por exemplo

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

mas Java usa apenas interfaces.

Os Java Trails têm uma ótima introdução às interfaces: http://download.oracle.com/javase/tutorial/java/concepts/interface.html Você provavelmente desejará seguir isso antes de mergulhar nas nuances da API do Android.

David Souther
fonte
24
Eu nunca entendi por que o problema do diamante é realmente um problema que impede a herança múltipla. Por que o compilador não pode simplesmente reclamar se existem métodos conflitantes com o mesmo nome?
Pete
1
Para compiladores suficientemente inteligentes, não é. É possível resolvê-lo no nível do compilador e, de fato, o C ++ o faz virtual class. Isso acontece com muitos avisos e advertências, tanto para o compilador quanto para o desenvolvedor.
David Souther
1
Que tal os mesmos métodos padrão em duas interfaces? Esse é outro exemplo do problema do diamante, com o qual o java pode lidar.
Lajos Meszaros 25/02
1
@ MészárosLajos Mas você não chama superde em um método herdado. Bem, você pode, mas precisa especificar o método de interface a ser chamado (e deve usar a palavra-chave defaultna implementação da interface) . Um exemplo é: MyIFace.super.foo()onde MyIFace é uma interface. Como você pode ver, o método de interface a ser executado é definido e evita completamente o problema do diamante. Se você estender MyClass1e MyClass2, ambas as classes tiverem uma foo()chamada e, super.foo()então o compilador será lançado pelo Problema de Diamante.
precisa saber é o seguinte
Você não pode retornar "bar"ou "baz"com o tipo de método de void. De qualquer forma, boa explicação xD
xdevs23
22

Sim, como todo mundo escreveu, você não pode fazer herança múltipla em Java. Se você tem duas classes das quais gostaria de usar o código, normalmente apenas subclasse uma (digamos classe A). Na aula B, você abstrai os métodos importantes para uma interface BInterface(nome feio, mas você entende) e depois diz Main extends A implements BInterface. Por dentro, você pode instanciar um objeto de classe Be implementar todos os métodos BInterfacechamando as funções correspondentes de B.

Isso altera o relacionamento "é-a" para um relacionamento "tem-a", pois o seu Mainagora é um A, mas possui um B. Dependendo do seu caso de uso, você pode até fazer essa mudança explícita, removendo o BInterfacedo seu Aclasse e sim fornecer um método para acessar o objeto B diretamente.

Nicolas78
fonte
Essa é a explicação mais legível e fácil de entender. Mais votos positivos, por favor.
Algorini
12

Faça uma interface. Java não tem herança múltipla.

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

slandau
fonte
9
aww por que o voto negativo? Eu não estava sendo cruel, eu só acho que ele poderia dar ao luxo de fazer algumas leituras e pensar sobre o problema por conta própria antes de nós construir suas aulas para ele
slandau
6

Java não suporta herança múltipla, mas você pode tentar implementar duas ou mais interfaces.


fonte
4

Sim. Slandau está certo. Java não permite a extensão de várias classes.

O que você quer é provavelmente public class Main extends ListActivity implements ControlMenu. Eu estou supondo que você está tentando fazer uma lista.

Espero que ajude.

turbilhão
fonte
3

Como outra alternativa, talvez você possa usar uma interface com a implementação padrão de um método. Isso depende, é claro, do que você deseja fazer.

Por exemplo, você pode criar uma classe abstrata e uma interface:

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

Então, depois disso, você pode estender e implementar as duas classes e usar os dois métodos.

public class extends FatherClass implements InterfaceWithDefaultsMethods {

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

Espero que isso ajude você...

impressões digitais
fonte
2

A extensão de várias classes não é permitida no java .. para impedir a morte do diamante mortal !

akkig
fonte
2

é possível

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

//blah
}
Jonathan
fonte
Parallaxore ParallaxControllersão desconhecidos, então suponho que não sejam classes SDK. Portanto, isso não funciona para mim (e, portanto, esta resposta mostra erros). O que é o ParallaxController? Essa é uma dependência específica? Por favor, elabore
Zoe
1

Os criadores de java decidiram que os problemas de herança múltipla superam os benefícios, portanto, não incluíram herança múltipla. Você pode ler sobre um dos maiores problemas de herança múltipla (o problema do diamante duplo) aqui .

Os dois conceitos mais semelhantes são a implementação da interface e a inclusão de objetos de outras classes como membros da classe atual. O uso de métodos padrão em interfaces é quase exatamente o mesmo que herança múltipla, no entanto, é considerado uma prática ruim usar uma interface apenas com métodos padrão.

Pika, o Mago das Baleias
fonte
0

você não pode fazer herança múltipla em java. considere usar interfaces:

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

ou classes internas:

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

fonte