Cada nova versão do Java difere das anteriores. Como exemplo dessa mudança do material que abordamos, a linguagem não existia
Da mesma forma, o Java 8 é visivelmente diferente do Java 7. Não vamos ignorar inovações importantes, é claro. Já que estamos falando sobre interfaces nesta lição, vamos considerar uma atualização da linguagem: métodos padrão em interfaces . Você já sabe que uma interface não implementa comportamento . Sua finalidade é descrever qual comportamento deve existir em todos os objetos que implementam a interface . Mas os desenvolvedores frequentemente encontravam situações em que a implementação de um método era a mesma em todas as classes. Vejamos nosso exemplo de carro antigo:
enums
antes do Java 5.
public interface Car {
public void gas();
public void brake();
}
public class Sedan implements Car {
@Override
public void gas() {
System.out.println("Gas!");
}
@Override
public void brake() {
System.out.println("Brake!");
}
}
public class Truck implements Car {
@Override
public void go() {
System.out.println("Gas!");
}
@Override
public void brake() {
System.out.println("Brake!");
}
}
public class F1Car implements Car {
@Override
public void go() {
System.out.println("Gas!");
}
@Override
public void brake() {
System.out.println("Brake!");
}
}
Qual você acha que é o principal problema com esse código? Você provavelmente notou que escrevemos um monte de código duplicado! Este é um problema comum na programação e deve ser evitado. Outra questão é que não havia soluções específicas antes do lançamento do Java 8. Quando essa versão foi lançada, tornou-se possível definir métodos padrão e implementá-los diretamente dentro de uma interface! Veja como fazer:
public interface Car {
public default void gas() {
System.out.println("Gas!");
}
public default void brake() {
System.out.println("Brake!");
}
}
public class Sedan implements Car {
}
public class Truck implements Car {
}
public class F1Car implements Car {
}
Agora os métodos gas()
e brake()
, que eram os mesmos para todos os carros, foram movidos para a interface, eliminando a necessidade de código duplicado. E os métodos estão disponíveis em cada uma das aulas!
public class Main {
public static void main(String[] args) {
F1Car f1Car = new F1Car();
Sedan sedan = new Sedan();
Truck truck = new Truck();
truck.gas();
sedan.gas();
f1Car.brake();
}
}
E se houver 100 classes com um gas()
método, mas apenas 99 delas tiverem o mesmo comportamento? Isso estraga tudo? Um método padrão não funcionará neste caso? Claro que não :) Os métodos de interface padrão podem ser substituídos.
public class UnusualCar implements Car {
@Override
public void go() {
System.out.println("This car accelerates differently!");
}
@Override
public void brake() {
System.out.println("This car slows down differently!");
}
}
Todos os outros 99 tipos de carros empregarão o método padrão, enquanto oUnusualCar
classe é uma exceção. Sem estragar o quadro geral, ele definirá com calma seu próprio comportamento. Herança múltipla em interfaces. Como você já sabe, não existe herança múltipla em Java. Há muitas razões para isto. Vamos considerá-los em detalhes em uma lição separada. Em outras linguagens, como C++, a situação é inversa. Nenhuma herança múltipla apresenta um grande desafio, pois um mesmo objeto pode ter várias características e comportamentos diferentes. Por exemplo, somos filhos para nossos pais, alunos para nossos professores e pacientes para nossos médicos. Na vida real, desempenhamos vários papéis e, portanto, nos comportamos de maneira diferente: obviamente, interagimos com os professores de maneira diferente do que com amigos próximos. Vamos tentar traduzir essa situação em código. Vamos imaginar que temos duas classes: Pond e Aviary. Um lago precisa de pássaros nadadores, enquanto um aviário precisa de pássaros voadores. Para representar isso, criamos duas classes base:FlyingBird
e Waterfowl
.
public class Waterfowl {
}
public class FlyingBird {
}
Assim, enviaremos as aves que herdam FlyingBird
para o aviário, enquanto as que derivam Waterfowl
irão para a lagoa. Tudo parece simples. Mas o que devemos fazer se precisarmos definir um pato em algum lugar? Os patos nadam e voam. Mas não temos herança múltipla. Felizmente, o Java oferece suporte a várias implementações de interfaces. Se uma classe não pode herdar vários pais, é fácil implementar várias interfaces! Nosso pato pode ser tanto um pássaro voador quanto um pássaro nadador :) Para atingir o resultado desejado, tudo o que precisamos fazer é criar FlyingBird
interfaces Waterfowl
em vez de classes.
public class Duck implements FlyingBird, Waterfowl {
// Methods of both interfaces combine easily into one class
@Override
public void fly() {
System.out.println("Flying!");
}
@Override
public void swim() {
System.out.println("Swimming!");
}
}
Isso significa que nosso programa mantém a capacidade de gerenciar classes de forma flexível. Quando combinamos isso com métodos padrão, nossa capacidade de determinar o comportamento dos objetos torna-se quase ilimitada! :)
GO TO FULL VERSION