Conceitos Avançados

LPOO 1 - Java


Prof. Rodrigo Noll @ IFRS Canoas



Versão para impressão

Arrays

Exercícios


LPOO 1 - Java

Arrays

    Um array é sempre um objeto e, portanto, uma referência. Para se utilizar um array, é necessário “new”:

                            int idades[] = new int[10];
                        
    Para se atribuir um valor:

                                    idades[5] = 10;
                                
    E como resultado, temos:
ÍNDICE 0 1 2 3 4 5 6 7 8 9
VALOR 0 0 0 0 0 10 0 0 0 0
    O código acima altera a sexta posição do array.
    • No Java, os índices do array vão de 0 a n-1, onde n é o tamanho dado no momento em que você criou o array
    • Para tipos primitivos é atribuído o valor padrão para todas as posições, caso sejam objetos, ficam nulos (null).

Declaração de Arrays (Vetores)

Em Java, se tentar acessar uma posição fora do tamanho do array, a aplicação irá lançar uma exceção.

public class MeuArray {
	public static void main(String[] args) {
		int idades[] = new int[10];
		idades[5] = 10;
		System.out.println(idades[5]);
		idades[10] = 10;
	}
}
                        

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10
	at br.edu.ifrs.canoas.java.arrays.MeuArray.main(MeuArray.java:9)
                        

Declaração de Arrays (Vetores)

Para criar um Array de Objetos, use a estrutura abaixo.

public class ContaTest {
	Conta minhasContas[];
	@Before
	public void setup() {
		minhasContas = new Conta[10];
	}
	@Test
	public void testaArrayDeContas() {
		minhasContas[0] = new Conta();
		//Até aqui só um objeto foi criado do array de 10.
		//Todos os outros espaços são null
		minhasContas[0].saldo = 100;
		minhasContas[0].deposita(50);
		assertEquals("O saldo deve ser 100+50=150",
			      150, minhasContas[0].saldo,0);
	}
}
                        

Percorrendo uma array

Todo array tem o atributo length que define seu tamanho

public class AlgumaClasse {
    public static void main(String[] args) {
        int[] idades = new int[10];
        System.out.println("Preenchendo da forma convencional");

        for (int i = 0; i < idades.length; i++) {
            idades[i] = i * 10;
        }

        System.out.println("Imprimindo com enhanced-for: foreach");
	for (int idade : idades) {
		System.out.println(idade);
	}
    }
}
                        

Exercício

Crie a estrutura abaixo e faça com que passe nos testes unitários disponíveis em https://github.com/aula-java/arrays-1 (você não pode alterar os testes unitários).

Conceitos Avançados

Arrays

Exercícios


LPOO 1 - Java

Encapsulamento

Exercícios


LPOO 1 - Java

Controle de Acesso

Java implementa Modificadores de Acesso para restringir o acesso dos membros de uma classe por outras classes.

Quando declaramos:

                            class Conta {
                                private double saldo;
                                private double limite; //Só é relevante para conta
                                // ...
                            }
                            
Os atributos de Conta são apenas visíveis apenas pelos objetos da Conta. Mais ninguém pode modificar seus atributos.

Controle de Acesso

  • O controle de acesso é implementado em Java por Modificadores de Acesso (ou visibilidade) e se aplica a atributos e métodos.
    • private
    • (default)
    • protected
    • public

  • Na orientação a objetos, é prática quase que obrigatória proteger atributos de classe com private.
    • Desta forma, toda conversa de um objeto com outro é feita por troca de mensagens, isto é, acessando seus métodos

Controle de Acesso

Private Default Protected Public
Mesma classe sim sim sim sim
Subclasse mesmo pacote não sim sim sim
Classe mesmo pacote não sim sim sim
Subclasse pacote diferente não não sim sim
Classe pacote diferente não não não sim

Controle de Acesso

Encapsulamento

  • Encapsular é esconder todos os membros (atributos e métodos) de uma classe
    • Encapsular é fundamental para que seu sistema seja suscetível a mudanças: não precisaremos mudar uma regra de negócio em vários lugares, mas sim em apenas um único lugar, já que essa regra está encapsulada.

  • O conjunto de métodos públicos de uma classe é também chamado de interface da classe, pois esta é a única maneira a qual você se comunica com objetos dessa classe.

