Menu
Coddy logo textTech

Default e Static em Interfaces

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 37 de 87.

Originalmente, as interfaces podiam conter apenas métodos abstratos sem implementação. A partir do Java 8, as interfaces ganharam a capacidade de incluir métodos default e métodos estáticos, tornando-as mais flexíveis.

Um método default fornece uma implementação diretamente na interface usando a palavra-chave default. Classes que implementam a interface herdam esse comportamento automaticamente, mas podem sobrescrevê-lo se necessário:

public interface Drawable {
    void draw();
    
    default void display() {
        System.out.println("Displaying on screen...");
        draw();
    }
}

Qualquer classe que implemente Drawable recebe o método display() gratuitamente. Isso é particularmente útil para adicionar novos métodos a interfaces existentes sem quebrar as classes que já as implementam.

Métodos estáticos em interfaces funcionam como métodos estáticos em classes. Eles pertencem à própria interface e são chamados usando o nome da interface:

public interface MathOperations {
    static int add(int a, int b) {
        return a + b;
    }
}

// Uso
int result = MathOperations.add(5, 3);

Métodos estáticos de interface não podem ser sobrescritos e não são herdados pelas classes que as implementam. Eles são úteis para métodos utilitários relacionados ao propósito da interface.

Se uma classe implementa duas interfaces com a mesma assinatura de método default, a classe deve sobrescrever esse método para resolver o conflito.

challenge icon

Desafio

Fácil

Vamos construir um sistema de mensagens que demonstre métodos default e estáticos em interfaces. Você criará uma interface com funcionalidade integrada que as classes implementadoras podem usar diretamente ou personalizar conforme necessário.

Você organizará seu código em quatro arquivos:

  • Messenger.java: Defina uma interface que represente qualquer serviço de mensagens. Ela deve declarar um método abstrato sendMessage(String message) que retorna void. Adicione um método default chamado sendWithTimestamp(String message) que imprime: [TIMESTAMP] seguido pela chamada de sendMessage(message). Também inclua um método estático chamado formatMessage(String message) que retorna a mensagem convertida para letras maiúsculas.
  • EmailMessenger.java: Crie uma classe que implemente Messenger. Ela possui um campo recipient (String). Inclua um construtor para inicializar o destinatário. Implemente sendMessage() para imprimir: Email to [recipient]: [message]. Esta classe usa o método default sendWithTimestamp() como ele é.
  • SMSMessenger.java: Crie outra classe que implemente Messenger. Ela possui um campo phoneNumber (String). Inclua um construtor para inicializar o número de telefone. Implemente sendMessage() para imprimir: SMS to [phoneNumber]: [message]. Sobrescreva o método default sendWithTimestamp() para imprimir: [URGENT] seguido pela chamada de sendMessage(message) em vez de usar o comportamento de timestamp padrão.
  • Main.java: Reúna tudo para demonstrar os métodos de interface default e estáticos. Você receberá três entradas: um destinatário de e-mail, um número de telefone e uma mensagem. Primeiro, use o método estático Messenger.formatMessage() para formatar a mensagem e armazená-la. Em seguida, crie um EmailMessenger e um SMSMessenger. Para cada mensageiro, chame sendWithTimestamp() com a mensagem formatada — observe como o EmailMessenger usa a implementação default enquanto o SMSMessenger usa sua versão sobrescrita.

Você receberá três entradas: o destinatário do e-mail (String), o número de telefone (String) e a mensagem (String).

Sua saída deve mostrar quatro linhas no total — duas para cada mensageiro. O EmailMessenger mostrará o prefixo de timestamp padrão, enquanto o SMSMessenger mostrará seu prefixo urgente personalizado. Ambos usarão a mensagem formatada estaticamente (em maiúsculas)!

Folha de consulta

A partir do Java 8, as interfaces podem incluir métodos default e métodos estáticos, além de métodos abstratos.

Métodos default fornecem uma implementação diretamente na interface usando a palavra-chave default. As classes que implementam a interface herdam esse comportamento automaticamente, mas podem sobrescrevê-lo se necessário:

public interface Drawable {
    void draw();
    
    default void display() {
        System.out.println("Displaying on screen...");
        draw();
    }
}

Métodos estáticos em interfaces pertencem à própria interface e são chamados usando o nome da interface. Eles não podem ser sobrescritos e não são herdados pelas classes implementadoras:

public interface MathOperations {
    static int add(int a, int b) {
        return a + b;
    }
}

// Usage
int result = MathOperations.add(5, 3);

Se uma classe implementa duas interfaces com a mesma assinatura de método default, a classe deve sobrescrever esse método para resolver o conflito.

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Ler as entradas
        String emailRecipient = scanner.nextLine();
        String phoneNumber = scanner.nextLine();
        String message = scanner.nextLine();
        
        // TODO: Use Messenger.formatMessage() para formatar a mensagem e armazená-la
        
        // TODO: Crie um EmailMessenger com o destinatário do e-mail
        
        // TODO: Crie um SMSMessenger com o número de telefone
        
        // TODO: Chame sendWithTimestamp() no EmailMessenger com a mensagem formatada
        
        // TODO: Chame sendWithTimestamp() no SMSMessenger com a mensagem formatada
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos