Java não permite herança múltipla, mas permite implementar várias interfaces. Por quê?
Java não permite herança múltipla, mas permite implementar várias interfaces. Por quê?
Respostas:
Como as interfaces especificam apenas o que a classe está fazendo, não como está fazendo.
O problema da herança múltipla é que duas classes podem definir maneiras diferentes de fazer a mesma coisa, e a subclasse não pode escolher qual escolher.
Um dos meus instrutores da faculdade me explicou da seguinte maneira:
Suponha que eu tenha uma classe, que é uma torradeira, e outra classe, que é a NuclearBomb. Ambos podem ter uma configuração de "escuridão". Ambos têm um método on (). (Um está desativado (), o outro não.) Se eu quiser criar uma classe que seja uma subclasse de ambos ... como você pode ver, esse é um problema que pode realmente explodir na minha cara aqui .
Portanto, um dos principais problemas é que, se você tiver duas classes principais, elas podem ter implementações diferentes do mesmo recurso - ou possivelmente dois recursos diferentes com o mesmo nome, como no exemplo do meu instrutor. Então você tem que lidar com a decisão de qual delas sua subclasse vai usar. Existem maneiras de lidar com isso, certamente - o C ++ faz isso -, mas os designers de Java acharam que isso tornaria as coisas muito complicadas.
Com uma interface, porém, você está descrevendo algo que a classe é capaz de fazer, em vez de emprestar o método de outra classe para fazer alguma coisa. É muito menos provável que várias interfaces causem conflitos complicados que precisam ser resolvidos do que várias classes-pai.
Como a herança é usada em excesso, mesmo quando você não pode dizer "ei, esse método parece útil, estenderei essa classe também".
public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter,
AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...
A resposta desta pergunta está no trabalho interno do compilador java (encadeamento de construtor). Se vemos o funcionamento interno do compilador java:
public class Bank {
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank{
public void printBankBalance(){
System.out.println("20k");
}
}
Depois de compilar esta aparência:
public class Bank {
public Bank(){
super();
}
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank {
SBI(){
super();
}
public void printBankBalance(){
System.out.println("20k");
}
}
quando estendemos a classe e criamos um objeto, uma cadeia de construtores será executada até a Object
classe.
O código acima funcionará bem. mas se tivermos outra classe chamada Car
que se estende Bank
e uma classe híbrida (herança múltipla) chamada SBICar
:
class Car extends Bank {
Car() {
super();
}
public void run(){
System.out.println("99Km/h");
}
}
class SBICar extends Bank, Car {
SBICar() {
super(); //NOTE: compile time ambiguity.
}
public void run() {
System.out.println("99Km/h");
}
public void printBankBalance(){
System.out.println("20k");
}
}
Nesse caso, o SBICar falhará ao criar a cadeia de construtores ( ambiguidade do tempo de compilação ).
Para interfaces, isso é permitido porque não podemos criar um objeto.
Para novos conceitos default
e static
métodos, por favor, consulte o padrão na interface .
Espero que isso resolva sua consulta. Obrigado.
A implementação de múltiplas interfaces é muito útil e não causa muitos problemas para implementadores de linguagem nem programadores. Então é permitido. A herança múltipla, embora útil, pode causar sérios problemas aos usuários (temido diamante da morte ). E a maioria das coisas que você faz com herança múltipla também pode ser feita por composição ou usando classes internas. Portanto, a herança múltipla é proibida por trazer mais problemas do que ganhos.
ToyotaCar
e HybridCar
ambos derivassem Car
e substituíssemCar.Drive
, e se PriusCar
herdassem ambos, mas não substituíssemDrive
, o sistema não teria como identificar o que o virtual Car.Drive
deveria fazer. As interfaces evitam esse problema, evitando a condição em itálico acima.
void UseCar(Car &foo)
; não se pode esperar que inclua desambiguação entre ToyotaCar::Drive
e HybridCar::Drive
(já que muitas vezes nem deve saber nem se importar que esses outros tipos existam ). Uma linguagem pode, como o C ++, exigir que o código que ToyotaCar &myCar
deseja transmiti-lo UseCar
seja primeiro convertido para um HybridCar
ou ToyotaCar
, mas desde ((Car) (HybridCar) myCar) .Drive` e ((Car)(ToyotaCar)myCar).Drive
faria coisas diferentes, isso implicaria que os upcasts não preservavam a identidade.
Você pode encontrar respostas precisas para esta consulta na página de documentação da Oracle sobre herança múltipla
Herança múltipla de estado: capacidade de herdar campos de várias classes
Uma razão pela qual a linguagem de programação Java não permite que você estenda mais de uma classe é evitar os problemas de herança múltipla de estado, que é a capacidade de herdar campos de várias classes
Se herança múltipla for permitida e Quando você criar um objeto instanciando essa classe, esse objeto herdará campos de todas as superclasses da classe. Isso causará dois problemas.
Herança múltipla de implementação: capacidade de herdar definições de métodos de várias classes
Problemas com essa abordagem: nome conflic ts e ambiguidade . Se uma subclasse e uma superclasse contiverem o mesmo nome de método (e assinatura), o compilador não poderá determinar qual versão chamar.
Mas o java suporta esse tipo de herança múltipla com métodos padrão , que foram introduzidos desde o lançamento do Java 8. O compilador Java fornece algumas regras para determinar qual método padrão uma determinada classe usa.
Consulte a publicação SE abaixo para obter mais detalhes sobre como resolver o problema do diamante:
Quais são as diferenças entre classes abstratas e interfaces no Java 8?
Herança múltipla do tipo: capacidade de uma classe implementar mais de uma interface.
Como a interface não contém campos mutáveis, você não precisa se preocupar com problemas que resultam da herança múltipla de estado aqui.
Diz-se que o estado dos objetos é referido com relação aos campos nele e se tornaria ambíguo se muitas classes fossem herdadas. Aqui está o link
http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html
Java suporta herança múltipla apenas através de interfaces. Uma classe pode implementar qualquer número de interfaces, mas pode estender apenas uma classe.
A herança múltipla não é suportada porque leva a um problema mortal de diamante. No entanto, ele pode ser resolvido, mas leva a um sistema complexo, de modo que a herança múltipla foi descartada pelos fundadores de Java.
Em um white paper intitulado “Java: uma visão geral”, de James Gosling, em fevereiro de 1995 ( link ), dá uma idéia de por que a herança múltipla não é suportada em Java.
De acordo com Gosling:
"O JAVA omite muitos recursos confusos e mal utilizados do C ++ que, em nossa experiência, trazem mais sofrimento do que benefícios. Isso consiste principalmente em sobrecarga do operador (embora exista sobrecarga de método), herança múltipla e coerções automáticas extensas".
Pelo mesmo motivo, o C # não permite herança múltipla, mas permite implementar várias interfaces.
A lição aprendida com C ++ com herança múltipla foi que ela levou a mais problemas do que valia a pena.
Uma interface é um contrato do que sua classe precisa implementar. Você não ganha nenhuma funcionalidade da interface. A herança permite herdar a funcionalidade de uma classe pai (e na herança múltipla, que pode ser extremamente confusa).
A permissão de várias interfaces permite que você use Design Patterns (como o Adapter) para resolver os mesmos tipos de problemas que você pode resolver usando herança múltipla, mas de uma maneira muito mais confiável e previsível.
D1
e D2
ambos herdam de B
, e cada um substitui uma função f
, e se obj
é uma instância de um tipo S
que herda de ambos D1
e D2
mas não substitui f
, a conversão de uma referência S
a D1
deve produzir algo que f
usa a D1
substituição e a conversão de B
não deve mude isso. Da mesma forma, converter uma referência S
em D2
deve produzir algo cujo f
uso D2
substitua, e converter em B
não deve mudar isso. Se um idioma não precisou permitir a adição de membros virtuais ...
Como este tópico não está fechado, postarei esta resposta, espero que ajude alguém a entender por que o java não permite herança múltipla.
Considere a seguinte classe:
public class Abc{
public void doSomething(){
}
}
Nesse caso a classe Abc não estende nada né? Não tão rápido, essa classe implícita estende a classe Object, classe base que permite que tudo funcione em java. Tudo é um objeto.
Se você tentar usar a classe acima, você verá que o seu IDE permitem que você use métodos como: equals(Object o)
, toString()
, etc, mas você não declarou esses métodos, eles vieram da classe baseObject
Você poderia tentar:
public class Abc extends String{
public void doSomething(){
}
}
Isso é bom, porque sua classe não será estendida implícita, Object
mas será estendida String
porque você a disse. Considere a seguinte alteração:
public class Abc{
public void doSomething(){
}
@Override
public String toString(){
return "hello";
}
}
Agora sua classe sempre retornará "olá" se você chamar toString ().
Agora imagine a seguinte classe:
public class Flyer{
public void makeFly(){
}
}
public class Bird extends Abc, Flyer{
public void doAnotherThing(){
}
}
Novamente, a classe Flyer
implícita estende o Object que possui o método toString()
, qualquer classe terá esse método, pois todos se estendem Object
indiretamente; portanto, se você chamar toString()
de Bird
, qual toString()
java teria que usar? De Abc
ou Flyer
? Isso acontecerá com qualquer classe que tentar estender duas ou mais classes. Para evitar esse tipo de "colisão de método", eles criaram a idéia de interface . Basicamente, você pode considerá-los uma classe abstrata que não estende Objeto indiretamente . Por serem abstratos , terão que ser implementados por uma classe, que é um objeto (você não pode instanciar uma interface sozinha, ela deve ser implementada por uma classe); portanto, tudo continuará funcionando bem.
Para diferenciar as classes das interfaces, a palavra-chave implementa foi reservada apenas para interfaces.
Você pode implementar qualquer interface que desejar na mesma classe, uma vez que ela não estende nada por padrão (mas você pode criar uma interface que estende outra interface, mas, novamente, a interface "pai" não estende Objeto "), portanto, uma interface é apenas uma interface e eles não sofrerão com " colisões de assinatura de métodos ", se o compilador enviar um aviso para você e você apenas precisará alterar a assinatura do método para corrigi-la (assinatura = nome do método + parâmetros + tipo de retorno) .
public interface Flyer{
public void makeFly(); // <- method without implementation
}
public class Bird extends Abc implements Flyer{
public void doAnotherThing(){
}
@Override
public void makeFly(){ // <- implementation of Flyer interface
}
// Flyer does not have toString() method or any method from class Object,
// no method signature collision will happen here
}
Porque uma interface é apenas um contrato. E uma classe é realmente um contêiner para dados.
Por exemplo, duas classes A, B com o mesmo método m1 (). E a classe C estende ambos A, B.
class C extends A, B // for explaining purpose.
Agora, a classe C pesquisará a definição de m1. Primeiro, ele pesquisará na classe se não encontrar, depois verificará a classe dos pais. Ambos A, B com a definição Então aqui ocorre a ambiguidade que definição deve escolher. Então, o JAVA NÃO SUPORTA MÚLTIPLAS HERANÇA.
Java não suporta herança múltipla por dois motivos:
Object
classe. Quando herda de mais de uma superclasse, a subclasse obtém a ambiguidade de adquirir a propriedade da classe Object.super()
para chamar o construtor da classe supper. Se a turma tiver mais de uma super turma, ela ficará confusa.Portanto, quando uma classe se estende de mais de uma superclasse, obtemos um erro de tempo de compilação.
Tomemos, por exemplo, o caso em que a Classe A possui um método getSomething e a classe B possui um método getSomething e a classe C estende A e B. O que aconteceria se alguém chamasse C.getSomething? Não há como determinar qual método chamar.
As interfaces basicamente apenas especificam quais métodos uma classe de implementação precisa conter. Uma classe que implementa várias interfaces significa apenas que a classe precisa implementar os métodos de todas essas interfaces. O Whci não levaria a nenhum problema, conforme descrito acima.
Considere um cenário em que Teste1, Teste2 e Teste3 são três classes. A classe Test3 herda as classes Test2 e Test1. Se as classes Test1 e Test2 tiverem o mesmo método e você o chamar de objeto de classe filho, haverá ambiguidade para chamar o método da classe Test1 ou Test2, mas não haverá ambiguidade para a interface, pois na interface não há implementação.
Java não suporta herança múltipla, caminhos múltiplos e herança híbrida devido a um problema de ambiguidade:
Scenario for multiple inheritance: Let us take class A , class B , class C. class A has alphabet(); method , class B has also alphabet(); method. Now class C extends A, B and we are creating object to the subclass i.e., class C , so C ob = new C(); Then if you want call those methods ob.alphabet(); which class method takes ? is class A method or class B method ? So in the JVM level ambiguity problem occurred. Thus Java does not support multiple inheritance.
Link de referência: https://plus.google.com/u/0/communities/102217496457095083679
De maneira simples, como todos sabemos, podemos herdar (estender) uma classe, mas podemos implementar tantas interfaces. Isso ocorre porque nas interfaces não fornecemos uma implementação, apenas digamos a funcionalidade. suponha que java possa estender tantas classes e que tenham os mesmos métodos .. neste ponto, se tentarmos chamar o método super class na subclasse que método supõe executar ??, o compilador se confunde exemplo: - tente várias extensões, mas em interfaces esses métodos não têm corpos, devemos implementar aqueles na subclasse .. tente vários implementos para não se preocupar ..
* Esta é uma resposta simples, pois sou iniciante em Java *
Considere existem três classes X
, Y
e Z
.
Então, estamos herdando como X extends Y, Z
And both Y
e estamos Z
tendo um método alphabet()
com o mesmo tipo de retorno e argumentos. Este método alphabet()
no Y
diz para exibir o primeiro alfabeto e o método do alfabeto no Z
diz exibir o último alfabeto . Então aqui vem a ambiguidade quando alphabet()
é chamado por X
. Se diz para exibir o primeiro ou o último alfabeto ?? Portanto, o java não suporta herança múltipla. No caso de interfaces, considere Y
e Z
como interfaces. Portanto, ambos conterão a declaração do método, alphabet()
mas não a definição. Ele não diz se deve exibir o primeiro alfabeto ou o último alfabeto ou qualquer outra coisa, mas apenas declarará um métodoalphabet()
. Portanto, não há razão para aumentar a ambiguidade. Podemos definir o método com o que quisermos dentro da classe X
.
Assim, em uma palavra, na definição de Interfaces é feita após a implementação, para que não haja confusão.