Encapsulamento

Exemplo:

class Cliente {
    private String nome;
    private String endereco;
    private String cpf;
    private int idade;
    public void mudaCPF(String cpf) {
        if (validaCPF(cpf))
        	this.cpf = cpf;
    }
    private boolean validaCPF(String cpf) {
        // série de regras aqui, falha caso não seja válido
    }
    // ..
}
                        
Se alguém tentar criar um Cliente e não usar o mudaCPF para alterar um cpf diretamente, vai receber um erro de compilação, já que o atributo CPF é privado

Getters e Setters

  • Para acessar atributos privados, utilizam-se métodos Getters e Setters.

  • Você só deve criar um getter ou setter se tiver a real necessidade.

  • No caso de atributos booleanos, pode-se usar no lugar do get o sufixo is.

  • Ex.: isLigado(): boolean

Construtores

Quando usamos a palavra chave new, estamos construindo um objeto.
Sempre quando o new é chamado, ele executa o construtor da classe.

class Conta {
    int numero;
    Cliente titular;
    double saldo;
    double limite;
    // construtor
    public Conta(Cliente titular) {
        this.titular = titular;
        System.out.println("Construindo uma conta.");
    }
    public Conta (int numero, Cliente titular) {
        this(titular); // chama o construtor que foi declarado acima
        this.numero = numero;
    }
    // ..
}
                            

Atributos de Classe


class Conta {
    private int totalDeContas;
    //...
    Conta() {
        this.totalDeContas = this.totalDeContas + 1;
    }
}
                            
  • Quando criarmos duas contas, qual será o valor do totalDeContas de cada uma delas?
    • Um
  • Se modificarmos para static:
  • 
    private static int totalDeContas;
                                
    • Ele passa a não ser mais um atributo de cada objeto, e sim um atributo da classe, a informação fica guardada pela classe, não é mais individual para cada objeto.

Atributos de Classe

  • Para acessarmos um atributo estático, não usamos a palavra chave this, mas sim o nome da classe:
  • 
    class Conta {
        private static int totalDeContas;
        //...
        Conta() {
            Conta.totalDeContas = Conta.totalDeContas + 1;
        }
    }
                                
  • Já que o atributo é privado, precisamos de um getter para ele!

public static int getTotalDeContas() {
        return Conta.totalDeContas;
}
                            

int total = Conta.getTotalDeContas();
                            

Conceitos Avançados

Encapsulamento

Exercícios


LPOO 1 - Java

Herança e Reescrita

Exercícios


LPOO 1 - Java

Herança

Observe os códigos abaixo:

class Funcionario {
    String nome;
    String cpf;
    double salario;
    //outros métodos
}
                            

Qual o problema?

Herança

E pode ser resolvido em Java utilizando o herança:
Gerente [subclasse] herda de Funcionario[superclasse]

Herança

Que pode ser traduzido da seguinte forma:

class Gerente extends Funcionario {
    int senha;
    int numeroDeFuncionariosGerenciados;

    public boolean autentica(int senha) {
        if (this.senha == senha) {
             return true;
        } else {
             return false;
        }
    }
    // setter da senha omitido
}                         

Herança

Exercício

  1. Clone o projeto https://github.com/aula-java/heranca-1
  2. Remova toda a repetição de código através do mecanismo de herança. Faça o teste unitário passar.
  3. Adicione o método abaixo na classe Gerente:
  4. 
                            public String getNome() {
                                return "Gerente " + nome;
                            }
                                
    • Para funcionar, altere a visibilidade do atributo nome da superclasse de privado (private) para protegido (protected)
    • Corrija o teste unitário para que ele passe.
  5. Crie uma classe Diretor que herda de Funcionario.
    • Adicione o método getNome que retorna "Diretor " + nome
    • Crie um TestCase de Diretor para verificar se o nome está correto.

Reescrita

Se quisermos que todos os funcionários tenham implementado um método que os bonifique, mas com valores diferentes para cargos, devemos utilizar o mecanismo de reescrita.

class Funcionario {
	protected String nome;
	protected String cpf;
	protected double salario;

	public double getBonificacao() {
		return this.salario * 0.10;
	}
	// métodos
}
                        
Da forma como está, o gerente, herdando o método de funcionário, terá a bonificação de 10%.

