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 interface
palavra-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();
}
- Em vez da
class
palavra-chave, escrevemosinterface
. - Ele contém apenas métodos abstratos (não escreva a
abstract
palavra-chave) - Na verdade, as interfaces têm todos
public
os métodos
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 implements
palavra-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 ChessItem
classe contém um método abstrato — draw()
.
O significado técnico das palavras-chave extends
e 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 public
palavra-chave. Se você quiser que alguns desses métodos sejam chamados apenas de dentro de sua classe, você precisa marcá-los com a private
palavra-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 |
---|---|
|
|
|
|
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
LinkedList
são duas implementações diferentes da List
interface.
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:
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 value
variável. Sua classe descendente XCoordinate usa essa variável para armazenar o x
valor, e a YCoordinate
classe descendente a usa para armazenar o y
valor.
E funciona. Separadamente. Mas, se quisermos que a classe XYCoordinates herde as classes XCoordinate
e 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.
GO TO FULL VERSION