O que é Interface em Kotlin?
Resposta rápida: uma interface em Kotlin define um contrato — quais funções e propriedades uma classe precisa ter — sem fixar a implementação. Uma mesma classe pode implementar várias interfaces, e a interface pode trazer métodos com corpo (default methods) e propriedades sem backing field. Para um único método abstrato usável com lambda, declare fun interface. Para hierarquias fechadas e when exaustivo, use sealed interface. Prefira interface quando o foco é o contrato; prefira abstract quando precisa de estado ou construtor compartilhado.
interface Autenticavel {
fun autenticar(senha: String): Boolean
}
class Usuario(val nome: String, private val senhaHash: String) : Autenticavel {
override fun autenticar(senha: String): Boolean = senha == senhaHash
}
| Se você precisa de… | Use |
|---|---|
| Contrato sem estado | interface |
| Estado, construtor ou base compartilhada | abstract class |
Hierarquia fechada + when exaustivo | sealed interface / sealed class |
| Um único método abstrato + lambda | fun interface |
| Reaproveitar implementação pronta | delegação com by |
Para um passo a passo mais longo, veja o tutorial de interfaces em Kotlin.
Sintaxe básica
interface Autenticavel {
fun autenticar(senha: String): Boolean
}
class Usuario(val nome: String, private val senhaHash: String) : Autenticavel {
override fun autenticar(senha: String): Boolean {
return senha == senhaHash
}
}
fun main() {
val user = Usuario("Karina", "abc123")
println(user.autenticar("abc123")) // true
println(user.autenticar("errada")) // false
}
Métodos com implementação padrão
Em Kotlin, interfaces podem ter métodos com corpo — os famosos default methods:
interface Logavel {
val tag: String
get() = this::class.simpleName ?: "Desconhecido"
fun log(mensagem: String) {
println("[$tag] $mensagem")
}
}
class Servico : Logavel
fun main() {
val servico = Servico()
servico.log("Iniciando processamento")
// [Servico] Iniciando processamento
}
Múltiplas interfaces
interface Imprimivel {
fun imprimir()
}
interface Exportavel {
fun exportar(): String
}
class Relatorio(val titulo: String) : Imprimivel, Exportavel {
override fun imprimir() {
println("Imprimindo: $titulo")
}
override fun exportar(): String {
return "PDF: $titulo"
}
}
fun main() {
val relatorio = Relatorio("Vendas Q1")
relatorio.imprimir()
println(relatorio.exportar())
}
Resolvendo conflitos
Quando duas interfaces têm o mesmo método com implementação padrão, você precisa resolver o conflito manualmente:
interface A {
fun saudacao() = "Olá de A"
}
interface B {
fun saudacao() = "Olá de B"
}
class C : A, B {
override fun saudacao(): String {
return "${super<A>.saudacao()} e ${super<B>.saudacao()}"
}
}
Quando usar interface vs abstract class?
Use interface quando quiser definir um contrato que múltiplas classes podem adotar. Use abstract class quando precisar de estado compartilhado (campos com valores) ou construtores. Interfaces são mais flexíveis e promovem um design mais desacoplado. Detalhes e exemplos no glossário de abstract.
Interface com propriedades abstratas
Interfaces podem declarar propriedades que as classes implementadoras devem fornecer:
interface Identificavel {
val id: String
val tipo: String
get() = "genérico" // Propriedade com valor padrao
}
interface Auditavel {
val criadoEm: Long
val atualizadoEm: Long
}
data class Documento(
override val id: String,
val titulo: String,
override val criadoEm: Long,
override val atualizadoEm: Long
) : Identificavel, Auditavel {
override val tipo: String
get() = "documento"
}
fun main() {
val doc = Documento("doc-001", "Contrato", 1700000000, 1700100000)
println("${doc.tipo}: ${doc.titulo} (ID: ${doc.id})")
// documento: Contrato (ID: doc-001)
}
fun interface e conversão SAM
Uma fun interface tem exatamente um método abstrato. Com isso, o Kotlin aceita uma lambda no lugar de uma classe anônima — a conversão SAM (Single Abstract Method):
fun interface Transformador {
fun transformar(texto: String): String
}
fun aplicar(valor: String, transformador: Transformador): String {
return transformador.transformar(valor)
}
fun main() {
val maiusculo = aplicar("kotlin") { it.uppercase() }
println(maiusculo) // KOTLIN
}
Sem fun interface, interfaces Kotlin não aceitam SAM conversion automaticamente. Interfaces Java com um único método abstrato já permitem a conversão a partir do lado Kotlin.
Interface como tipo para injeção de dependência
Um dos usos mais poderosos de interfaces é permitir a substituição de implementações, fundamental para testes e arquiteturas desacopladas:
interface NotificacaoService {
fun enviar(destinatario: String, mensagem: String): Boolean
}
class EmailService : NotificacaoService {
override fun enviar(destinatario: String, mensagem: String): Boolean {
println("Enviando email para $destinatario: $mensagem")
return true
}
}
class SmsService : NotificacaoService {
override fun enviar(destinatario: String, mensagem: String): Boolean {
println("Enviando SMS para $destinatario: $mensagem")
return true
}
}
// Em testes, voce pode criar um fake facilmente
class FakeNotificacaoService : NotificacaoService {
val mensagensEnviadas = mutableListOf<Pair<String, String>>()
override fun enviar(destinatario: String, mensagem: String): Boolean {
mensagensEnviadas.add(destinatario to mensagem)
return true
}
}
class PedidoService(private val notificacao: NotificacaoService) {
fun finalizarPedido(clienteEmail: String) {
// ... logica do pedido
notificacao.enviar(clienteEmail, "Seu pedido foi confirmado!")
}
}
Delegação de interface com by
Kotlin permite implementar uma interface reaproveitando outra implementação com delegation:
interface Repositorio {
fun buscar(id: String): String?
fun salvar(id: String, valor: String)
}
class RepositorioEmMemoria : Repositorio {
private val dados = mutableMapOf<String, String>()
override fun buscar(id: String) = dados[id]
override fun salvar(id: String, valor: String) {
dados[id] = valor
}
}
class RepositorioComLog(
private val origem: Repositorio
) : Repositorio by origem {
override fun salvar(id: String, valor: String) {
println("salvando $id")
origem.salvar(id, valor)
}
}
Sealed interfaces
A partir do Kotlin 1.5, você pode usar sealed interfaces para restringir quais classes podem implementar uma interface:
sealed interface Resultado {
data class Sucesso(val dados: String) : Resultado
data class Erro(val mensagem: String) : Resultado
data object Carregando : Resultado
}
fun processar(resultado: Resultado) {
when (resultado) {
is Resultado.Sucesso -> println("Dados: ${resultado.dados}")
is Resultado.Erro -> println("Erro: ${resultado.mensagem}")
Resultado.Carregando -> println("Carregando...")
}
}
O when é exaustivo automaticamente para sealed interfaces, dispensando o ramo else. Compare com sealed class quando houver estado compartilhado entre os subtipos.
Casos de Uso no Mundo Real
- Camada de repositório: definir uma interface
UsuarioRepositorycom operações comobuscarPorId,salvaredeletar, permitindo trocar a implementação entre banco de dados real e repositório em memória para testes. - Strategy pattern em regras de negócio: criar uma interface
CalculoFretecom diferentes implementações para Correios, transportadora e retirada, injetando a estratégia correta conforme a escolha do cliente. - Plugins e extensibilidade: sistemas de plugins usam interfaces para definir contratos que módulos externos devem seguir, permitindo adicionar funcionalidades sem modificar o código principal.
- Tratamento de estado com sealed interface: modelar estados de tela no Android (Loading, Success, Error) como uma sealed interface, garantindo que o
whencubra todos os estados possíveis. - Callbacks concisos com
fun interface: APIs de listener no Android e no backend aceitam lambda em vez de classe anônima verbosa.
Boas Práticas
- Prefira interfaces pequenas e focadas (Interface Segregation Principle). Uma interface com muitos métodos força implementadores a lidar com funcionalidades que podem não ser relevantes.
- Use implementações padrão com moderação. Elas são úteis para métodos auxiliares, mas não devem conter lógica de negócio complexa que seria melhor em uma classe abstrata.
- Nomeie interfaces pelo comportamento que descrevem, não pela implementação:
Serializavel,Persistivel,Autenticavelcomunicam intenção melhor queSerializadorImplouBancoDeDados. - Programe para a interface, não para a implementação. Declare variáveis e parâmetros usando o tipo da interface sempre que possível.
- Use sealed interfaces quando o conjunto de implementações é fechado e conhecido, permitindo
whenexaustivo e maior segurança em tempo de compilação. - Marque como
fun interfacesó quando houver exatamente um método abstrato e a API for pensada para receber lambdas.
Erros Comuns
- Criar interfaces com um único implementador sem justificativa: se a interface existe apenas por existir e nunca será reimplementada, ela adiciona complexidade sem benefício. Crie interfaces quando houver necessidade real de abstração.
- Colocar estado mutável em interfaces: interfaces não devem ter campos
varcom backing field. Se precisa de estado compartilhado, use uma classe abstrata. - Esquecer o
overrideao implementar métodos da interface: diferente de Java, Kotlin exige a palavra-chaveoverrideexplicitamente, o que previne erros acidentais. - Não resolver conflitos de nomes entre interfaces: quando duas interfaces têm métodos com o mesmo nome e implementação padrão, a classe deve resolver explicitamente com
super<Interface>.método(). - Usar interface quando abstract class seria mais apropriada: se as implementações compartilham estado (propriedades com backing field) ou lógica de construtor, uma classe abstrata é a escolha mais adequada.
- Esperar SAM conversion em interface Kotlin comum: sem
fun interface, passar uma lambda no lugar da interface gera erro de tipo.
Perguntas Frequentes
Interfaces em Kotlin podem ter construtores? Não. Interfaces não podem ter construtores. Se você precisa de parâmetros de inicialização, use uma classe abstrata.
Qual a diferença entre interface em Kotlin e em Java? Em Kotlin, interfaces podem ter propriedades (sem backing field), implementações padrão de métodos e participar de sealed hierarchies. Em Java, default methods existem desde o Java 8, mas propriedades em interfaces não são suportadas da mesma forma. Para SAM conversion em interfaces Kotlin, use fun interface.
Posso usar delegação com interfaces? Sim. Kotlin suporta delegação de interface com a palavra-chave by: class MeuServico(servico: NotificacaoService) : NotificacaoService by servico. Isso delega todas as chamadas de interface para o objeto fornecido. Veja delegation.
Quando usar sealed interface vs sealed class? Use sealed interface quando as implementações não precisam compartilhar estado (propriedades com backing field) e quando deseja que uma classe implemente múltiplas sealed hierarchies. Sealed class é melhor quando há estado e lógica compartilhados.
O que é fun interface? É a forma de declarar uma interface funcional em Kotlin, com um único método abstrato, habilitando conversão automática de lambda (SAM).
Termos Relacionados
- Abstract — alternativa quando há estado ou construtor compartilhado
- Sealed Class — hierarquias fechadas; base para comparar com sealed interface
- Delegation — reaproveitar implementação de interface com
by - Fun — funções declaradas em interfaces são implementadas usando
funeoverride - Generics — interfaces genéricas como
Comparable<T>eIterable<T>definem contratos flexíveis - Lambda —
fun interfacepermite substituir a implementação por lambda (SAM) - Higher-Order Function — interfaces com um único método abstrato se aproximam de tipos de função
- Tutorial: Interfaces em Kotlin — guia passo a passo com mais exemplos