Herança, Polimorfismo, Classes e Métodos Abstratos

Prática em laboratório

Objetivos:

Entender e verificar o uso de técnicas de reuso de software através de herança

Criar e utilizar classes e métodos abstratos

Entender e verificar o uso de polimorfismo

1. Herança


A herança proporciona o reuso de software, quer dizer: novas classes são criadas a partir de outras já existentes, absorvendo atributos e
comportamentos e adicionando os seus próprios.

No entanto, atenção: nem todos os membros da classe base são obrigatoriamente acessíveis na classe derivada. Isto dependerá
dos atributos de acesso do membro. Portanto, lembre sempre dos atributos de acesso:

Em caso de dúvida de como utilizá-los, verifique as regras abaixo:

E algumas exceções:


Exercício 1: Herança

Crie um projeto para a aula de hoje. Dada a seguinte classe Circulo, que possui um objeto Ponto como atributo, implemente uma nova classe CirculoColorido utilizando herança. Esta nova classe apresenta o mesmo comportamento de Circulo, mas possui a capacidade adicional de manter a informação da cor de desenho do traçado do círculo e uma cor interna para o preenchimento da figura geométrica. A modelagem em UML e o código original da classe Circulo são apresentados a seguir para ajudá-lo na tarefa. Crie vários objetos e teste a chamada dos métodos.

public class Ponto {
    private double x;
    private double y;
    public Ponto(double x, double y) {
        this.x = x;
        this.y = y;
    }
    public void setX (double xVal) { x = xVal; }
    public void setY (double yVal) { y = yVal; }
    public double getX() { return(x); }
    public double getY() { return(y); }
    public String toString() {
         String str = "(" + x + "," + y + ")";
         return str;
    }
}
 
public class Circulo {
   private Ponto centro;
   private double raio; 
   public Circulo(double x, double y, double r) {
      if (x < 0) x = 0;
      if (y < 0) y = 0;
      Centro = new Ponto(x,y);
      if (r > 0) raio = r;
      else raio = 1;
   }
   public void mover(double x, double y) {
      centro.setX(x);
      centro.setY(y);
   }
   public void aumentar() {
      raio++;
   }
   public void diminuir() {
      raio--;
   }
   public double getX() {
      return centro.getX();
   }
   public double getY() {
      return centro.getY();
   }
   public double getRaio() {
      return raio;
   }
}


 

2. Polimorfismo


Polimorfismo é a característica única de linguagens orientadas a objetos que permite que diferentes objetos respondam a mesma mensagem cada um a sua maneira.

Em termos de programação, polimorfismo representa a capacidade de uma única referência invocar métodos diferentes, dependendo do seu conteúdo.

Assim, usa-se uma referência da superclasse para armazenar referências para instâncias de subclasses. Entretanto, através dessa “referência genérica” só é possível acessar os métodos das subclasses que pertençam à interface comum com a superclasse.

Quando referências de uma superclasse são utilizadas para referenciar instâncias de subclasses, a compilação fará a checagem pelos tipos da referência. Na hora da execução, porém, o que conta é a classe a qual pertence a instância referenciada. Esse mecanismo que permite ao Java decidir em tempo de execução qual o método que será ativado em função da classe a qual pertence a instância referenciada é chamado de ligação dinâmica.

O fato de Java implementar ligação dinâmica é que permite que o mesmo explore a característica do polimorfismo. Explorando esta característica é possível construir algoritmos genéricos que trabalham com as referências para uma superclasse, mas que se aplicam as subclasses sem a necessidade de testes para determinar o tipo de instância que está sendo referenciada.

Teste o funcionamento do polimorfismo da seguinte maneira:

 

1.     Olhe a classe chamada Teste que implementa o método main() e possui os comandos abaixo.

Professor prof1 = new ProfDE("Joao", 1, 1123.56);
Professor prof2 = new ProfHorista("Jose", 3, 14, 12.5);
ProfDE prof3 = new Professor ("Maria", 2, 14);
Professor profSuper;
ProfDE profSub;
ProfDE prof4 = new ProfDE("Jose", 3, 1500.00);
profSuper = prof4;
profSub = profSuper;
profSub = (ProfDE) profSuper;
 
System.out.println(prof1.getSalario());
System.out.println(prof2.getSalario());     

2.     Ao tentar compilar o programa, você verá que alguns comandos estarão com erro. Tente entender porque estes erros ocorreram. Depois, corrija estes erros ou elimine os comandos.

 

3.     Uma solução para criar e manipular uma lista de professores utilizando um ArrayList é criar dois objetos, um para cada tipo de professor. Teste esta solução executando TestaProfessor. Depois, altere esta solução para utilizar polimorfismo e declarar somente um ArrayList de Professor. A saída do programa deve continuar a mesma!!

 

4.     Agora vamos trabalhar com polimorfismo de método. Inicialmente, altere a classe Professor para que também implemente o método getSalario(). Desta forma, não será mais necessário testar pelo tipo de objeto que está armazenado dentro do ArrayList, podendo-se simplesmente utilizar p.getSalario(). Veja a seguir como fazer estas alterações.

public class Professor {
   private String nome;
   private int matricula;
   private int cargaHoraria;
   ...
   public double getSalario() { return 0; }
}
...
System.out.println("Salário dos Professores:");
for(Professor p : cadProfessor) {
      System.out.println(p.getNome() + " " + p.getSalario());
}
      

 

5.     Observe que na prática nunca iremos instanciar um objeto Professor e que o método getSalario() desta classe não possui nenhuma função. Portanto, altere a classe Professor e o método getSalario() para que sejam abstratos. Depois execute o programa e veja como tudo continua funcionando normalmente!


 


Exercício 2: Polimorfismo

Um sistema de cadastro de clientes de uma empresa guarda informações sobre nomes, endereços e telefones. Além disso, caso o cliente seja uma pessoa física, seu número de CPF é armazenado e, caso o cliente seja uma pessoa jurídica, seu CNPJ e nome de fantasia da empresa devem ser guardados. A qualquer momento deve ser possível imprimir todos dados de um determinado cliente. Altere a modelagem a seguir e implemente as classes necessárias em Java utilizando os conceitos de polimorfismo e classes abstratas (não é necessário implementar o cadastro completo de clientes).

 


 
  Obs.: Esta aula prática foi adaptada do material dos professores Marcelo Cohen, Bernardo Copstein,Julio P. Machado e Isabel Manssour.