Quando usar: método padrão da interface Java 8+, vs. método abstrato

540

O Java 8 permite a implementação padrão de métodos em interfaces chamadas Métodos Padrão .

Estou confuso entre quando eu usaria esse tipo de interface default method, em vez de um abstract class(com abstract method(s)).

Então, quando a interface com os métodos padrão deve ser usada e quando deve ser usada uma classe abstrata (com método (s) abstrato)? As classes abstratas ainda são úteis nesse cenário?

Narendra Pathai
fonte
38
Talvez você ainda não possa ter campos, métodos particulares etc. nas interfaces, enquanto na classe abstrata?
Sp00m
2
Eu estava pensando sobre esse tópico antes, agora estou claro.Graças a @Narendra Pathai. Gostaria de adicionar um link de outro tópico solicitado por você sobre o mesmo tópico, pois essas são minhas dúvidas. stackoverflow.com/questions/19998309/…
Ashutosh Ranjan
Você pode encontrar um bom post sobre este aqui: blog.codefx.org/java/everything-about-default-methods
Fabri Pautasso
Às vezes, você ainda pode codificar uma classe base como uma interface, mesmo que a classe base tenha estado. É que a interface precisa definir setters e getters para o estado e as classes concretas precisam implementá-los e definir o campo. Uma restrição é que, em uma classe abstrata, a propriedade do bean pode ser privada ou protegida. Nas interfaces, apenas existem métodos públicos. Portanto, um motivo para você usar uma classe base abstrata é se suas classes têm uma propriedade que precisa ser privada ou protegida.
DaBlick 13/08
@DaBlick Você não conseguiu resolver o problema de estado em uma interface via HashMap. Ex: se você deseja uma classe Foo que contém int a, b, String c. e você deseja que eles tenham estado, crie um HashMap </ * nome do objeto Foo * / String, / * mapa de campos * / Hashmap </ * campo específico do nome * / String, / * valor do campo * / Object >> map . Quando você deseja "instanciar" a classe teórica Foo, você tem o método instanciar (String nameOfFoo), que faz map.put (nameOfFoo, fields) em que fields é um HashMap <String, Object> fields.put ("a", new int ("5")); fields.put ("b", novo int ("6")); fields.put ("c", "blá"));
George Xavier

Respostas:

307

Há muito mais nas classes abstratas do que implementações de métodos padrão (como estado privado), mas a partir do Java 8, sempre que você tiver a opção de escolher, você deve usar o defaultmétodo defender (aka. ) Na interface.

A restrição no método padrão é que ele pode ser implementado apenas nos termos de chamadas para outros métodos de interface, sem referência ao estado de uma implementação específica. Portanto, o principal caso de uso são os métodos de nível superior e de conveniência.

O bom desse novo recurso é que, onde antes você era forçado a usar uma classe abstrata para os métodos de conveniência, restringindo o implementador a uma herança única, agora você pode ter um design realmente limpo, com apenas a interface e um mínimo de implementação esforço forçado ao programador.

A motivação original para introduzir defaultmétodos no Java 8 era o desejo de estender as interfaces do Collections Framework com métodos orientados a lambda sem interromper nenhuma implementação existente. Embora isso seja mais relevante para os autores das bibliotecas públicas, você também pode encontrar o mesmo recurso útil no seu projeto. Você tem um local centralizado para adicionar nova comodidade e não precisa confiar na aparência do restante da hierarquia de tipos.

