LP II
Professor: Wilton Souza
Controlando o acesso
Um dos problemas mais simples que temos no nosso
sistema de contas é que a função saca permite sacar
mesmo que o limite tenha sido atingido.
A seguir você pode lembrar como está a classe
Conta:
Controlando o acesso
class Conta {
int numero;
Cliente titular;
double saldo;
void saca(double quantidade) {
[Link] = [Link] - quantidade;
}
}
Controlando o acesso
A classe a seguir mostra como é possível ultrapassar o limite
usando o método saca:
class TestaContaEstouro1 {
public static void main(String args[]) {
Conta minhaConta = new Conta();
[Link] = 1000.0;
[Link](50000);
}
}
Controlando o acesso
Podemos incluir um if dentro do nosso método
saca() para evitar a situação que resultaria em uma
conta em estado inconsistente, com seu saldo abaixo
do limite.
Apesar de melhorar bastante, ainda temos um
problema mais grave: ninguém garante que o usuário
da classe vai sempre utilizar o método para alterar o
saldo da conta.
Controlando o acesso
class TestaContaEstouro2 {
public static void main(String args[]) {
Conta minhaConta = new Conta();
[Link] = -200;
}
}
Controlando o acesso
Para evitar essa situação basta declarar que os
atributos não podem ser acessados de fora da classe
através da palavra chave private (Modificador de
acesso):
class Conta {
private double saldo;
// ...
}
Controlando o acesso
Marcando um atributo como privado, fechamos o
acesso ao mesmo em relação a todas as outras classes,
fazendo com que o seguinte código não compile:
class TestaAcessoDireto {
public static void main(String args[]) {
Conta minhaConta = new Conta();
/*não compila! você não pode acessar o atributo privado de outra
classe*/
[Link] = 1000;
}
}
Controlando o acesso
Cada classe é responsável por controlar seus
atributos, portanto ela deve julgar se aquele novo
valor é válido ou não! Esta validação não deve ser
controlada por quem está usando a classe e sim por
ela mesma, centralizando essa responsabilidade e
facilitando futuras mudanças no sistema.
A palavra chave private também pode ser usada para
modificar o acesso a um método.
Controlando o acesso
public: qualquer classe ou método pode ter acesso, é
transmitido por herança.
private: disponível somente para a classe onde
aparece e não é transmitido por herança
protected: disponível para a classe onde aparece, as
demais classes do mesmo package, é transmitido por
herança
default (não declarando explicitamente nenhum dos
outros modificadores): acessível somente por classes
do mesmo pacote.
Encapsulamento
A idéia de encapsular é esconder todos os membros
de uma classe, além de esconder como funcionam as
rotinas (no caso métodos) do nosso sistema.
Encapsular é fundamental para que seu sistema seja
susceptí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. (veja o caso do método saca)
Encapsulamento
Getters e Setters
O modificador private faz com que ninguém consiga
modificar, nem mesmo ler, o atributo em questão.
Com isso temos um problema: como fazer para
mostrar o saldo de uma Conta, agora que nem mesmo
podemos acessa-lo para leitura?
Getters e Setters
public class Conta {
private double saldo;
// outros atributos omitidos
private double recuperaSaldo() {
return [Link];
}
// deposita() saca() e transfere() omitios
}
Getters e Setters
Agora, para acessarmos o saldo de uma conta,
podemos fazer:
class TestaAcessoComPegaSaldo {
public static void main(String args[]) {
Conta minhaConta = new Conta();
[Link](1000);
[Link]("Saldo: " +
[Link]());
}
}
Getters e Setters
Para permitir o acesso aos atributos (já que eles são
private) de uma maneira controlada, a prática mais
comum é criar dois métodos, um que retorna o valor e
outro que muda o valor.
A convenção para esses métodos é de colocar a
palavra get ou set antes do nome do atributo.
Por exemplo, a nossa conta com saldo, limite e titular
fica assim, no caso da gente desejar dar acesso a
leitura e escrita a todos os atributos:
Getters e Setters
public class Conta {
private double saldo;
private double limite;
private Cliente titular;
public double getSaldo() {
return [Link];
}
public void setSaldo(double saldo) {
[Link] = saldo;
}
public double getLimite() {
return [Link];
}
Getters e Setters
public void setLimite(double limite) {
[Link] = limite;
}
public Cliente getTitular() {
return [Link];
}
public void setTitular(Cliente titular) {
[Link] = titular;
}
}
Getters e Setters
Repare que nesse exemplo setSaldo não deveria ter
sido criado, já que queremos que todos usem
deposita() e saca().
Construtores
Quando usamos a palavra chave new, estamos
construindo um objeto. Sempre quando o new é
chamado, ele executa o construtor da classe. O
construtor da classe é um bloco declarado com o
mesmo nome que a classe:
Construtores
class Conta {
int numero;
Cliente titular;
double saldo;
double limite;
// construtor
Conta() {
[Link]("Construindo uma conta.");
}
}
Construtores
Então, quando fizermos:
Conta c = new Conta();
A mensagem “construindo uma conta” aparecerá. É
como uma rotina de inicialização que é chamada
sempre que um novo objeto é criado. Um construtor
pode parecer, mas não é um método.
O construtor default
Até agora, as nossas classes não possuíam nenhum
construtor. Então como é que era possível dar new, se
todo new chama um construtor obrigatoriamente?
Quando você não declara nenhum construtor na sua
classe, o Java cria um para você. Esse construtor é o
construtor default, ele não recebe nenhum argumento
e o corpo dele é vazio.
A partir do momento que você declara um construtor,
o construtor default não é mais fornecido.
Construtores
O interessante é que um construtor pode receber um
argumento, podendo assim inicializar algum tipo de
informação:
class Conta {
int numero;
Cliente titular;
double saldo;
double limite;
// construtor
Conta(Cliente titular) {
[Link] = titular;
}
}
Construtores
Você pode ter mais de um construtor na sua classe e,
no momento do new, o construtor apropriado será
escolhido.
Um construtor só pode rodar durante a construção do
objeto, isto é, você nunca conseguirá chamar o
construtor em um objeto já construído.
Porém, durante a construção de um objeto, você pode
fazer com que um construtor chame outro, para não
ter de ficar copiando e colando:
Atributos de classe
Nosso banco também quer controlar a quantidade de
contas existentes no sistema. Como poderíamos fazer
isto? A idéia mais simples:
Conta c = new Conta();
totalDeContas = totalDeContas + 1;
Aqui, voltamos em um problema parecido com o da
validação de CPF. Estamos espalhando um código
por toda aplicação
Atributos de classe
Tentamos então, passar para a seguinte proposta:
class Conta {
private int totalDeContas;
//...
Conta() {
totalDeContas = totalDeContas + 1;
}
}
Atributos de classe
Quando criarmos duas contas, qual será o valor do
totalDeContas de cada uma delas? Vai ser 1. Pois
cada uma tem essa variável. O atributo é de cada
objeto.
Seria interessante então, que essa variável fosse
única, compartilhada por todos os objetos dessa
classe.
Dessa maneira, quando mudasse através de um
objeto, o outro enxergaria o mesmo valor. Para fazer
isso em java, declaramos a variável como static
Atributos de classe
private static int totalDeContas;
Quando declaramos um atributo como static, 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.
Para acessarmos um atributo estático, não usamos a
palavra chave this, mas sim o nome da classe:
Atributos de classe
Já que o atributo é privado, como podemos acessar
essa informação a partir de outra classe? Precisamos
de um getter para ele!
class Conta {
private static int totalDeContas;
//...
Conta() {
totalDeContas = totalDeContas + 1;
}
public int getTotalDeContas() [
return totalDeContas;
}
}
Métodos de classe
Métodos static também são chamados de métodos de
classes. Estes métodos só podem operar sobre
atributos de classes, atributos static.
Dentro de métodos static somente é possível pode
acessar outros métodos e variáveis que também
sejam static
O método static mais famoso de todos é o main. É
através dele que vimos nosso primeiro programa em
Java nascer
Métodos de classe
Na execução de uma prgrama Java, a JVM tenta
chamar o método main da classe que foi executada.
Quando declarado o método main como static
permite que a JVM invoque o main sem criar uma
instância da classe.
Métodos de classe
public class Calcula {
public static int soma(int num1, int num2) {
return (num1 + num2);
}
}
public class TestaSomaEstatica {
public static void main(String[] args) {
[Link]([Link](10, 50));
}
}
Para acessar um método ou váriavel static de outra
classe basta utilizar o nome da [Link].
Exemplo =: [Link]();
O não-static precisa primeiramente criar uma
instância da classe para só então chamar algum
método também não-static.
Exemplo: NomeDaClasse ndc =new NomeDaClasse();
[Link]();
Se for criado uma instância de classes para utilizar
métodos ou variáveis static o programa compila e
funciona normalmente.
Exercícios
1) Crie uma classe que representará um Funcionário de
uma Empresa. Esta classe deverá possuir atributos
privados conforme descrito abaixo:
- o seu número de Matrícula (pode ser do tipo Inteiro)
- o seu nome
- a sua idade
- o seu cargo
- o seu salário
Faça o Encapsulamento desta Classe (criar os métodos
"set" e "get").
Para esta classe, gere três Métodos Construtores.
- o primeiro não deve receber parâmetros, mas deve
iniciar o valor do salário com R$ 1.500,00
- o segundo deve receber como parâmetro o nome e a
idade do funcionário, e preencher estes dois campos
com os valores recebidos.
- o terceiro deve receber o número de matrícula, o
nome, e o salário, e preencher estes três campos
com os valores recebidos.
Crie uma classe "TesteConstrutor" (com o método main) que:
- instancia a classe criada no exercício anterior, através do
Método Construtor sem parâmetros.
- imprime o valor dos atributos nome e salário.
- instancia a classe criada no exercício anterior, através do
Método Construtor com os parâmetros de nome e idade.
- imprime o valor dos atributos nome, idade e salário
- instancia a classe criada no exercício anterior, através do
Método Construtor com os parâmetros de matrícula, nome e
salário.
- imprime o valor dos atributos matrícula, nome e salário.
Exercícios
2) Porque esse código não compila?
class Teste {
int x = 37;
public static void main(String [] args) {
[Link](x);
}
}
Exercícios
3) Defina uma classe com dois métodos static que
permite cálculos matemáticos como soma(double
valor, double valor2), fatorial(int valor).