Se um tipo implementa duas interfaces, e cada interface
uma define um método que possui assinatura idêntica, na verdade, existe apenas um método e elas não são distinguíveis. Se, por exemplo, os dois métodos tiverem tipos de retorno conflitantes, será um erro de compilação. Essa é a regra geral de herança, substituição de método, ocultação e declaração, e se aplica também a possíveis conflitos não apenas entre 2 interface
métodos herdados , mas também um método interface
e um super class
, ou mesmo apenas conflitos devido ao apagamento de tipo de genéricos.
Exemplo de compatibilidade
Aqui está um exemplo em que você tem um interface Gift
, que tem um present()
método (como em apresentar presentes), e também um interface Guest
, que também tem um present()
método (como em, o convidado está presente e não está ausente).
Presentable johnny
é a Gift
e a Guest
.
public class InterfaceTest {
interface Gift { void present(); }
interface Guest { void present(); }
interface Presentable extends Gift, Guest { }
public static void main(String[] args) {
Presentable johnny = new Presentable() {
@Override public void present() {
System.out.println("Heeeereee's Johnny!!!");
}
};
johnny.present(); // "Heeeereee's Johnny!!!"
((Gift) johnny).present(); // "Heeeereee's Johnny!!!"
((Guest) johnny).present(); // "Heeeereee's Johnny!!!"
Gift johnnyAsGift = (Gift) johnny;
johnnyAsGift.present(); // "Heeeereee's Johnny!!!"
Guest johnnyAsGuest = (Guest) johnny;
johnnyAsGuest.present(); // "Heeeereee's Johnny!!!"
}
}
O trecho acima compila e executa.
Observe que há apenas um @Override
necessário !!! . Isso ocorre Gift.present()
e Guest.present()
é " @Override
-equivalente" ( JLS 8.4.2 ).
Assim, johnny
só tem uma implementação de present()
, e não importa como você trata johnny
, seja como Gift
ou como Guest
, só há um método a ser chamado.
Exemplo de incompatibilidade
Aqui está um exemplo em que os dois métodos herdados NÃO são @Override
equivalentes:
public class InterfaceTest {
interface Gift { void present(); }
interface Guest { boolean present(); }
interface Presentable extends Gift, Guest { } // DOES NOT COMPILE!!!
// "types InterfaceTest.Guest and InterfaceTest.Gift are incompatible;
// both define present(), but with unrelated return types"
}
Isso reitera ainda que a herança de membros de um interface
deve obedecer à regra geral das declarações de membros. Aqui temos Gift
e Guest
definimos present()
com tipos de retorno incompatíveis: um void
o outro boolean
. Pelo mesmo motivo que você não pode um void present()
e um boolean present()
em um tipo, este exemplo resulta em um erro de compilação.
Resumo
Você pode herdar métodos que sejam @Override
equivalentes, sujeitos aos requisitos usuais de substituição e ocultação de métodos. Como são @Override
equivalentes, efetivamente existe apenas um método para implementar e, portanto, não há nada para distinguir / selecionar.
O compilador não precisa identificar qual método é para qual interface, porque uma vez que eles são considerados @Override
equivalentes, eles são o mesmo método.
Resolver possíveis incompatibilidades pode ser uma tarefa complicada, mas isso é outra questão.
Referências
default
métodos em Java 8.Foo
eBar
. Basicamente, sua classe implementa uma das interfaces, digamosFoo
, e fornece umBar asBar()
método para retornar uma classe interna que implementa a segundaBar
interface. Não é perfeito, pois sua classe não é "um bar", mas pode ser útil em algumas circunstâncias.Isso foi marcado como uma duplicata para esta pergunta /programming/24401064/understanding-and-solving-the-diamond-problems-in-java
Você precisa do Java 8 para obter um problema de herança múltipla, mas ainda assim não é um problema diário.
Como comenta JB Nizet, você pode corrigir isso, minha substituição.
No entanto, você não tem problemas com
fonte
hi()
(para corrigir a ambiguidade). Por exemplo, através da implementação lo comoA.super.hi()
escolher implementá-lo da mesma maneira como A.No que diz respeito ao compilador, esses dois métodos são idênticos. Haverá uma implementação de ambos.
Isso não é um problema se os dois métodos forem efetivamente idênticos, pois devem ter a mesma implementação. Se eles forem contratualmente diferentes (conforme a documentação de cada interface), você estará com problemas.
fonte
Não há nada para identificar. As interfaces apenas proíbem o nome e a assinatura de um método. Se ambas as interfaces tiverem um método exatamente com o mesmo nome e assinatura, a classe de implementação poderá implementar os dois métodos de interface com um único método concreto.
No entanto, se os contratos semânticos do método de duas interfaces estiverem em contradição, você praticamente perderá; você não pode implementar as duas interfaces em uma única classe então.
fonte
Tente implementar a interface como anônima.
fonte
Como na interface, estamos apenas declarando métodos, a classe concreta que implementa essas duas interfaces entende que existe apenas um método (como você descreveu, ambos têm o mesmo nome no tipo de retorno). portanto, não deve haver problema. Você poderá definir esse método na classe concreta.
Mas quando duas interfaces têm um método com o mesmo nome, mas com um tipo de retorno diferente e você implementa dois métodos na classe concreta:
Por favor, veja o código abaixo:
quando o compilador obtém o método "public void print ()", ele procura pela primeira vez na InterfaceA e o obtém. Mas, ainda assim, gera um erro de tempo de compilação que o tipo de retorno não é compatível com o método da InterfaceB.
Por isso, dá errado para o compilador.
Dessa forma, você não poderá implementar duas interfaces com um método com o mesmo nome, mas com um tipo de retorno diferente.
fonte
Bem, se ambos são iguais, não importa. Ele implementa os dois com um único método concreto por método de interface.
fonte