CodeGym /Cursos /JAVA 25 SELF /Diferenças entre interfaces e classes abstratas

Diferenças entre interfaces e classes abstratas

JAVA 25 SELF
Nível 20 , Lição 1
Disponível

1. Classe abstrata: revisando o básico

Antes de partir para a comparação, vamos relembrar o que é uma classe abstrata.

Classe abstrata — é uma classe que não pode ser instanciada diretamente (não dá para escrever new Animal()), mas pode conter tanto métodos comuns (com implementação) quanto métodos abstratos (sem implementação). Uma classe abstrata é frequentemente usada como base para outras classes, que herdam seu comportamento e/ou são obrigadas a implementar alguns métodos.

Por exemplo, se no nosso aplicativo há diferentes tipos de transporte, podemos criar uma classe abstrata Transport:

public abstract class Transport {
    private String model;

    public Transport(String model) {
        this.model = model;
    }

    public String getModel() {
        return model;
    }

    // Método abstrato — sem implementação, apenas declaração
    public abstract void move();

    // Método comum — possui implementação
    public void printInfo() {
        System.out.println("Modelo do transporte: " + model);
    }
}

Características da classe abstrata:

  • Pode conter campos (estado).
  • Pode conter métodos implementados.
  • Pode conter métodos abstratos (obrigatórios de implementar nas subclasses).
  • Não é possível instanciar diretamente.
  • Usada para comportamento e estado comuns.

2. Interface: revisando o básico

Interface — é um conjunto de métodos que uma classe deve implementar. A interface não descreve estado (não pode ter campos comuns, apenas constantes) e não contém implementações de métodos (até o Java 8). Interface é um contrato puro: “Se você me implementa, é obrigado a saber fazer isto”.

Exemplo de interface:

public interface Movable {
    void move(int x, int y);
}

Características da interface:

  • Não contém estado (apenas constantes public static final).
  • Até o Java 8 — apenas métodos abstratos (a partir do Java 8 surgiram métodos default e static, mas falaremos deles depois).
  • Os métodos são sempre public abstract por padrão.
  • Uma classe pode implementar várias interfaces.
  • Usada para descrever capacidades, “o que a classe sabe fazer”.

3. Tabela comparativa: classe abstrata vs. interface

Hora de comparar essas duas ferramentas lado a lado! Aqui está uma tabela ilustrativa:

Característica Classe abstrata Interface
Sintaxe
abstract class
interface
É possível criar instâncias? Não Não
Pode conter métodos comuns? Sim Até o Java 8 — não; a partir do Java 8 — apenas default/static
Pode conter métodos abstratos? Sim Sim (todos os métodos até o Java 8 são abstratos)
Pode conter campos (estado)? Sim (quaisquer campos) Apenas public static final (constantes)
Pode conter construtores? Sim Não
Herança Apenas uma classe (abstrata ou concreta) Pode implementar várias interfaces
Modificadores de métodos Qualquer um (public, protected, private) Por padrão, os métodos são public abstract. A partir do Java 9 é possível adicionar métodos private para uso interno na interface
Herança por meio de
extends
implements
Uso típico Implementação e estado comuns Descrição de capacidades e papéis
Exemplos da JDK
AbstractList, AbstractMap
Comparable, Runnable

4. Quando usar interface e quando usar classe abstrata?

Interface use quando:

  • Você quer descrever “o que a classe sabe fazer”, sem se preocupar em como ela faz.
  • Você precisa que a classe possa implementar várias capacidades independentes.
  • Exemplo: Comparable (pode ser comparado), Serializable (pode ser serializado), Runnable (pode ser executado em uma thread).

Classe abstrata use quando:

  • Você quer definir implementação e estado comuns que todas as subclasses terão.
  • Você precisa que todas as subclasses tenham determinados campos ou métodos já implementados.
  • A herança é estritamente “um-para-um”: a classe pode herdar de apenas uma classe (concreta ou abstrata).

