Porque você só pode herdar uma turma. Se você tem duas interfaces cujas implementações são complexas o suficiente para que você precise de uma classe base abstrata, essas duas interfaces são mutuamente exclusivas na prática.
A alternativa é converter essas classes base abstratas em uma coleção de métodos estáticos e transformar todos os campos em argumentos. Isso permitiria que qualquer implementador da interface chamasse os métodos estáticos e obtivesse a funcionalidade, mas é uma grande quantidade de clichês em uma linguagem que já é muito detalhada.
Como um exemplo motivador de por que ser capaz de fornecer implementações em interfaces pode ser útil, considere esta interface do Stack:
public interface Stack<T> {
boolean isEmpty();
T pop() throws EmptyException;
}
Não há como garantir que quando alguém implementa a interface, pop
lançará uma exceção se a pilha estiver vazia. Poderíamos aplicar essa regra separando pop
em dois métodos: um método public final
que impõe o contrato e um método protected abstract
que realiza o popping real.
public abstract class Stack<T> {
public abstract boolean isEmpty();
protected abstract T pop_implementation();
public final T pop() throws EmptyException {
if (isEmpty()) {
throw new EmptyException();
else {
return pop_implementation();
}
}
}
Não apenas garantimos que todas as implementações respeitem o contrato, mas também as liberamos de verificar se a pilha está vazia e lançando a exceção. É uma grande vitória! ... exceto pelo fato de termos que mudar a interface para uma classe abstrata. Em uma linguagem com herança única, é uma grande perda de flexibilidade. Isso torna suas interfaces em potencial mutuamente exclusivas. Ser capaz de fornecer implementações que dependem apenas dos próprios métodos de interface resolveria o problema.
Não tenho certeza se a abordagem do Java 8 para adicionar métodos a interfaces permite adicionar métodos finais ou métodos abstratos protegidos, mas eu sei a linguagem D permite e fornece suporte nativo para Design por contrato . Não há perigo nesta técnica, pois pop
é final, portanto, nenhuma classe de implementação pode substituí-la.
Quanto às implementações padrão de métodos substituíveis, suponho que quaisquer implementações padrão incluídas nas APIs Java dependam apenas do contrato da interface à qual foram adicionadas, portanto, qualquer classe que implemente corretamente a interface também se comportará corretamente com as implementações padrão .
Além disso,
There's virtually no difference between an interface and an abstract class (other than multiple inheritance). In fact you can emulate a regular class with an interface.
Isso não é bem verdade, pois você não pode declarar campos em uma interface. Qualquer método que você escreva em uma interface não pode confiar em detalhes de implementação.
Como um exemplo em favor de métodos estáticos em interfaces, considere classes de utilitários como Coleções na API Java. Essa classe existe apenas porque esses métodos estáticos não podem ser declarados em suas respectivas interfaces. O Collections.unmodifiableList
também poderia ter sido declarado na interface List
, e seria mais fácil encontrá-lo.