Reescrita

Vamos testar?
Adicione o código abaixo no teste unitário em GerenteTest.

@Test
public void testBonificacao() {
	gerente.setSalario(1000);
	assertEquals("Com o salario de 1000, a bonificacao eh 100",
                            100, gerente.getBonificacao(),0);
}
                        
Da forma como está, o gerente, herdando o método de funcionário, terá a bonificação de 10%.

Reescrita

Para que o gerente tenha uma bonificação diferente, basta que a classe Gerente tenha o método com o mesmo nome – getBonificacao() – da classe Funcionario.

class Gerente extends Funcionario {
	int senha;
	int numeroDeFuncionariosGerenciados;

	public double getBonificacao() {
		return this.salario * 0.15;
	}
	// ...
}
                        
Não se esqueça de alterar a visibilidade do atributo salario (protected)
Altere o teste de GerenteTest para que reflita a reescrita do método.

Conceitos Avançados

Herança e Reescrita

Exercícios


LPOO 1 - Java

Polimorfismo

Exercícios


LPOO 1 - Java

Polimorfismo

  • Polimorfismo = múltiplas formas.
    • O objeto não fica mudando, o que muda é como nos referenciamos a ele.

  • Múltiplas formas de fazer algo.
    • Trabalha com a reescrita de métodos herdados de uma superclasse.
    • Reescrita de Método: Embora semelhantes, esses métodos diferem na forma de implementação. Dessa maneira podem existir dois ou mais métodos com a mesma nomenclatura mas com implementações diferentes.

Polimorfismo

  • Capacidade de um objeto tomar diferentes formas.
    • Ao estendermos ou especializarmos uma classe, não perdemos compatibilidade com a superclasse.
    • Exemplo: a sub-classe Ave de Animal é, além de outras coisas, um tipo de Animal.
  • Permite a manipulação de instâncias de classes diferentes (mas que herdem de uma mesma classe ancestral) de forma unificada.

Polimorfismo

Polimorfismo

Como saber qual método invocar para calcular o salário de cada funcionário?
A decisão sobre qual o método que deve ser selecionado, de acordo com o tipo da classe derivada, é tomada em tempo de execução, através do mecanismo de ligação tardia.

Funcionario funcionario1 = new Funcionario ();
Funcionario funcionario2 = new Gerente ();
Funcionario funcionario3 = new Desenvolvedor ();
                            
Resposta:

Cálculo padrão...
Cálculo padrão...
Cálculo com horas extras...

                        

Conceitos Avançados

Polimorfismo

Exercícios


LPOO 1 - Java

Classes Abstratas

Exercícios


LPOO 1 - Java

Classes Abstratas

  • A boa prática de programação diz que o código comum a diversas classes deve ser colocado em uma classe-base (Template pattern)

  • Esta classe nunca será instanciada diretamente, e seu código só poderá ser utilizado através de herança

  • Então, esta classe deve ser criada como sendo abstrata (abstract)

Classes Abstratas

  • Representam um conceito abstrato (modelo)
  • Não deve ser instanciada (gerar um objeto)
  • Servem apenas para permitir a derivação de novas classes
  • Identificamos uma classe como abstrata pelo palavra reservada abstract

  • Exemplo:

public abstract class nomeClasse { ... }
                                

Classes Abstratas

Podem conter:

  • Atributos de instância
  • Atributos de classe (static)
  • Construtores
    • chamados através de super pelas classes filhas
  • Métodos
    • Concretos (de instância ou classe)
    • Abstratos (apenas de instância)

Classes Abstratas

    Podem conter métodos concretos:
    • Usados através das subclasses

    Podem conter métodos abstratos:
    • Identificados pela palavra reservada abstract
    • Nunca serão chamados
    • Não possuem implementação (definem apenas a interface)
    • Devem ser obrigatoriamente implementados na classe filha
    • Padronização no comportamento das classes filhas
    • Não podem ser declarados como private
    • Não podem ser declarados como final
    • Não podem ser declarados como static
    • Herdados pelas classes filhas

Exemplo: Classes Abstratas


public class abstract Funcionario {
	protected String nome;
	protected String cpf;
	protected double salario;

	public Funcionario(){};

