Aula 7
“Apresentar herança no contexto da linguagem Java”
Herança de classes é o processo de se criar uma classe (a subclasse) a partir de outra já existente (a superclasse), herdando as suas características (comportamento e estado).
class Individuo { //superclasse de Aluno e Professor protected String nome; public String getNome() { return nome; } public Individuo(String nome){ this.nome = nome; } } class Aluno extends Individuo { //subclasse de Individuo //... public void fazEEntregaRelatorio() { /*codigo*/ } } class Professor extends Individuo { //subclasse de Individuo //... public void corrigeRelatorios() { /*codigo*/ } }
public
, protected
e package-protected
(sem modificador).Object
class Aluno extends Individuo { int matricula; //definir novas variáveis public void umCoisaQueOAlunoFaz() { //definir novos métodos System.out.println(getNome()); //chamar métodos herdados nome = "novo nome"; //Usar as variáveis herdadas normalmente } public String getNome() { //sobrescrever métodos return "Aluno " + super.getNome() //super usado para desambiguar //chamadas à superclasse } //tudo mais que se pode fazer numa classe comum (última aula) }
public static void imprimeNome(Individuo ind) { //ind pode ser Aluno, Professor ou Individuo System.out.println (ind.getNome()); }
Aluno aluno = new Aluno("João"); Professor prof = new Professor("José"); imprimeNome(aluno); imprimeNome(prof);
public void fazAlgo(Individuo ind) { //só posso usar a interface de Individuo em ind ind.fazEEntregaRelatorio(); //gera erro mesmo se passarmos um Aluno }
O contrário não é válido! (não se pode tratar um objeto de uma classe como objeto de sua subclasse).
“Um aluno é um indivíduo, mas um indivíduo nem sempre é um aluno”.
Individuo ind = new Aluno("João"); //ok Individuo ind2 = new Professor("João"); //ok Aluno aluno = new Indivíduo("José"); //gera erro
class Relatorio { //... public Relatorio(double qualidade, double originalidade, Aluno aluno) { /* ...*/ } //... }
AlunoSafoPreguicoso alunoS = new AlunoSafoPreguicoso('João'); AlunoEsforcado alunoE = new AlunoEsforcado('Manuel'); Relatorio rela1 = new Relatorio(0.6, 0.7, alunoS) Relatorio rela1 = new Relatorio(0.6, 0.7, alunoE)
Permite ‘converter’ um objeto mais geral (superclasse) para um objeto mais específico (subclasse).
Individuo ind = new Professor("João"); // casting implicito Professor prof = (Professor) ind; // diz ao compilador que ind é um Professor Aluno aluno = (Aluno) ind; //gera erro de runtime pois ind não é um Aluno.
Como em C, os tipos nativos podem sofrer conversão com casting.
double d = 1.23; float f = 1.43f + (float) d
class Animal { public static void testClassMethod() { System.out.println("The class method in Animal."); } public void testInstanceMethod() { System.out.println("The instance method in Animal."); } }
class Cat extends Animal { public static void testClassMethod() { System.out.println("The class method in Cat."); } public void testInstanceMethod() { System.out.println("The instance method in Cat."); } public static void main(String[] args) { Cat myCat = new Cat(); Animal myAnimal = myCat; Animal.testClassMethod(); myAnimal.testInstanceMethod(); } }
O controle de acesso aos métodos pode ser “ampliado”, mas nunca restrito.
class SuperClasse { protected void umMetodo(){/*...*/} public void outroMetodo(){/*...*/} } class SubClasse extends SuperClasse { public void umMetodo(){/*...*/} //ok - ampliado private void outroMetodo(){/*...*/} // erro! - não pode ser restrito }
A keyword super
(de forma semelhante ao @this@) pode ser usada para:
class AlunoSafoPreguicoso extends Aluno public AlunoSafoPreguicoso(String nome, RelaQueue queue) { super(nome, queue); } }
super()
(sem parâmetros) em todos os construtores que não invocarem explicitamente super
Podemos impedir que classes sejam estendidas e métodos sejam sobreescritos com o keyword final
.
final class SemSubClasses { /*...*/ } class UmaClasse { final void semOverriding() { /* ... */ } }
Classes abstratas:
public abstract class Aluno { //... public abstract float getInteligencia(); public abstract float getDedicacao(); public String getNome() { return nome; } } public class AlunoEsforcado { //... public float getInteligencia() { return 0.5; } public float getDedicacao(){ return 1; } }
Em uma linha: são como classes abstratas, com todos métodos públicos abstratos, e com herança múltipla.
public interface GroupedInterface extends Interface1, Interface2, Interface3 { double E = 2.718282; // constante void doSomething (int i, double x); //assinatura de método int doSomethingElse(String s); //assinatura de método }
public interface ComComportamento { double getInteligencia(); double getDedicacao(); } public class AlunoInteligente extends Aluno implements ComComportamento { //... double getInteligencia() {/*implementação*/}; double getDedicacao(){/*implementação*/}; } public class Cachorro implements ComComportamento { /*...*/}
Pode-se usar o polimorfismo e tratar a interface como um tipo.
static void dizSeEhInteligente(ComComportamento obj) { if (obj.getInteligencia() > 0.9) System.out.println ("Isto é um gênio!"); } static void main(String[] args) { AlunoInteligente aluno = new AlunoInteligente('Joao'); Cachorro pet = new Cachorro('Pluto') dizSeEhInteligente(pet); dizSeEhInteligente(aluno); }
Conjuntos de classes relacionadas. Ex.: java.io
, java.util
.
package-protected
e @public@).package graphics; public class Retangle {/*disponível fora do pacote*/} class RetanglePainter {/*só disponível no pacote*/}
Usando uma classe dentro de um pacote:
java.util.Random r = new java.util.Random(); //ou import java.util.Random; java.util.Random r = new java.util.Random(); //pode também importar todas as classes (públicas) de um package import java.util.*;