Marko Topolnik
fonte
34
Por esse raciocínio, a próxima coisa que eles adicionariam são as declarações de método padrão. Ainda não tenho certeza disso, o recurso me parece mais um hack que está sendo exposto a todos por mau uso.
pantera
3
O único uso das Classes Abstratas na era Java 8 que posso ver é para definir campos não finais. Em Interfaces, os campos são, por padrão, finais; portanto, você não pode alterá-los depois de atribuídos.
Anuroop
7
@ Anuroop Não é apenas por padrão --- essa é a única opção. As interfaces não podem declarar o estado da instância, e é por isso que as classes abstratas estão aqui para ficar.
Marko Topolnik
2
@PhilipRego Os métodos abstratos não chamam nada porque não têm implementação. Os métodos implementados em uma classe podem acessar o estado da classe (variáveis ​​de instância). As interfaces não podem declará-las, portanto os métodos padrão não podem acessá-las. Eles precisam confiar na classe, fornecendo um método implementado que acessa o estado.
Marko Topolnik
2
Marko Topolnik, sua resposta está morta. Mas eu gostaria de recomendar uma atualização para sua resposta. Você pode adicionar que a beleza dos métodos padrão é que, se a interface adicionar novos métodos padrão, sua implementação anterior dessa interface não será interrompida. Isso não era verdade antes de Java 8.
hfontanez
125

Existem algumas diferenças técnicas. As classes abstratas ainda podem fazer mais em comparação com as interfaces Java 8:

  1. A classe abstrata pode ter um construtor.
  2. As aulas abstratas são mais estruturadas e podem conter um estado.

Conceitualmente, o principal objetivo dos métodos de defesa é uma compatibilidade com versões anteriores após a introdução de novos recursos (como funções lambda) no Java 8.

Vadym Vasyliev
fonte
20
Esta resposta está realmente correta e faz sentido, especialmente "Conceitualmente, o principal objetivo dos métodos de defesa é uma compatibilidade com versões anteriores"
Tentando
1
@Unknown desta página dá mais insight: docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Bernie
@UnKnown, basicamente permite adicionar métodos a uma interface e classes que implementam essa interface obtêm automaticamente essa funcionalidade.
LegendLength
3
Um ponto mais sutil sobre o ponto não. 2 acima sobre "pode ​​segurar estado é isto". As classes abstratas podem conter um estado que pode ser alterado posteriormente. As interfaces também podem conter estado, mas uma vez que um estado é designado após a criação da instância, o estado não pode ser alterado.
Anuroop
3
@ Anuroop Eu não descreveria os public static finalcampos de uma interface como "estado". A staticparte significa que eles não estão relacionados a uma instância específica. Eles são atribuídos na instanciação de classe , que não é a mesma que após a criação da instância .
Geronimo 22/12
65

Isso está sendo descrito neste artigo . Pense em forEachcoleções.

List<?> list = 
list.forEach(…);

O forEach ainda não foi declarado por java.util.Listnem a java.util.Collectioninterface. Uma solução óbvia seria apenas adicionar o novo método à interface existente e fornecer a implementação onde necessário no JDK. No entanto, uma vez publicado, é impossível adicionar métodos a uma interface sem interromper a implementação existente.

O benefício que os métodos padrão trazem é que agora é possível adicionar um novo método padrão à interface e não interromper as implementações.

Masudul
fonte
1
'é impossível adicionar métodos a uma interface sem interromper a implementação existente' - é?
Andrey Chaschev
26
@AndreyChaschev Se você adicionar um novo método à interface, todos os implementadores deverão implementar esse novo método. Portanto, ele quebra as implementações existentes.
Marko Topolnik
4
Obrigado @ MarkoTopolnik, perdi isso. Apenas para mencionar, há uma maneira de evitar isso parcialmente - apresentando esse método em uma implementação abstrata padrão. Para este exemplo, isso lançaria AbstractList::forEachum UnsupportedOperationException.
Andrey Chaschev
3
@AndreyChaschev Sim, essa era a maneira antiga (khm ... é a maneira atual :), com a deficiência de restringir o implementador à herança única da implementação abstrata fornecida.
Marko Topolnik
Não vou quebrar se acontecer que, com antecedência, todas as implementações incluíam esse método. O que é improvável, mas possível.
George Xavier
19

Estes dois são bem diferentes:

Os métodos padrão são adicionar funcionalidade externa às classes existentes sem alterar seu estado.

