Interface: essência, contratos em Java e Kotlin para Android

Autor: IT Sectr Publicado: 2026-02-18 Tempo de leitura: 9 min

Interface é um contrato que define um conjunto de métodos abstratos que uma classe deve implementar. Em Java e Kotlin, as interfaces são o mecanismo principal de abstração e polimorfismo. Em Java 8+, as interfaces podem conter métodos default e static, em Kotlin — implementações padrão. Segundo o Google Android Developers (2025), as interfaces são usadas em 90% dos projetos Android para definir camadas de arquitetura — repositórios, UseCases e serviços.

Principais pontos

  • Interface é um tipo abstrato que define assinaturas de métodos sem implementação (antes do Java 8)
  • Implements é a palavra-chave que liga uma classe a uma interface; uma classe pode implementar várias interfaces
  • Default method é um método com implementação em uma interface Java, adicionado no Java 8 para compatibilidade reversa
  • Kotlin interface suporta propriedades com getters e implementações de métodos, substituindo abstract class em muitos cenários
  • Markup interface é uma interface vazia usada como marcador (Serializable, Cloneable, RandomAccess)

O que é Interface em Java e Kotlin?

Interface é um tipo de referência que contém métodos abstratos, constantes e métodos padrão. Uma classe que implementa uma interface deve fornecer implementação para todos os seus métodos abstratos. Em Java, uma interface não pode ter estado (campos de instância); Kotlin também segue essa restrição, mas suporta propriedades com acessores.

Java
public interface Repository {
    T findById(Long id);
    List findAll();
    T save(T entity);
    void deleteById(Long id);
    
    default long count() {
        return findAll().size();
    }
}

@Entity
public class UserEntity {
    private Long id;
    private String email;
    // getters e setters
}

public class UserRepositoryImpl implements Repository {
    private final EntityManager em;
    
    public UserEntity findById(Long id) {
        return em.find(UserEntity.class, id);
    }
    
    public List findAll() {
        return em.createQuery("FROM UserEntity", UserEntity.class)
                .getResultList();
    }
    // outros métodos
}

Repository<T> é uma interface genérica com métodos CRUD. O método default count() fornece uma implementação padrão que pode ser sobrescrita. UserRepositoryImpl implementa a interface usando EntityManager para acesso a dados. Essa abordagem permite testar a camada de dados através de um mock da interface sem um banco de dados real.

Interface vs abstract class: quando escolher o quê

A escolha entre uma interface e uma classe abstrata depende da presença de estado compartilhado e das relações entre tipos. Uma interface define um contrato (o que uma classe pode fazer), uma classe abstrata define uma implementação comum (o que uma classe é).

CritérioInterfaceAbstract Class
Estado (campos)Apenas constantes static finalSim, qualquer campo
ConstrutoresNãoSim
Herança múltiplaSim (implements)Não (extends um)
Modificadores de acessopublic (Java 8-), métodos defaultTodos (private, protected, public)
Quando usarContrato para classes não relacionadasBase comum para classes relacionadas

No Clean Architecture, as interfaces são colocadas na camada interna (domain), e as implementações na camada externa (data). Isso permite manter a Dependency Rule: a camada externa depende da interna, mas não o contrário. Classes abstratas são mais usadas para métodos template (Template Method pattern).

Interface em Kotlin: propriedades e delegados

As interfaces do Kotlin são mais flexíveis que as do Java: podem declarar propriedades abstratas e fornecer implementações de métodos. Diferente do Java, Kotlin suporta delegação através da palavra-chave by, o que reduz poderosamente o boilerplate ao implementar o padrão Delegate.

Kotlin
interface ApiService {
    val baseUrl: String  // propriedade abstrata
    
    suspend fun fetchData(): Result>
    
    fun getEndpoint(path: String): String {
        return "$baseUrl/$path"  // implementação padrão
    }
}

class RetrofitApiService(
    override val baseUrl: String
) : ApiService {
    private val client = Retrofit.Builder()
        .baseUrl(baseUrl)
        .build()
    
    override suspend fun fetchData(): Result> {
        // implementação da solicitação
    }
}

// Delegação via by
interface Logger {
    fun log(message: String)
}

class ConsoleLogger : Logger {
    override fun log(message: String) = println(message)
}

class UserService(logger: Logger) : Logger by logger

UserService implementa a interface Logger através de delegação (by). Todas as chamadas log() são redirecionadas para o objeto logger sem escrever métodos wrapper. Este é um exemplo de composição que em Java exigiria 5-10 linhas de código boilerplate.

Interface no Clean Architecture Android

Clean Architecture para Android separa claramente o aplicativo em camadas. As interfaces atuam como limites entre camadas: Domain define as interfaces de repositórios e UseCases, Data fornece as implementações. Isso permite substituir implementações sem alterar a lógica de negócio — uma vantagem chave ao migrar de Room para Firebase ou de REST para GraphQL.

Kotlin
// Domain layer — interface (contrato)
interface UserRepository {
    suspend fun getUser(id: String): User
    suspend fun updateUser(user: User)
}