Analogias do dia a dia

  • Interface — é como uma “carteira de motorista”: se você a tem, você pode dirigir um carro, mas ninguém diz em qual carro exatamente nem como você faz isso.
  • Classe abstrata — é como um “projeto genérico de um automóvel”: todos os carros têm volante, pedais, motor, mas cada marca implementa os detalhes à sua maneira.

5. Exemplos da biblioteca padrão do Java

Interface: Comparable

public interface Comparable<T> {
    int compareTo(T o);
}

Qualquer classe que implemente essa interface é obrigada a implementar o método compareTo. Por exemplo, String, Integer, LocalDate e muitas outras.

Classe abstrata: AbstractList

public abstract class AbstractList<E> implements List<E> {
    // Implementação de alguns métodos de List por padrão
    // Alguns métodos são deixados como abstratos
}

AbstractList já implementa parte do comportamento das coleções (por exemplo, métodos de adição/remoção), mas deixa alguns métodos abstratos para que as subclasses possam implementá-los à sua maneira.

6. Exemplos de código: comparação na prática

Interface

Vamos criar uma interface e uma classe que a implementa.

public interface Printable {
    void print();
}

public class Document implements Printable {
    @Override
    public void print() {
        System.out.println("Imprimindo documento...");
    }
}

Classe abstrata

Agora, uma classe abstrata e sua subclasse.

public abstract class Machine {
    public void turnOn() {
        System.out.println("Máquina ligada.");
    }

    public abstract void work();
}

public class Printer extends Machine {
    @Override
    public void work() {
        System.out.println("A impressora está imprimindo...");
    }
}

Classe que combina ambos: interface e classe abstrata

public class SmartPrinter extends Machine implements Printable {
    @Override
    public void work() {
        System.out.println("A impressora inteligente está funcionando...");
    }

    @Override
    public void print() {
        System.out.println("A impressora inteligente está imprimindo...");
    }
}

7. Implementação múltipla de interfaces: por que isso é bacana

Em Java, uma classe pode herdar de apenas uma classe (abstrata ou concreta), mas pode implementar quantas interfaces quiser! Isso permite criar arquiteturas flexíveis e extensíveis.

public interface Scannable {
    void scan();
}

public class MultiFunctionPrinter extends Machine implements Printable, Scannable {
    @Override
    public void work() {
        System.out.println("O multifuncional está funcionando...");
    }

    @Override
    public void print() {
        System.out.println("O multifuncional está imprimindo...");
    }

    @Override
    public void scan() {
        System.out.println("O multifuncional está escaneando...");
    }
}

Quando escolher cada um?

  • Se você está projetando funcionalidade base com estado comum (por exemplo, campos), use uma classe abstrata.
  • Se você quer adicionar “rótulos de capacidades” aos objetos (por exemplo, “sabe imprimir”, “sabe comparar”, “sabe serializar”) — use interfaces.
  • Se não tiver certeza — comece com interface. Em Java isso é considerado uma boa prática: interfaces oferecem mais flexibilidade e extensibilidade.

8. Erros comuns e armadilhas

Erro nº 1: Você tenta herdar de várias classes — o Java não permite!
Uma classe pode herdar de apenas uma classe, mas implementar muitas interfaces. Por exemplo, class A extends B, C — erro, mas class A extends B implements X, Y, Z — tudo bem.

Erro nº 2: Confundir campos de interface e de classe.
Em uma interface só é possível declarar constantes (public static final). Não é possível declarar estado comum, por exemplo, private int count; — o compilador vai impedir na hora.

Erro nº 3: Não implementar todos os métodos da interface.
Se a classe não implementar nem que seja um único método da interface — ela deve ser declarada como abstract; caso contrário, o compilador emitirá um erro.

Erro nº 4: Tentar instanciar uma interface ou classe abstrata.
Ambos esses tipos — “semiprodutos”. Eles podem apenas ser estendidos, não instanciados diretamente:

Printable p = new Printable(); // Erro!
Machine m = new Machine();     // Erro!

Erro nº 5: Achar que uma interface pode ter construtor.
Interfaces não podem ter construtores, pois não descrevem o estado de objetos. Apenas classes (concretas e abstratas).

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION