Herança, Polimorfismo e Classes Abstratas em Java Disciplina: Programação Orientada a Objetos Prof. Ricardo Satoshi Oyakawa Herança em Java O que torna a Orientação a Objetos única é o conceito de herança. Herança é um mecanismo que permite que características comuns a diversas classes sejam fatoradas de uma classe base, ou superclasse. A partir de uma classe base, outras classes podem ser especificadas. Cada classe derivada ou subclasse apresenta as características (estrutura e métodos) da superclasse e acrescenta a elas o que for definido de particularidade para ela. 2 Herança em Java Sintaxe: [modificador] class NomeDaSuperclasse { // corpo da superclasse... } [modificador] class NomeDaSubclasse extends NomeDaSuperclasse { // corpo da subclasse... } extends - indica que está sendo criada uma nova classe que deriva de uma classe existente Classe existente - superclasse, classe base ou classe progenitora Nova classe - subclasse, classe derivada ou classe filha Em geral, as subclasses têm mais funcionalidade que sua superclasse. 3 Exemplo de Herança (Superclasse-Empregado.java) import java.text.*; public class Empregado { private String nome; private double salario; public Empregado (String n, double s){ nome = n; salario = s; } public void imprimir (){ System.out.println(nome + " " + formatarMoeda()); } 4 Exemplo de Herança (Superclasse-Empregado.java) public void aumentarSalario (double porPercentual){ salario *= 1 + porPercentual / 100; } public String formatarMoeda (){ NumberFormat nf = NumberFormat.getCurrencyInstance(); nf.setMinimumFractionDigits (2); String formatoMoeda = String.valueOf(nf.format(salario)); return formatoMoeda; } 5 Exemplo de Herança (Superclasse-Empregado.java) public static void main (String args []){ Empregado [] e = new Empregado [3]; e[0] = new Empregado ("Harry Hacker", 3500); e[1] = new Empregado ("Carl Cracker", 7500); e[2] = new Empregado ("Tony Tester", 3800); int i; for (i = 0; i < 3; i++) e[i].imprimir(); System.out.println("******************************"); for (i = 0; i < 3; i++){ e[i].aumentarSalario(10); e[i].imprimir(); } } } 6 Exemplo de Herança (Subclasse-Gerente.java) import java.text.*; public class Gerente extends Empregado { private String nomeSecretaria; public Gerente (String n, double s){ super (n, s); nomeSecretaria =" "; } public void aumentarSalario (double porPercentual){ //adiciona bonus de 20% ao valor do salario double bonus = 20; super.aumentarSalario(porPercentual + bonus); } 7 Exemplo de Herança (Subclasse-Gerente.java) public String getNomeSecretaria (){ return nomeSecretaria; } public void setNomeSecretaria (String nome){ nomeSecretaria = nome; } } 8 Exemplo de Herança Palavra-chave super refere-se a uma superclasse indica a chamada ao construtor da superclasse se a superclasse não contiver o construtor padrão e o construtor da subclasse não chamar nenhum outro construtor da superclasse explicitamente compilador java vai informar um erro Em um relacionamento de herança: é necessário apenas indicar as diferenças entre a subclasse e superclasse o reuso é automático é necessário redefinir métodos um dos 9 primeiros motivos para usar herança Exemplo de Herança Exemplo da subclasse Gerente: redefinição do método aumentarSalario ( ) para que ele funcione diferente para gerentes e empregados comuns esse método não tem acesso direto às variáveis de instância privados da superclasse, ou seja, esse método não pode alterar diretamente a variável de instância salario, embora cada objeto Gerente tenha uma variável de instância salario somente os métodos da classe Empregado têm acesso aos atributos de instância privados Resultado dessa redefinição para objetos da classe Gerente: Quando se dá a todos os empregados um aumento de 5%, os gerentes vão receber um aumento maior automaticamente 10 Exemplo de Herança (Classe Principal-GerenteTeste.java) public class GerenteTeste { public static void main (String args[]){ Gerente g = new Gerente ("Carl Cracker", 7500); g.setNomeSecretaria ("Harry Hacker"); Empregado [] e = new Empregado [3]; e[0] = g; e[1] = new Empregado ("Harry Hacker", 3500); e[2] = new Empregado ("Tony Tester", 3800); int i; for (i = 0; i < 3; i++) e[i].aumentarSalario(10); for (i = 0; i < 3; i++) e[i].imprimir(); System.out.println("O nome da secretaria do departamento e: " +g.getNomeSecretaria()); } } 11 Subclasses Para saber se a herança é adequada para um programa ter em mente que qualquer objeto que seja uma instância de uma subclasse precisa ser utilizável no lugar de um objeto que seja uma instância de superclasse objetos de subclasse são utilizáveis em qualquer código que use a superclasse um objeto de subclasse pode ser passado como argumento para qualquer método que espera um parâmetro de superclasse um objeto de superclasse não pode geralemente ser atribuído a um objeto de subclasse g = e[i]; //erro Os atributos só podem ser adicionados, e não removidos, os objetos de uma subclasse herdados têm, pelo menos, tantos atributos de dados quanto os objetos de superclasse 12 Recomendações de Projeto para Herança 1. 2. 3. Coloque métodos e atributos comuns na superclasse Use herança para modelar uma relação de “estar contido em” (um objeto da subclasse é um (a) objeto da superclasse) Exemplo: classe Empreiteiro Não use herança a menos que todos os métodos herdados façam sentido Exemplo: classe Feriado class Feriado extends Day { . . .} - Um dos métodos públicos da classe Day é avancarData ( ), que permite transformar dias feriados em dias normais, de modo que não é um método apropriado para se fazer com dias feriados. Feriado natal; natal.avancarData(10); // neste caso, um feriado é um 13 dia mas não um Day (objeto) Recomendações de Projeto para Herança 4. Use polimorfismo, não informação de tipo - Sempre que você encontrar código do tipo if (x é o tipo 1) acao1(x); else if (x é o tipo 2) acao2(x); - Pense em Polimorfismo - acao1 e acao2 representam um conceito comum? Caso afirmativo, faça o conceito virar um método de uma superclasse. Assim poderá simplesmente chamar: x.acao( ); - o ponto a ser obervado aqui é que o código para usar métodos polimórficos é muito mais fácil de se manter e estender que um código que use múltiplos testes de tipos de dados. 14 Polimorfismo Comunicação entre objetos: envio de mensagens ao enviar uma mensagem que pede para uma subclasse aplicar um método usando certos parâmetros a subclasse verifica se ela tem ou não um método com esse nome e com exatamente os mesmos parâmetros. Se tiver, usa-o. caso contrário: a superclasse torna-se responsável pelo processamento da mensagem e procura por um método com esse nome e esses parâmetros. Se encontrar, chama esse método. Uma das regras fundamentais da herança: um método definido em uma subclasse com o mesmo nome e mesma lista de parâmetros que um método em uma de suas classes antecessoras oculta o método da classe ancestral a partir da 15 subclasse Polimorfismo Exemplo: o método aumentarSalario () da classe Gerente é chamado em vez do método aumentarSalario () da classe Empregado quando se envia uma mensagem aumentarSalario ao objeto Gerente Polimorfismo: é a capacidade de um objeto decidir que método aplicar a si mesmo. embora a mensagem possa ser a mesma - os objetos podem responder diferentemente aplicado a qualquer método que seja herdado de uma superclasse 16 Polimorfismo a chave para fazer polimorfismo: ligação tardia (late binding) ou ligação dinâmica: o compilador não gera o código para chamar um método em tempo de compilação em vez disso, cada vez que se aplica um método a um objeto, o compilador gera código para calcular que método deve ser chamado, usando informações de tipo do objeto o mecanismo de chamada de método tradicional é chamado ligação estática: determinada em tempo de compilação 17 Classes Abstratas Ao subir na hierarquia de heranças, as classes se tornam mais genéricas e, provavelmente mais abstratas Em algum ponto, a classe ancestral se torna tão geral que acaba sendo vista mais como um modelo para outras classes do que uma classe com instâncias específicas que são usadas Uma classe abstrata não pode ser instanciada, ou seja, não há objetos que possam ser construídos diretamente de sua definição. Classes abstratas correpondem a especificações genéricas, que deverão ser concretizadas em classes derivadas (subclasses). Sintaxe: abstract class NomeDaSuperclasse { // corpo da classe abstrata... } 18 Classes Abstratas Exemplo: Sistema de mensagens eletrônicas que integre e-mail, fax e correio de voz Seguindo os princípios OO o programa vai precisar de classes como MensagemTexto, MensagemVoz e MensagemFax Mensagem MensagemTexto MensagemVoz MensagemFax 19 Classes Abstratas Por que se preocupar com um nível tão alto de abstração? Tornar o projeto das classes mais claro Uma das chaves da POO é entender como combinar e reunir operações comuns num nível mais alto na hierarquia de herança Por exemplo: todas as mensagens têm um método comum denominado enviar ( ) é fácil perceber como reproduzir uma mensagem de voz enviando-a ao alto falante, ou uma mensagem de texto exibindo-a em uma janela de texto, ou uma mensagem de fax imprimindo-a ou mostrando-a em uma janela gráfica 20 Classes e Métodos Abstratos Como implementar o método enviar ( ) na superclasse Mensagem? A resposta é que não se pode Em Java, usa-se a palavra-chave abstract para indicar que um método não pode ser especificado nessa classe. Para aumentar a clareza, uma classe com um ou mais métodos abstratos precisa, ela mesma, ser declarada abstrata public abstract class Mensagem { … public abstract void enviar ( ); } 21 Classes e Métodos Abstratos Além dos métodos abstratos, as classes abstratas podem ter dados e métodos concretos Por exemplo, a classe Mensagem pode armazenar o remetente da mensagem e ter um método concreto que retorne o nome do remetente public abstract class Mensagem { private String remetente; public Mensagem (String r) { remetente = r;} public abstract void enviar ( ); public String getRemetente( ) { return remetente;} } } 22 Classes e Métodos Abstratos Um método abstrato promete que todos os descendentes não abstratos dessa classe abstrata irão implementar esse método abstrato Os métodos abstratos funcionam como uma espécie de guardador de lugar para métodos que serão posteriormente implementados nas subclasses Uma classe pode ser declarada como abstrata mesmo sem ter métodos abstratos 23 Classes e Métodos Abstratos public class MensagemTexto extends Mensagem { private String texto; public MensagemTexto(String r, String t) { super (r); texto = t; } public void enviar ( ){ System.out.println(texto); } } - Observe que foi preciso fornecer somente uma definição concreta do método abstrato enviar( ) na classe MensagemTexto 24