Ir para o conteúdo

Interfaces

Definição

Um contrato que define um conjunto de métodos que uma classe deve implementar, sem fornecer a implementação desses métodos.

Diferente da herança, interfaces definem contratos que podem ser implementados por diferentes classes, permitindo maior flexibilidade e desacoplamento.

Objetivos

A interface permite:

  • Abstração de código
  • Ativar o mecanismo de polimorfismo
  • Desacoplamento entre as classes

Representação em diagrama de classes da UML.

Código Java

Por padrão, os métodos em uma interface são públicos e abstratos, ou seja, não possuem um corpo(implementação). No entanto, a partir do Java 8, interfaces também podem possuir métodos default e static com implementação.

public interface Printable{
  void print();
}

A interface pode possuir atributos, porém são sempre públicos, estáticos (escopo de classe) e finais (constantes).

public interface Constants{
  double PI = 3.1415;
}

Implementação

Os métodos devem ser implementados/realizados em uma classe concreta.

Passo 1

Indicar na classe a implementação/realização de interface. Após o nome da classe utilize a palavra-chave implements.

class Person implements Printable{
  private String name;
  // getters e setters ocultos
}

Passo 2

A classe obrigatoriamente deve implementar todos os métodos da interface. Recomenda-se sempre utilizar a anotação @Override nos métodos implementados.

class Person implements Printable{

  private String name;

  @Override
  public void print(){
    System.out.println("Name: " + name);
  }
}

Instanciação

Um objeto não pode ser criado a partir de uma interface. Deve ser sempre instanciado um objeto que implementa a interface.

// ERRADO
Printable c = new Printable();

// CERTO
Person p = new Person();

Polimorfismo

Um objeto que implementa uma interface pode ser referenciado por uma variável do tipo da interface. O polimorfismo é um dos objetivos de se utilizar interfaces.

Printable c = new Person();

// Retornar ao objeto original,
// deve ser utilizado o operador de casting

Person p = (Person) c;

O casting só é seguro quando o objeto realmente é do tipo convertido. A conversão do objeto para um tipo que ele não pertença causará o erro de ClassCastException.

Múltiplas realizações de interface

Uma classe pode realizar a implementação de múltiplas interfaces.

Os nomes das interfaces implementadas são separadas pela vírgula.

class Person implements Printable, Cloneable{

  private String name;

  @Override
  public void print(){
    
  }
}

Interfaces podem definir métodos com a mesma assinatura. Quando esses métodos possuem implementação (default), podem ocorrer conflitos que devem ser resolvidos pela classe. Esse problema é conhecido como “diamond problem” (problema do diamante).

interface A {
  default void print() {
    System.out.println("A");
  }
}

interface B {
  default void print() {
    System.out.println("B");
  }
}

class Person implements A, B {
  @Override
  public void print() {
    A.super.print(); // resolve conflito
  }
}

Herança de interfaces

As interfaces podem realizar uma ou múltiplas heranças de outras interfaces.

Na implementação, se utiliza a palavra-chave extends para indicar herança de interfaces.

interface Cloneable{

}

interface Printable extends Cloneable{
  void print();
}

Interface na linguagem Java

A linguagem Java fornece recursos extras na criação de interfaces.

Método default

O método default permite adicionar uma implementação padrão em um método da interface. Caso a classe que implementa a interface não sobrescreva o método, será utilizado o método default da interface.

public interface Printable{
  default void print(){
     System.out.println("Hello print");
  }
}

public class Person implements Printable{

  // Não é obrigatório implementar o método print
}

Método static

Interfaces também podem possuir métodos estáticos. Esses métodos pertencem à própria interface e não às classes que a implementam. Diferente dos métodos default, métodos static não são herdados pelas classes que implementam a interface.

public interface Printable{

  static void printMessage(){
    System.out.println("Printing...");
  }
}

Utilização: O método estático deve ser acessado diretamente pela interface:

Printable.printMessage();

Não é possível acessar o método estático a partir de uma instância da classe:

Printable p = new Person();

// ERRADO
p.printMessage();

Observação: Métodos estáticos em interfaces são geralmente utilizados para:

  • métodos utilitários relacionados à interface
  • métodos auxiliares
  • criação de objetos (factory methods, em alguns casos)