Métodos padrão das interfaces
Introdução no JDK 8:
- Métodos padrão permitem que interfaces forneçam uma implementação padrão para um método.
- Esse recurso resolve problemas de compatibilidade ao expandir interfaces sem quebrar códigos existentes.
Motivações:
- Compatibilidade retroativa: Adicionar novos métodos a interfaces populares sem invalidar código existente.
- Métodos opcionais: Permitir que certas implementações sejam opcionais, especialmente em casos de métodos irrelevantes para algumas classes que implementam a interface.
Exemplo de código:
// Interface com método padrão
interface MyInterface {
void abstractMethod();
// Método padrão
default void defaultMethod() {
System.out.println("Default implementation.");
}
}
class MyClass implements MyInterface {
public void abstractMethod() {
System.out.println("Implemented abstract method.");
}
// Pode sobrescrever o método padrão, se necessário
public void defaultMethod() {
System.out.println("Overridden default method.");
}
}
class DefaultMethodDemo {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.abstractMethod();
obj.defaultMethod();
}
}
Ponto importante: Interfaces ainda não podem ter variáveis de instância, e continuam servindo principalmente para especificar o quê, e não como algo deve ser feito.
Fundamentos dos Métodos Padrão
Métodos padrão foram introduzidos no JDK 8.
Palavra-chave default: É usada para definir um método padrão em uma interface.
Objetivo: Permitir que as interfaces evoluam sem quebrar códigos existentes.
Implementação padrão: Fornece um corpo ao método que será utilizado caso a classe que implementa a interface não sobreponha o método.
Exemplo Básico de Método Padrão
public interface MyIF {
// Método de interface comum, sem implementação.
int getUserID();
// Método padrão, com implementação fornecida.
default int getAdminID() {
return 1;
}
}
class MyIFImp implements MyIF {
// Apenas o método getUserID precisa ser implementado.
public int getUserID() {
return 100;
}
}
class DefaultMethodDemo {
public static void main(String args[]) {
MyIFImp obj = new MyIFImp();
System.out.println("User ID is " + obj.getUserID());
System.out.println("Administrator ID is " + obj.getAdminID());
}
}
Saída:
User ID is 100
Administrator ID is 1
Explicação:
- O método getAdminID() tem uma implementação padrão. A classe MyIFImp não precisa sobrescrever esse método, pois já existe um comportamento fornecido.
- A classe MyIFImp só precisa implementar o método getUserID(), enquanto getAdminID() pode ser utilizado diretamente com a implementação padrão.
Sobrescrevendo Métodos Padrão
Sobrescrita de método padrão: A classe pode fornecer sua própria implementação, sobrescrevendo o método padrão.
Exemplo de Sobrescrita de Método Padrão
class MyIFImp2 implements MyIF {
public int getUserID() {
return 100;
}
// Sobrescreve o método padrão.
public int getAdminID() {
return 42;
}
}
class DefaultMethodOverrideDemo {
public static void main(String args[]) {
MyIFImp2 obj = new MyIFImp2();
System.out.println("User ID is " + obj.getUserID());
System.out.println("Administrator ID is " + obj.getAdminID());
}
}
Saída:
User ID is 100
Administrator ID is 42
Explicação:
A implementação de getAdminID() foi sobrescrita em MyIFImp2, portanto, ao chamar esse método, ele retorna 42 ao invés do valor padrão 1.
Exemplo Prático de Método Padrão
- Cenário Prático: Adição de métodos padrão em uma interface existente para evitar a quebra de código legado.
- Interface Series: Define métodos que lidam com uma sequência de números. Um método padrão getNextArray() foi adicionado para retornar um array com os próximos n números da sequência, usando o método getNext() já existente.
Exemplo de Método Padrão em um Cenário Prático
public interface Series {
int getNext(); // Retorna o próximo número da série.
// Método padrão que retorna um array com os próximos n números.
default int[] getNextArray(int n) {
int[] vals = new int[n];
for(int i = 0; i < n; i++) {
vals[i] = getNext();
}
return vals;
}
void reset(); // Reinicia a série.
void setStart(int x); // Define o valor inicial.
}
class ByTwos implements Series {
int start;
int val;
ByTwos() {
start = 0;
val = 0;
}
public int getNext() {
val += 2;
return val;
}
public void reset() {
val = start;
}
public void setStart(int x) {
start = x;
val = x;
}
}
class SeriesDemo {
public static void main(String args[]) {
ByTwos ob = new ByTwos();
int[] nextNums = ob.getNextArray(5);
for(int n : nextNums) {
System.out.print(n + " ");
}
}
}
Saída:
2 4 6 8 10
Explicação:
A interface Series foi estendida com o método padrão getNextArray(), que usa o método getNext() para obter os próximos n números da série.
O código implementa a sequência de números pares e utiliza o novo método para obter um array com os próximos 5 números.
Vantagens dos Métodos Padrão
- Evolução das interfaces sem quebrar código existente: Interfaces podem ser expandidas com novos métodos sem exigir alterações em classes que já as implementam.
- Funcionalidade opcional: Permite que métodos sejam opcionais, sem necessidade de implementações de "espaço reservado".
- Flexibilidade: Classes podem usar os métodos padrão como estão ou sobrescrevê-los conforme necessário.