Vamos começar por mostrar como NÃO se devem fazer as coisas, para depois, na próxima secção, fazermos da forma correta.
Se adicionássemos a seguinte instrução
System.out.println(meuJogador);
ao método main
da classe ClienteDeJogador
, com o propósito de imprimir o estado do nosso jogador, obteríamos um output parecido com:
xxxxxxxxxx
Jogador@677327b6
que não é, decididamente, o que nós queríamos...
O que obtivemos foi o nome do tipo do objeto seguido de um código hexadecimal (base 16) especial que é único para cada objeto. Este código pode variar de máquina para máquina e até de execução para execução.
Se acrescentássemos a seguinte instrução, com a intenção de “copiar” um jogador:
xxxxxxxxxx
Jogador copiaJogador = meuJogador;
iríamos ter o seguinte objeto e variáveis em memória:
o que mostra que não foi criada nenhuma cópia, ou seja,
Por isso, se invocássemos o método para alterar a pontuação, por exemplo, com a instrução copiaJogador.registarPontos(13);
, essa invocação afetaria o único objeto existente.
Agora, se acrescentássemos as seguintes instruções:
xxxxxxxxxx
Jogador jogadorIgual = new Jogador("Maria",14,9);
if(meuJogador == jogadorIgual){
System.out.println("Sao iguais!");
} else {
System.out.println("Sao diferentes!");
}
iríamos ter os seguintes objetos e variáveis em memória:
e, por isso, iríamos obter o output:
xxxxxxxxxx
Sao diferentes!
que também não é o que poderíamos estar à espera, pois os objetos têm igual estado.
Mas, aqui, já devíamos saber! (relembrar secção 7.2.9).
O problema é que estamos a comparar os valores das variáveis meuJogador
e jogadorIgual
, os quais são referências para dois objetos distintos; logo, embora os objetos tenham valores iguais para os seus atributos, as referências para esses objetos são diferentes.
Já que a classe nos fornece métodos que revelam os valores dos atributos, poderíamos usar esses métodos para obter o que queremos...
x// Imprimir o jogador
System.out.println("Nome: " + meuJogador.nome() +
" Pontuacao: " + meuJogador.pontuacao());
System.out.println("Maximo numa soh jogada: " + meuJogador.maximoNumaJogada());
// Criar uma copia de jogador
Jogador copiaJogador = new Jogador(meuJogador.nome(),
meuJogador.pontuacao(),
meuJogador.maximoNumaJogada());
// Testar se dois objetos sao iguais
boolean iguais = meuJogador.nome().equals(copiaJogador.nome()) &&
meuJogador.pontuacao() == copiaJogador.pontuacao() &&
meuJogador.maximoNumaJogada() == copiaJogador.maximoNumaJogada();
if(iguais){
System.out.println("Sao iguais!");
} else {
System.out.println("Sao diferentes!");
}
Um dos defeitos desta abordagem é que dificulta a evolução do software: por exemplo, se um dia quisermos aumentar o número de atributos que caracterizam um jogador, todas as classes cliente da classe Jogador
que têm este tipo de instruções, terão que ser modificadas para acomodar essa modificação.
Na verdade ESTA NÃO É UMA ABORDAGEM ORIENTADA A OBJETOS!!
Raciocinemos então:
se um jogador encapsula toda a informação sobre ele próprio, ninguém melhor do que ele para
- fornecer a representação textual dele próprio,
- fornecer uma cópia dele próprio e
- dizer se é igual a um outro jogador.
Assim, as classes cliente só precisariam de invocar os métodos da classe
Jogador
que fornecem esses “serviços”.
É o que vamos ver na próxima secção.
Anterior: 10.6. Mais construtores
Seguinte: 10.8. Agora SIM! – Imprimir, duplicar e comparar objetos