E classes abstratas são um tipo normal de herança, são classes normais que devem ser estendidas.

Andrey Chaschev
fonte
18

Conforme descrito neste artigo,

Classes abstratas versus interfaces em Java 8

Depois de introduzir o Método Padrão, parece que as interfaces e as classes abstratas são iguais. No entanto, eles ainda são conceito diferente no Java 8.

Classe abstrata pode definir construtor. Eles são mais estruturados e podem ter um estado associado a eles. Por outro lado, o método padrão pode ser implementado apenas nos termos da chamada de outros métodos de interface, sem referência ao estado de uma implementação específica. Portanto, ambos usam para finalidades diferentes e a escolha entre dois realmente depende do contexto do cenário.

Sufiyan Ghori
fonte
Eu acredito que a classe Abstract possui o Constructor, que pode ser definido diferentemente da Interface. No Java 8, eles também são diferentes devido a isso.
Hemanth Peela
1
por que uma classe abstrata tem um construtor se não pode ser instanciada?
George Xavier
Podemos chamar super () da classe filho, que chamará o construtor da classe abstrata. Isso afeta o estado da classe abstrata.
Sujay Mohan 24/09/19
14

Em relação à sua consulta de

Então, quando a interface com os métodos padrão deve ser usada e quando uma classe abstrata deve ser usada? As classes abstratas ainda são úteis nesse cenário?

documentação java fornece resposta perfeita.

Classes abstratas comparadas às interfaces:

Classes abstratas são semelhantes às interfaces. Você não pode instancia-los e eles podem conter uma mistura de métodos declarados com ou sem uma implementação.

No entanto, com classes abstratas, é possível declarar campos que não são estáticos e finais e definir métodos concretos públicos, protegidos e privados.

Com interfaces, todos os campos são automaticamente públicos, estáticos e finais, e todos os métodos que você declara ou define (como métodos padrão) são públicos. Além disso, você pode estender apenas uma classe, seja abstrata ou não, enquanto pode implementar qualquer número de interfaces.

Os casos de uso de cada um deles foram explicados abaixo na postagem do SE:

Qual é a diferença entre uma interface e uma classe abstrata?

As classes abstratas ainda são úteis nesse cenário?

Sim. Eles ainda são úteis. Eles podem conter métodos e atributos não estáticos e não finais ( protegidos, privados e públicos ), o que não é possível mesmo nas interfaces Java-8.

Ravindra babu
fonte
Agora interfaces têm métodos privados também howtodoinjava.com/java9/java9-private-interface-methods
valijon
13

Sempre que temos uma escolha entre classe abstrata e interface, devemos sempre (quase) preferir métodos padrão (também conhecidos como defensor ou extensões virtuais).

  1. Os métodos padrão encerraram o padrão clássico de interface e uma classe complementar que implementa a maioria ou todos os métodos nessa interface. Um exemplo é Collection and AbstractCollection. Agora devemos implementar os métodos na própria interface para fornecer a funcionalidade padrão. As classes que implementam a interface têm a opção de substituir os métodos ou herdar a implementação padrão.
  2. Outro uso importante dos métodos padrão é interface evolution. Suponha que eu tenha uma classe Ball como:

    public class Ball implements Collection { ... }

Agora, no Java 8, um novo recurso é introduzido. Podemos obter um fluxo usando o streammétodo adicionado à interface. Se streamnão fosse um método padrão, todas as implementações da Collectioninterface teriam sido interrompidas, pois não estariam implementando esse novo método. Adicionar um método não padrão a uma interface não é source-compatible.

Mas suponha que não recompilemos a classe e utilizemos um arquivo jar antigo que contenha essa classe Ball. A classe carregará bem sem esse método ausente, instâncias podem ser criadas e parece que tudo está funcionando bem. MAS se o programa invocar o streammétodo, por exemplo Ball, obteremos AbstractMethodError. Então, tornar o método padrão resolveu os dois problemas.

akhil_mittal
fonte
9

