Herança é a relação entre duas classes, uma superclasse e uma subclasse, que faz com que
Por exemplo, vamos fazer uma classe Pato
que tem os atributos: nome e ano de nascimento; e os métodos voa e nada.
Depois vamos definir uma subclasse PatoSubmarino
que tem também uma valocidade para nadar e redefine o método nadar.
class Pato{ private String nome; private int ano; public Pato(String aNome, int aAno){ this.nome = aNome; this.ano = aAno; } public String getNome(){ return nome; } public int getAno(){ return ano; } public void voa(){ System.out.println("O Pato voa"); } public void nada(){ System.out.println("O Pato nada"); } @Override public String toString(){ String res = "classe " + this.getClass() + "\n"; res += "nome: " + this.nome + "\n"; res += "nascimento: " + this.ano + "\n"; return res; } }
class PatoSubmarino extends Pato{ private double velocidade; public PatoSubmarino(String aNome, int aAno, double aVelocidade){ super(aNome, aAno); this.velocidade = aVelocidade; } @Override public void nada(){ System.out.println("Nada com uma velocidade de " + this.velocidade); } @Override public String toString(){ String res = super.toString(); res += "Velocidade: " + this.velocidade + "\n"; return res; } }
class TestePato{ public static void main(String[] args){ Pato pato = new Pato("joao", 1999); System.out.println(pato); pato.voa(); pato.nada(); PatoSubmarino patoSubmarino = new PatoSubmarino("atomico", 2000, 555); System.out.println(patoSubmarino); patoSubmarino.voa(); patoSubmarino.nada(); } }
Saída
classe class Pato
nome: joao
nascimento: 1999
O Pato voa
O Pato nada
classe class PatoSubmarino
nome: atomico
nascimento: 2000
Velocidade: 555.0
O Pato voa
Nada com uma velocidade de 555.0
Polimorfismo é a capacidade que uma variável de um tipo poder representar qualquer objeto filho deste tipo.
No exemplo anterior podemos ter uma variável do tipo Pato
com objetos do tipo PatoSubmarino
Podemos ter uma Lista de Pato
com objetos do tipo PatoSubmarino
import java.util.ArrayList; class TestePolimorfismo{ public static void main(String[] args){ Pato pato01 = new Pato("joao", 1999); System.out.println(pato01); pato01.voa(); pato01.nada(); Pato patoSubmarino = new PatoSubmarino("atomico", 2000, 555); System.out.println(patoSubmarino); patoSubmarino.voa(); patoSubmarino.nada(); System.out.println(); System.out.println("\n----------------------------------------"); System.out.println("Fazendo uma lista de patos do tipo Pato"); System.out.println("----------------------------------------\n"); ArrayList<Pato> patos = new ArrayList<Pato>(); patos.add(pato01); patos.add(patoSubmarino); for(Pato pato: patos){ System.out.println(pato); pato.voa(); pato.nada(); } } }
Saída
classe class Pato
nome: joao
nascimento: 1999
O Pato voa
O Pato nada
classe class PatoSubmarino
nome: atomico
nascimento: 2000
Velocidade: 555.0
O Pato voa
Nada com uma velocidade de 555.0
----------------------------------------
Fazendo uma lista de patos do tipo Pato
----------------------------------------
classe class Pato
nome: joao
nascimento: 1999
O Pato voa
O Pato nada
classe class PatoSubmarino
nome: atomico
nascimento: 2000
Velocidade: 555.0
O Pato voa
Nada com uma velocidade de 555.0
Classes abstratas servem como classe base para fazer subclasses. Por exemplo, se você tem as classes Cachorro
, Gato
e Pato
, que compartilham atributos e métodos, você pode fazer uma classe abstrata para servir de super classe para as três classes.
A vantagem da classe abstrata é que ela pode ter métodos abstratos, que são métodos que não precisam ser implementados, forçando que a subclasse concreta implemente.
As características de uma clase abstrata são:
Por exemplo, considere as seguintes classes:
class Cachorro{ private String nome; private int idade; public Cachorro(String aNome){ this.nome = aNome; this.idade = 0; } public String getNome(){return this.nome;} public int getIdade(){return this.idade;} public void aumentaIdade(){this.idade++;} public String fazBarulho(){ return "au au"; } @Override public String toString(){ String res = ""; res += "Classe: Cachorro\n"; res += "Nome: " + this.nome + "\n"; res += "Idade: " + this.idade + "\n"; res += "Barulho: " + this.fazBarulho() + "\n"; return res; } }
class Gato{ private String nome; private int idade; public Gato(String aNome){ this.nome = aNome; this.idade = 0; } public String getNome(){return this.nome;} public int getIdade(){return this.idade;} public void aumentaIdade(){this.idade++;} public String fazBarulho(){ return "Miau"; } @Override public String toString(){ String res = ""; res += "Classe: Gato\n"; res += "Nome: " + this.nome + "\n"; res += "Idade: " + this.idade + "\n"; res += "Barulho: " + this.fazBarulho() + "\n"; return res; } }
class Pato{ private String nome; private int idade; public Pato(String aNome){ this.nome = aNome; this.idade = 0; } public String getNome(){return this.nome;} public int getIdade(){return this.idade;} public void aumentaIdade(){this.idade++;} public String fazBarulho(){ return "Quaaack"; } @Override public String toString(){ String res = ""; res += "Classe: Pato\n"; res += "Nome: " + this.nome + "\n"; res += "Idade: " + this.idade + "\n"; res += "Barulho: " + this.fazBarulho() + "\n"; return res; } }
class Teste{ static public void main(String[] args){ Cachorro cachorro = new Cachorro("Brutus"); Gato gato = new Gato("Chirriro"); Pato pato = new Pato("Donaldo"); System.out.println(cachorro); System.out.println(gato); System.out.println(pato); cachorro.aumentaIdade(); gato.aumentaIdade(); pato.aumentaIdade(); System.out.println(cachorro); System.out.println(gato); System.out.println(pato); } }
Poderemos fazer uma superclasse abstrata Animal
implementando os métodos que são comuns e definindo como abstrato o método que difere:
abstract class Animal{ private String nome; private int idade; public Animal(String aNome){ this.nome = aNome; this.idade = 0; } public String getNome(){return this.nome;} public int getIdade(){return this.idade;} public void aumentaIdade(){this.idade++;} abstract public String fazBarulho(); @Override public String toString(){ String res = ""; res += "Classe: " + this.getClass().getSimpleName() + "\n"; res += "Nome: " + this.nome + "\n"; res += "Idade: " + this.idade + "\n"; res += "Barulho: " + this.fazBarulho() + "\n"; return res; } }
class Cachorro extends Animal{ public Cachorro(String aNome){ super(aNome); } @Override public String fazBarulho(){ return "au au"; } }
class Gato extends Animal{ public Gato(String aNome){ super(aNome); } @Override public String fazBarulho(){ return "Miau"; } }
class Pato extends Animal{ public Pato(String aNome){ super(aNome); } @Override public String fazBarulho(){ return "Quaaack"; } }
import java.util.List; import java.util.ArrayList; class Teste{ static public void main(String[] args){ List<Animal> animais = new ArrayList<>(); animais.add(new Cachorro("Brutus")); animais.add(new Gato("Chirriro")); animais.add(new Pato("Donaldo")); for(Animal a: animais){ System.out.println(a); } for(Animal a: animais){ a.aumentaIdade(); } for(Animal a: animais){ System.out.println(a); } } }
Diferente de Python, na linguagem Java as classes podem ter apenas uma superclasse. Porém as classes podem ter multiplas interfaces
.
Interfaces são classes completamente abstratas (todos os métodos são abstratos) e sem nenhum atributo.
Nestes casos se diz que uma classe implementa a interface
.
Veja o exemplo de três classes completamente diferentes, mas que compartilham de um método: public void voa()
class Pato extends Animal{ public Pato(String aNome){ super(aNome); } @Override public String fazBarulho(){return "Qauaack";} public void voa(){ System.out.println("O Pato voa para o norte"); } }
class Aviao{ private String modelo; public Aviao(String aModelo){ this.modelo = aModelo; } public String getModelo(){return modelo;} public void voa(){ System.out.println("O Aviao voa levando pessoas"); } @Override public String toString(){ String res = ""; res += "Classe Aviao\n"; res += "Modelo: "+modelo+"\n"; return res; } }
class SuperMan{ public void voa(){ System.out.println("O SuperMan voa para salvar alguem"); } @Override public String toString(){ String res = ""; res += "Classe SuperMan\n"; return res; } }
class Teste{ static public void main(String[] args){ Pato pato = new Pato("Donaldo"); Aviao aviao = new Aviao("Jato"); SuperMan superMan = new SuperMan(); System.out.println(pato); System.out.println(aviao); System.out.println(superMan); pato.voa(); aviao.voa(); superMan.voa(); } }
Usando interfaces
podemos tirar proveito do polimorfismo para colocar os objetos na mesma lista.
interface Voavel{ public void voa(); }
class Pato extends Animal implements Voavel{ public Pato(String aNome){ super(aNome); } @Override public String fazBarulho(){return "Qauaack";} @Override public void voa(){ System.out.println("O Pato voa para o norte"); } }
class Aviao implements Voavel{ private String modelo; public Aviao(String aModelo){ this.modelo = aModelo; } public String getModelo(){return modelo;} @Override public void voa(){ System.out.println("O Aviao voa levando pessoas"); } @Override public String toString(){ String res = ""; res += "Classe Aviao\n"; res += "Modelo: "+modelo+"\n"; return res; } }
class SuperMan implements Voavel{ @Override public void voa(){ System.out.println("O SuperMan voa para salvar alguem"); } @Override public String toString(){ String res = ""; res += "Classe SuperMan\n"; return res; } }
import java.util.List; import java.util.ArrayList; class Teste{ static public void main(String[] args){ List<Voavel> voavels = new ArrayList<>(); voavels.add(new Pato("Donaldo")); voavels.add(new Aviao("Jato")); voavels.add(new SuperMan()); for(Voavel v: voavels){ System.out.println(v); } for(Voavel v: voavels){ v.voa(); } } }
.