265 lines
11 KiB
Markdown
265 lines
11 KiB
Markdown
|
---
|
|||
|
title: Interfaces
|
|||
|
localeTitle: Interfaces
|
|||
|
---
|
|||
|
# Interfaces
|
|||
|
|
|||
|
A interface em Java é um pouco como a Classe, mas com uma diferença significativa: uma `interface` _só_ pode ter assinaturas de métodos, campos e métodos padrão. Desde o Java 8, você também pode criar [métodos padrão](https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html) . No próximo bloco você pode ver um exemplo de interface:
|
|||
|
|
|||
|
```java
|
|||
|
public interface Vehicle {
|
|||
|
public String licensePlate = "";
|
|||
|
public float maxVel
|
|||
|
public void start();
|
|||
|
public void stop();
|
|||
|
default void blowHorn(){
|
|||
|
System.out.println("Blowing horn");
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
A interface acima contém dois campos, dois métodos e um método padrão. Sozinho, não é de muita utilidade, mas geralmente são usados junto com Classes. Como? Simples, você tem que ter certeza que alguma classe o `implements` .
|
|||
|
|
|||
|
```java
|
|||
|
public class Car implements Vehicle {
|
|||
|
public void start() {
|
|||
|
System.out.println("starting engine...");
|
|||
|
}
|
|||
|
public void stop() {
|
|||
|
System.out.println("stopping engine...");
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":foguete:") [Executar código](https://repl.it/CItd/0)
|
|||
|
|
|||
|
Agora, existe uma **regra básica** : A classe deve implementar **todos** os métodos na interface. Os métodos devem ter _exatamente a mesma_ assinatura (nome, parâmetros e exceções) conforme descrito na interface. A classe _não_ precisa declarar os campos, apenas os métodos.
|
|||
|
|
|||
|
## Instâncias de uma interface
|
|||
|
|
|||
|
Depois de criar uma classe Java que `implements` qualquer interface, a instância do objeto pode ser referenciada como uma instância da interface. Este conceito é semelhante ao da instanciação de herança.
|
|||
|
|
|||
|
```java
|
|||
|
// following our previous example
|
|||
|
|
|||
|
Vehicle tesla = new Car();
|
|||
|
|
|||
|
tesla.start(); // starting engine ...
|
|||
|
```
|
|||
|
|
|||
|
Uma interface **não pode** conter um método construtor, portanto, você **não pode** criar uma instância de uma interface em si. Você deve criar uma instância de alguma classe implementando uma interface para referenciá-la. Pense em interfaces como um formulário de contrato em branco ou um modelo.
|
|||
|
|
|||
|
O que você pode fazer com esse recurso? Polimorfismo! Você pode usar apenas interfaces para se referir a instâncias de objetos!
|
|||
|
|
|||
|
```java
|
|||
|
class Truck implements Vehicle {
|
|||
|
public void start() {
|
|||
|
System.out.println("starting truck engine...");
|
|||
|
}
|
|||
|
public void stop() {
|
|||
|
System.out.println("stopping truck engine...");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class Starter {
|
|||
|
// static method, can be called without instantiating the class
|
|||
|
public static void startEngine(Vehicle vehicle) {
|
|||
|
vehicle.start();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Vehicle tesla = new Car();
|
|||
|
Vehicle tata = new Truck();
|
|||
|
|
|||
|
Starter.startEngine(tesla); // starting engine ...
|
|||
|
Starter.startEngine(tata); // starting truck engine ...
|
|||
|
```
|
|||
|
|
|||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":foguete:") [Executar código](https://repl.it/CItm/0)
|
|||
|
|
|||
|
## Mas e quanto a múltiplas interfaces?
|
|||
|
|
|||
|
Sim, você pode implementar várias interfaces em uma única classe. Enquanto em [Herança](//forum.freecodecamp.com/t/java-docs-inheritance) dentro de Classes você estava restrito a herdar apenas uma classe, aqui você pode estender qualquer número de interfaces. Mas não esqueça de implementar _todos_ os métodos de todas as Interfaces, caso contrário a compilação falhará!
|
|||
|
|
|||
|
```java
|
|||
|
public interface GPS {
|
|||
|
public void getCoordinates();
|
|||
|
}
|
|||
|
|
|||
|
public interface Radio {
|
|||
|
public void startRadio();
|
|||
|
public void stopRadio();
|
|||
|
}
|
|||
|
|
|||
|
public class Smartphone implements GPS,Radio {
|
|||
|
public void getCoordinates() {
|
|||
|
// return some coordinates
|
|||
|
}
|
|||
|
public void startRadio() {
|
|||
|
// start Radio
|
|||
|
}
|
|||
|
public void stopRadio() {
|
|||
|
// stop Radio
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":foguete:") [Executar código](https://repl.it/CIto/0)
|
|||
|
|
|||
|
## Algumas características das interfaces
|
|||
|
|
|||
|
* Você pode colocar variáveis dentro de uma Interface, embora não seja uma decisão sensata, pois as Classes não estão obrigadas a ter a mesma variável. Em suma, evite colocar variáveis!
|
|||
|
* Todas as variáveis e métodos em uma interface são públicos, mesmo se você deixar de fora a palavra-chave `public` .
|
|||
|
* Uma interface não pode especificar a implementação de um método específico. Cabe às classes fazer isso. Embora tenha havido uma exceção recente (veja abaixo).
|
|||
|
* Se uma classe implementa múltiplas interfaces, existe uma chance remota de sobreposição de assinatura de método. Como o Java não permite vários métodos da mesma assinatura, isso pode causar problemas. Veja [esta pergunta](http://stackoverflow.com/questions/2598009/method-name-collision-in-interface-implementation-java) para mais informações.
|
|||
|
|
|||
|
## Métodos padrão de interface
|
|||
|
|
|||
|
Antes do Java 8, não tínhamos como direcionar uma interface para ter uma implementação de método particular. Isso leva a muita confusão e quebras de código se uma definição de interface for repentinamente alterada.
|
|||
|
|
|||
|
Suponha que você escreveu uma biblioteca de código aberto, que contém uma interface. Digamos, seus clientes, ou seja, praticamente todos os desenvolvedores em todo o mundo, estão usando muito e estão felizes. Agora você precisou atualizar a biblioteca adicionando uma nova definição de método à Interface para suportar um novo recurso. Mas isso quebraria _todas as_ compilações, já que todas as classes que implementam essa interface precisam mudar agora. Que catástrofe!
|
|||
|
|
|||
|
Felizmente, o Java 8 agora nos fornece métodos `default` para Interfaces. Um método `default` _pode_ conter sua própria implementação _diretamente_ na Interface! Portanto, se uma classe não implementar um método padrão, o compilador executará a implementação mencionada na interface. Bom, não é? Então, em sua biblioteca, você pode adicionar qualquer número de métodos padrão em interfaces sem o medo de quebrar nada!
|
|||
|
|
|||
|
```java
|
|||
|
public interface GPS {
|
|||
|
public void getCoordinates();
|
|||
|
default public void getRoughCoordinates() {
|
|||
|
// implementation to return coordinates from rough sources
|
|||
|
// such as wifi & mobile
|
|||
|
System.out.println("Fetching rough coordinates...");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public interface Radio {
|
|||
|
public void startRadio();
|
|||
|
public void stopRadio();
|
|||
|
}
|
|||
|
|
|||
|
public class Smartphone implements GPS,Radio {
|
|||
|
public void getCoordinates() {
|
|||
|
// return some coordinates
|
|||
|
}
|
|||
|
public void startRadio() {
|
|||
|
// start Radio
|
|||
|
}
|
|||
|
public void stopRadio() {
|
|||
|
// stop Radio
|
|||
|
}
|
|||
|
|
|||
|
// no implementation of getRoughCoordinates()
|
|||
|
}
|
|||
|
|
|||
|
Smartphone motoG = new Smartphone();
|
|||
|
motog.getRoughCoordinates(); // Fetching rough coordinates...
|
|||
|
```
|
|||
|
|
|||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":foguete:") [Executar código](https://repl.it/CItp/0)
|
|||
|
|
|||
|
### Mas o que acontece se duas interfaces tiverem a mesma assinatura de método?
|
|||
|
|
|||
|
Pergunta impressionante. Nesse caso, se você não fornecer a implementação na classe, o compilador pobre ficará confuso e simplesmente falhará! Você tem que fornecer uma implementação de método padrão dentro da classe também. Há também uma maneira bacana de usar `super` para chamar de qual implementação você gosta:
|
|||
|
|
|||
|
```java
|
|||
|
public interface Radio {
|
|||
|
// public void startRadio();
|
|||
|
// public void stopRadio();
|
|||
|
|
|||
|
default public void next() {
|
|||
|
System.out.println("Next from Radio");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public interface MusicPlayer {
|
|||
|
// public void start();
|
|||
|
// public void pause();
|
|||
|
// public void stop();
|
|||
|
|
|||
|
default public void next() {
|
|||
|
System.out.println("Next from MusicPlayer");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class Smartphone implements Radio, MusicPlayer {
|
|||
|
public void next() {
|
|||
|
// Suppose you want to call MusicPlayer next
|
|||
|
MusicPlayer.super.next();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Smartphone motoG = new Smartphone();
|
|||
|
motoG.next(); // Next from MusicPlayer
|
|||
|
```
|
|||
|
|
|||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":foguete:") [Executar código](https://repl.it/CIts/0)
|
|||
|
|
|||
|
## Métodos estáticos em interfaces
|
|||
|
|
|||
|
Outra novidade no Java 8 é a capacidade de adicionar métodos estáticos a interfaces. Métodos estáticos em interfaces são quase idênticos aos métodos estáticos em classes concretas. A única grande diferença é que os métodos `static` não são herdados nas classes que implementam a interface. Isso significa que a interface é referenciada ao chamar o método estático e não a classe que o implementa.
|
|||
|
|
|||
|
```java
|
|||
|
interface MusicPlayer {
|
|||
|
public static void commercial(String sponsor) {
|
|||
|
System.out.println("Now for a message brought to you by " + sponsor);
|
|||
|
}
|
|||
|
|
|||
|
public void play();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
class Smartphone implements MusicPlayer {
|
|||
|
public void play() {
|
|||
|
System.out.println("Playing from smartphone");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class Main {
|
|||
|
public static void main(String[] args) {
|
|||
|
Smartphone motoG = new Smartphone();
|
|||
|
MusicPlayer.commercial("Motorola"); // Called on interface not on implementing class
|
|||
|
// motoG.commercial("Motorola"); // This would cause a compilation error
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":foguete:") [Executar código](https://repl.it/CIts/9)
|
|||
|
|
|||
|
## Herdando uma Interface
|
|||
|
|
|||
|
Também é possível em Java que uma interface _herde_ outra interface, usando, você adivinhou, `extends` palavra-chave:
|
|||
|
|
|||
|
```java
|
|||
|
public interface Player {
|
|||
|
public void start();
|
|||
|
public void pause();
|
|||
|
public void stop();
|
|||
|
}
|
|||
|
|
|||
|
public interface MusicPlayer extends Player {
|
|||
|
default public void next() {
|
|||
|
System.out.println("Next from MusicPlayer");
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
Isso significa que a Classe que implementa a Interface `MusicPlayer` tem que implementar _todos os_ métodos do `MusicPlayer` , bem como do `Player` :
|
|||
|
|
|||
|
```java
|
|||
|
public class SmartPhone implements MusicPlayer {
|
|||
|
public void start() {
|
|||
|
System.out.println("start");
|
|||
|
}
|
|||
|
public void stop() {
|
|||
|
System.out.println("stop");
|
|||
|
}
|
|||
|
public void pause() {
|
|||
|
System.out.println("pause");
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ":foguete:") [Executar código](https://repl.it/CIty/0)
|
|||
|
|
|||
|
Ops, eu esqueci o `next()` ? Veja, já que era um método `default` , eu não tive que fornecer uma implementação. (Não funciona para JDK <8)
|
|||
|
|
|||
|
Então, agora você tem uma boa compreensão das Interfaces! Aprenda mais sobre as Classes Abstratas para saber como o Java oferece outra maneira de definir contratos.
|