Os métodos padrão na interface Java permitem a evolução da interface .

Dada uma interface existente, se você deseja adicionar um método sem interromper a compatibilidade binária com versões mais antigas da interface, você tem duas opções disponíveis: adicionar um método padrão ou estático. De fato, qualquer método abstrato adicionado à interface teria que ser implementado pelas classes ou interfaces que implementam essa interface.

Um método estático é exclusivo para uma classe. Um método padrão é exclusivo para uma instância da classe.

Se você adicionar um método padrão a uma interface existente, as classes e interfaces que implementam essa interface não precisam implementá-lo. Eles podem

  • implementar o método padrão e substitui a implementação na interface implementada.
  • declare novamente o método (sem implementação) que o torna abstrato.
  • não faça nada (então o método padrão da interface implementada é simplesmente herdado).

Mais sobre o tópico aqui .

Kiriloff
fonte
7

Embora seja uma pergunta antiga, deixe-me dar minha opinião sobre isso também.

  1. classe abstrata: dentro da classe abstrata, podemos declarar variáveis ​​de instância, que são necessárias para a classe filho

    Interface: Dentro da interface, todas as variáveis ​​são sempre estáticas e finais públicas, não podemos declarar variáveis ​​de instância

  2. classe abstrata: a classe abstrata pode falar sobre o estado do objeto

    Interface: a interface nunca pode falar sobre o estado do objeto

  3. classe abstrata: Dentro da classe abstrata podemos declarar construtores

    Interface: Na interface interna, não podemos declarar construtores, pois o objetivo dos
    construtores é inicializar variáveis ​​de instância. Então, qual é a necessidade do construtor se não pudermos ter variáveis ​​de instância nas interfaces .

  4. classe abstrata: dentro da classe abstrata podemos declarar blocos estáticos e de instância

    Interface: As interfaces não podem ter blocos estáticos e de instância.

  5. classe abstrata: classe abstrata não pode se referir à expressão lambda

    Interfaces: interfaces com método abstrato único podem se referir à expressão lambda

  6. classe abstrata : dentro da classe abstrata, podemos substituir os métodos OBJECT CLASS

    Interfaces: Não podemos substituir os métodos OBJECT CLASS dentro de interfaces.

Terminarei com a observação de que:

Os conceitos de método padrão / conceitos de método estático na interface vieram apenas para salvar as classes de implementação, mas não para fornecer uma implementação útil significativa. Métodos padrão / métodos estáticos são um tipo de implementação fictícia ", se você quiser, pode substituí-los ou substituí-los (no caso de métodos padrão) na classe de implementação", evitando assim a implementação de novos métodos nas classes de implementação sempre que novos métodos nas interfaces são adicionados. Portanto, as interfaces nunca podem ser iguais às classes abstratas.

Umar Tahir
fonte
5

A regra Remi Forax é Você não cria com as classes Abstratas. Você cria seu aplicativo com interfaces . Watever é a versão do Java, qualquer que seja a linguagem. É apoiada pela eu princípio segregação nterface em SOL I D princípios.

Posteriormente, você pode usar classes Abstratas para fatorar o código. Agora, com o Java 8, você pode fazer isso diretamente na interface. Esta é uma instalação, não mais.

Nicolas Zozol
fonte
2

quando a interface com os métodos padrão deve ser usada e quando uma classe abstrata deve ser usada?

Compatibilidade com versões anteriores: imagine que sua interface seja implementada por centenas de classes, modificando essa interface forçará todos os usuários a implementar o método recém-adicionado, mesmo que não seja essencial para muitas outras classes que implementam sua interface. Além disso, permite que sua interface ser uma interface funcional

Fatos e Restrições:

1-Só pode ser declarado dentro de uma interface e não dentro de uma classe ou classe abstrata.

2-Deve fornecer um corpo

3-Não é assumido que seja abstrato como outros métodos normais usados ​​em uma interface.

Ahmad Sanie
fonte
1

