Lembre-se de que o Java é meticuloso em relação ao tipo.
Vamos estender um pouco seu exemplo e renomear a classe para Jumpable
.
interface Jumpable {
void jump(int);
}
class Person extends Mammal implements Jumpable {
//other stuff
void jump(int howHigh) {
//jump method
}
}
class Dog extends Mammal implements Jumpable {
//other stuff
void jump(int howHigh) {
//jump method
//also make him bark when he jumps
}
}
class Cat extends Mammal implements Jumpable {
//other stuff
void jump(int howHigh) {
//jump method
//make it stretch its legs as well
}
}
class FlyingFish extends Fish implements Jumpable {
//other stuff
void jump(int howHigh) {
//jump method
//make it come out of water
}
}
class Mantis extends Insect implements Jumpable {
//other stuff
void jump(int howHigh) {
//jump method
//make it come out of water
}
}
class Ant extends Insect { //Cannot jump
//other stuff
}
class Whale extends Mammal { //Cannot jump (hopefully)
//other stuff
}
Note que aqui temos uma variedade de classes, organizadas em alguma hierarquia. Nem todos eles podem pular, e a habilidade de pular não é universalmente aplicável a qualquer categoria - cada classe pai ( Animal
, Mammal
, Insect
, Fish
).
Digamos que queremos realizar uma competição de saltos. Sem interfaces , teríamos que fazer algo assim:
void competition(
Person[] pCompetitors,
Dog[] dCompetitors,
Cat[] cCompetitors,
FlyingFish[] fCompetitors,
Mantis[] mCompetitors
) {
for(int i=0; i<pCompetitors.length; i++) {
pCompetitors[i].jump((int)Math.rand() * 10);
}
//Do the same for ALL the other arrays.
}
Aqui, como não há "classe envolvente" que contenha todas as classes que podem pular, temos que invocá-las individualmente. Lembre-se, não podemos apenas ter uma matriz Animal[]
ou Mammal[]
, pois o compilador não nos permitirá chamar jump()
; e nem todos Animal
s / Mammal
s podem jump()
.
Além disso, isso se torna impossível de se estender. Vamos dizer que você quer adicionar outra aula de salto.
class Bob extends Animal { //Bob is NOT a human. Bob is something....else....
void jump(int howHigh) {
//...
}
}
Agora, você precisa modificar competition(.........)
para aceitar também um parâmetro Bob[]
. Você também precisa modificar todas as instâncias de competition[]
para criar seus próprios Bob[]
s ou passar os parâmetros Bob[]
vazios. E fica nojento.
Se você usou interfaces, seu método de competição se torna assim:
void competition(Jumpable[] j) {
for(int i=0; i<j.length; i++) {
j[i].jump((int)Math.rand() * 10);
}
}
Isso pode ser estendido sem problemas também.
Basicamente, as interfaces permitem que o compilador conheça o esperado comportamento do objeto - que métodos / dados o compilador pode assumir. Dessa forma, podemos escrever programas gerais.
Além disso, você pode herdar várias interfaces, você não pode fazer isso com extends
em Java.
Alguns exemplos do mundo real: O primeiro que vem à mente é o manipulador de eventos do AWT. Isso nos permite passar um método como um parâmetro e torná-lo um manipulador de eventos. Isso só funcionará se o compilador tiver certeza de que o método existe e, portanto, usarmos interfaces.