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. |