No Java 8, uma interface se parece com uma classe abstrata, embora possam haver algumas diferenças, como:

1) Classes abstratas são classes, portanto, não estão restritas a outras restrições da interface em Java, por exemplo, a classe abstrata pode ter o estado , mas você não pode ter o estado na interface em Java.

2) Outra diferença semântica entre a interface com métodos padrão e a classe abstrata é que você pode definir construtores dentro de uma classe abstrata , mas não pode definir construtor dentro da interface em Java

Manish Sahni
fonte
Concordo com o nº 2, mas com o nº 1, você não pode simplesmente implementar a interface e, portanto, ter um estado através da classe de implementação?
George Xavier
0

Os métodos padrão na Interface Java devem ser usados ​​mais para fornecer implementação fictícia de uma função, poupando assim qualquer classe de implementação dessa interface do trabalho de declarar todos os métodos abstratos, mesmo que eles desejem lidar com apenas um. Os métodos padrão na interface são, de certa forma, mais um substituto para o conceito de classes de adaptadores.

Os métodos na classe abstrata devem, no entanto, fornecer uma implementação significativa que qualquer classe filho deve substituir somente se necessário para substituir uma funcionalidade comum.

shubh
fonte
0

Como mencionado em outras respostas, a capacidade de adicionar implementação a uma interface foi adicionada para fornecer compatibilidade com versões anteriores na estrutura Coleções. Eu argumentaria que fornecer compatibilidade com versões anteriores é potencialmente a única boa razão para adicionar implementação a uma interface.

Caso contrário, se você adicionar implementação a uma interface, estará violando a lei fundamental do motivo pelo qual as interfaces foram adicionadas em primeiro lugar. Java é uma linguagem de herança única, diferentemente do C ++, que permite herança múltipla. As interfaces fornecem os benefícios de digitação que vêm com um idioma que suporta herança múltipla sem introduzir os problemas que acompanham a herança múltipla.

Mais especificamente, o Java permite apenas herança única de uma implementação, mas permite herança múltipla de interfaces. Por exemplo, o seguinte é um código Java válido:

class MyObject extends String implements Runnable, Comparable { ... }

MyObject herda apenas uma implementação, mas herda três contratos.

Java transmitiu herança múltipla de implementação porque a herança múltipla de implementação vem com uma série de problemas espinhosos, que estão fora do escopo desta resposta. As interfaces foram adicionadas para permitir a herança múltipla de contratos (aka interfaces) sem os problemas de herança múltipla da implementação.

Para apoiar meu argumento, aqui está uma citação de Ken Arnold e James Gosling do livro The Java Programming Language, 4th edition :

A herança única exclui alguns designs úteis e corretos. Os problemas da herança múltipla surgem da herança múltipla da implementação, mas em muitos casos a herança múltipla é usada para herdar vários contratos abstratos e talvez uma implementação concreta. Fornecer um meio de herdar um contrato abstrato sem herdar uma implementação permite os benefícios de digitação de herança múltipla sem os problemas de herança de implementação múltipla. A herança de um contrato abstrato é denominada herança de interface . A linguagem de programação Java suporta herança de interface, permitindo que você declare um interfacetipo

johnnyodonnell
fonte
-1

Por favor, pense primeiro no princípio aberto / fechado. Os métodos padrão nas interfaces O VIOLAM. Este é um recurso ruim em Java. Ele incentiva o design ruim, a arquitetura ruim e a baixa qualidade do software. Eu sugeriria evitar o uso completo de métodos padrão.

Faça a si mesmo algumas perguntas: Por que você não pode colocar seus métodos na classe abstrata? Você precisaria então de mais de uma classe abstrata? Em seguida, pense sobre o que é sua classe responsável. Você tem certeza de que todos os métodos que você vai colocar na classe realmente cumprem o mesmo propósito? Pode ser que você distinga vários propósitos e depois divida sua classe em várias classes, para cada finalidade sua própria classe.

mentallurg
fonte