// Domain layer — use case (depende da interface)
class GetUserUseCase(
    private val repository: UserRepository
) {
    suspend operator fun invoke(id: String): Result {
        return runCatching { repository.getUser(id) }
    }
}

// Data layer — implementação
class UserRepositoryImpl(
    private val api: UserApi,
    private val dao: UserDao
) : UserRepository {
    override suspend fun getUser(id: String): User {
        val cached = dao.getUser(id)
        if (cached != null) return cached
        val remote = api.fetchUser(id)
        dao.insertUser(remote)
        return remote
    }
    // updateUser...
}

UserRepository é uma interface na camada domain. GetUserUseCase depende da interface, não da implementação. UserRepositoryImpl na camada data implementa a interface, combinando API e banco de dados local. Essa arquitetura permite testar UseCases com um repositório mock sem configurar banco de dados ou rede.

Métodos default e static no Java 8+

Os métodos default foram adicionados no Java 8 para extensão evolutiva de interfaces sem quebrar a compatibilidade reversa. Se ArrayList não implementasse o novo método stream() adicionado ao Collection, o código antigo continuaria funcionando. Métodos static em interfaces servem como utilitários relacionados à interface — uma alternativa a classes utilitárias.

Java
public interface Vehicle {
    void start();
    void stop();
    
    default void honk() {
        System.out.println("Beep!");
    }
    
    static Vehicle of(String type) {
        if ("car".equals(type)) return new Car();
        return new Bicycle();
    }
    
    // constante
    String CATEGORY = "transport";
}

Os métodos default resolvem o diamond problem: se uma classe implementa duas interfaces com o mesmo método default, o compilador exige sobrescrita explícita. Métodos static são chamados através do nome da interface — Vehicle.of("car"), sem uma instância.

Erros comuns no design de interfaces

Erros no design de interfaces levam a código frágil, complexidade de teste e violações SOLID. Vamos ver três problemas comuns.

Interface Pollution — muitos métodos em uma interface

Uma interface contendo 15+ métodos viola o Interface Segregation Principle (ISP). Um exemplo é o antigo java.util.Dictionary com 10+ métodos. Solução: dividir em várias interfaces pequenas — ReadableRepository, WritableRepository, SearchableRepository. Um cliente (serviço) depende apenas dos métodos que precisa.

Abstração excessiva — interface para cada classe

Criar uma interface para cada classe sem necessidade real de polimorfismo é o antipadrão Interface overkill. Indicador: a interface tem exatamente uma implementação e o projeto não tem planos de adicionar alternativas. Solução: adicionar uma interface apenas quando uma segunda opção de implementação aparecer ou um mock for necessário para testes.

Perguntas frequentes

Como interface difere de abstract class em Java?

Interface define apenas um contrato (assinaturas de métodos), não pode ter estado e suporta herança múltipla. Abstract class pode conter campos, construtores e métodos implementados, mas uma classe pode herdar apenas uma classe abstrata. Desde Java 8, as interfaces ganharam métodos default e static, reduzindo a lacuna.

Uma interface pode herdar outra interface?

Sim, em Java e Kotlin as interfaces suportam herança. public interface AdvancedRepository<T> extends Repository<T>, Pageable é uma interface que combina outras duas. Uma classe implementando AdvancedRepository deve implementar todos os métodos de ambas as interfaces pai. Herança múltipla é permitida apenas para interfaces.

O que é uma interface funcional em Java?

Interface funcional é uma interface com um único método abstrato (SAM — Single Abstract Method). A anotação @FunctionalInterface garante essa restrição. Exemplos: Runnable, Callable, Comparator, Consumer. Interfaces funcionais são a base das expressões lambda do Java 8: () -> System.out.println() implementa Runnable.

Por que métodos default são necessários em interfaces Java?

Métodos default permitem adicionar novos métodos a uma interface sem modificar todas as classes que a implementam. Por exemplo, Java 8 adicionou stream() à Collection como método default. Sem esse mecanismo, foreach(), stream() e outros métodos exigiriam alterações em milhares de classes no JDK. Default é uma forma de extensão compatível com versões anteriores.

Como Kotlin resolve o problema de herança múltipla?

Kotlin proíbe herança múltipla de classes mas permite implementação múltipla de interfaces. Se duas interfaces têm um método com a mesma assinatura e implementação padrão, o compilador exige sobrescrita explícita com a chamada super<InterfaceName>.method(). Isso resolve o diamond problem no nível de compilação.

Resumo

  • Interface é um contrato que define métodos que uma classe deve implementar; o mecanismo principal de polimorfismo em Java e Kotlin
  • Java 8+ adicionou métodos default e static às interfaces, reduzindo a lacuna com classes abstratas
  • Kotlin interfaces suportam propriedades abstratas, implementações padrão e delegação via by
  • Clean Architecture usa interfaces como limites entre as camadas Domain e Data
  • Interface Segregation Principle requer dividir interfaces grandes em especializadas
  • Interfaces funcionais (Single Abstract Method) são a base das expressões lambda e Stream API
  • Recomendação: adicione uma interface quando uma segunda implementação aparecer ou um mock for necessário para testes

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também