	public Funcionario(String nome, String cpf, double salario){
		this.nome = nome;
		this.cpf = cpf;
		this.salario = salario;
	}

	public abstract void exibirDados();
	public abstract void calcularPagamento();

	public void setNome(String nome){
		this.nome = nome;
	}
	public String getNome(String nome){
		return this.nome;
	}
}
                            

Classes Abstratas

Se não podemos instanciar uma classe abstrata, para que ela serve?
  • Quando não estamos interessados em uma referência genérica da classe como funcionário, que pode ser qualquer posição dentro de uma empresa.
  • Quando pretendemos criar um comportamento padrão (métodos) em uma superclasse que:
    • Permita reescrever alguns métodos específicos da subclasse (se necessário). Esses métodos são definidos na superclasse, mas não podem ser usados por objetos dela.
    • Obriga a definir alguns métodos específicos na subclasse (herda a responsabilidade de implementar métodos - todas subclasses devem implementar todos os métodos abstratos da superclasse).

Classes Abstratas

  • Uma classe que estende uma classe normal também pode ser abstrata! Ela não poderá ser instanciada, mas sua classe pai sim!
  • Uma classe abstrata não precisa necessariamente ter métodos abstratos.

Exercício

  1. Altere o projeto sobre Polimorfismo.
  2. Torne a classe Funcionário abstrata
  3. Corrija os testes unitários
  4. Transforme o método Funcionario.setSalario() como abstrato.
  5. Faça todas as alterações no código para que funcione os testes unitários
  6. Transforme o método Funcionario.getBonificacao() como abstrato.
  7. O que aconteceu? Qual a diferença com relação a alteração do método setSalario()? Escreva no código a discussão.

Conceitos Avançados

Classes Abstratas

Exercícios


LPOO 1 - Java

Interfaces

Exercícios


LPOO 1 - Java

Interfaces

  • São classes abstratas “puras”
  • São “contratos” que definem o que a classe poderá fazer, mas não dizem nada sobre a maneira como será feito
  • Implementação fica a cargo das classes que utilizam a interface
  • Assim como a abstrata não pode ser instanciada
  • Ela só expõe o que o objeto deve fazer, e não como ele faz, nem o que ele tem. Como ele faz vai ser definido em uma implementação dessa interface.

Interfaces


public interface Tributavel {

	void calculaTributos();

	default void log(String str){
		System.out.println("Log:"+str);
	}
}
                        

Podemos ter métodos concretos em interfaces a partir do Java 8 usando o modificador default. Eles serão "herdados" por todos que implementarem essa interface.
Esse recurso, chamado default method, permite evoluir uma interface sem quebrar compatibilidade.

Interfaces

Aplicações

  • Definir um comportamento que pode ser implementado por qualquer classe, independentemente da sua hierarquia de classes.

  • Captura de similaridades entre classes não relacionadas, sem ser obrigado a criar artificialmente uma relação de herança entre elas.

  • Declaração de métodos que uma ou mais classes esperam implementar

Interfaces

Características

  • Diferença entre classes abstratas e interfaces: é que uma classe filha pode herdar de apenas uma única classe (abstrata ou não) enquanto qualquer classe pode implementar várias interfaces simultaneamente

  • Mecanismo “simplificado” de implementação de herança múltipla em Java

  • Interfaces podem ser úteis para implementação de bibliotecas de constantes (pois todos os atributos devem ser declarados como static e final)

Interfaces

Criação

  • Declaradas através da palavra-chave interface e o modificador de acesso public

  • Não tem construtor

  • Não tem variáveis de instância (a não ser constantes estáticas)

  • Todos os métodos são abstratos e públicos (a classe que implementa a interface deve implementar todos os métodos definidos na interface)

  • Não pode ter métodos estáticos

Interfaces

  • Uma classe que implementar a interface deve implementar todos os métodos definidos na interface

  • Uma classe pode implementar interfaces múltiplas. Ex: class Tile extends Rectangle implements Cloneable, Comparable

  • Uma interface pode estender outras interfaces

  • Uma interface não pode implementar outras interfaces

Conceitos Avançados

Interfaces

Exercícios


LPOO 1 - Java

Conceitos Avançados

Exercícios: Arrays, Encapsulamento, Herança e Reescrita, Polimorfismo, Exercícios e Exercícios


LPOO 1 - Java