1. Apresentando interfaces

Hoje é o seu dia de conhecimento. Outro tópico novo e interessante são as interfaces.

O conceito de interface é filho dos princípios de abstração e polimorfismo. Uma interface é muito semelhante a uma classe abstrata, na qual todos os métodos são abstratos. É declarado da mesma forma que uma classe, mas usamos a interfacepalavra-chave.

interface Feline
{
   void purr();
   void meow();
   void growl();
}

Aqui estão alguns fatos úteis sobre interfaces:

1. Declarando uma interface

interface Drawable
{
   void draw();
}

interface HasValue
{
   int getValue();
}
  1. Em vez da classpalavra-chave, escrevemos interface.
  2. Ele contém apenas métodos abstratos (não escreva a abstractpalavra-chave)
  3. Na verdade, as interfaces têm todospublic os métodos
2. Herança de interface

Uma interface só pode herdar interfaces. Mas uma interface pode ter muitos pais. Outra maneira de dizer isso é dizer que Java tem herança múltipla de interfaces. Exemplos:

interface Piece extends Drawable, HasValue
{
   int getX();
   int getY();
}

3. Herdando classes de interfaces

Uma classe pode herdar várias interfaces (somente de uma classe). Isso é feito usando a implementspalavra-chave. Exemplo:

abstract class ChessItem implements Drawable, HasValue
{
   private int x, y, value;
   public int getValue()
   {
      return value;
   }

   public int getX()
   {
      return x;
   }

   public  int getY()
   {
      return y;
   }
}

A classe ChessItem é declarada abstrata: ela implementa todos os métodos herdados, exceto draw. Em outras palavras, a ChessItemclasse contém um método abstrato — draw().

O significado técnico das palavras-chave extendse implementsé o mesmo: ambos são herança. A distinção foi feita para melhorar a legibilidade do código. Também dizemos que as classes são herdadas (via extends) e as interfaces são implementadas (via implements)

4. Variáveis

Aqui está o mais importante: variáveis ​​comuns não podem ser declaradas em interfaces (embora as estáticas possam).

Mas por que precisamos de interfaces? Quando são usados? As interfaces têm duas grandes vantagens sobre as classes:



2. Separar a "descrição dos métodos" da sua implementação.

Anteriormente, dissemos que se você deseja permitir que os métodos de sua classe sejam chamados de outras classes, seus métodos precisam ser marcados com a publicpalavra-chave. Se você quiser que alguns desses métodos sejam chamados apenas de dentro de sua classe, você precisa marcá-los com a privatepalavra-chave. Em outras palavras, dividimos os métodos da classe em duas categorias: "para todos usarem" e "somente para nosso próprio uso".

As interfaces ajudam a fortalecer ainda mais essa divisão. Faremos uma "classe especial para todos usarem" bem como uma segunda classe "apenas para nosso próprio uso", que herdará a primeira classe. Veja mais ou menos como ficaria:

Antes Depois
class Student
{
   private String name;
   public Student(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
interface Student
{
   public String getName();
}

class StudentImpl implements Student
{
   private String name;
   public StudentImpl(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
}
public static void main(String[] args)
{
   Student student = new Student("Alibaba");
   System.out.println(student.getName());
}
public static void main(String[] args)
{
   Student student = new StudentImpl("Ali")
   System.out.println(student.getName());
}

Dividimos nossa classe em duas: uma interface e uma classe que herda a interface . E qual é a vantagem aqui?

Muitas classes diferentes podem implementar (herdar) a mesma interface. E cada um pode ter seu próprio comportamento. Por exemplo, ArrayList LinkedListsão duas implementações diferentes da Listinterface.

Assim, ocultamos não apenas as várias implementações, mas também a própria classe implementadora (já que precisamos apenas da interface no código). Isso nos permite ser muito flexíveis: à medida que o programa roda, podemos substituir um objeto por outro, alterando o comportamento de um objeto sem afetar todas as classes que o utilizam.

Esta é uma técnica muito poderosa quando combinada com polimorfismo. Por enquanto, está longe de ser óbvio por que você deve fazer isso. Você primeiro precisa encontrar programas com dezenas ou centenas de classes para entender que as interfaces podem tornar sua vida muito mais fácil do que sem elas.


3. Herança múltipla

Em Java, todas as classes podem ter apenas uma classe pai. Em outras linguagens de programação, as classes geralmente podem ter várias classes pai. Isso é muito conveniente, mas também traz muitos problemas.

Os criadores de Java chegaram a um acordo: proibiram a herança múltipla de classes, mas permitiram a herança múltipla de interfaces. Uma interface pode ter várias interfaces pai. Uma classe pode ter várias interfaces pai, mas apenas uma classe pai.

Por que eles baniram a herança múltipla de classes, mas permitiram a herança múltipla de interfaces? Por causa do chamado problema de herança de diamantes:

Herança múltipla

Quando a classe B herda a classe A, ela não sabe nada sobre as classes C e D. Então ele usa as variáveis ​​da classe A como bem entender. A classe C faz o mesmo: usa as variáveis ​​da classe A, mas de maneira diferente. E tudo isso resulta em um conflito na classe D.

Vejamos o seguinte exemplo simples. Digamos que temos 3 classes:

class Data
{
   protected int value;
}
class XCoordinate extends Data
{
   public void setX (int x) { value = x;}
   public int getX () { return value;}
}
class YCoordinate extends Data
{
   public void setY (int y) { value = y;}
   public int getY () { return value; }
}

A classe Data armazena a valuevariável. Sua classe descendente XCoordinate usa essa variável para armazenar o xvalor, e a YCoordinateclasse descendente a usa para armazenar o yvalor.

E funciona. Separadamente. Mas, se quisermos que a classe XYCoordinates herde as classes XCoordinatee YCoordinate, obteremos um código corrompido. Esta classe terá os métodos de suas classes ancestrais, mas não funcionarão corretamente, pois possuem o mesmo value variable.

Mas como as interfaces não podem ter variáveis, elas não podem ter esse tipo de conflito. Assim, a herança múltipla de interfaces é permitida.