• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Nazgulled

Pequena dúvida sobre accessos a metodos numa classe

16 mensagens neste tópico

A resolução do prof num exercício é a seguinte:

public class CartaoCliente {

private String codigo;
private String titular;
private double totCompras;
private int pontos;
private double taxaPremio;


public CartaoCliente(String cod, String tit, double taxa) {
	codigo = cod;
	titular = tit;
	taxaPremio = taxa;
	totCompras = 0;
	pontos = 0;
}

public CartaoCliente(CartaoCliente cart) {
	codigo = cart.getCodigo();
	titular = cart.getTitular();
	pontos = cart.getPontos();
	taxaPremio = cart.getTaxa();
	totCompras = cart.getTotCompras();
}

public String getCodigo() {
	return codigo;
}

public String getTitular() {
	return titular;
}

public int getPontos() {
	return pontos;
}

public double getTaxa() {
	return taxaPremio;
}

public double getTotCompras() {
	return totCompras;
}


public void mudaTaxa(double novaTaxa) {
	taxaPremio = novaTaxa;
}

public void mudaTitular(String tit) {
	titular = tit;
}

private void tiraPontos(int pts) {
	pontos -= pts;
}

public void descPontos(int pts) {
	pontos -= pts;
}

public void compra(double valor) {
	int quantos50 = (int) valor/50;

	totCompras += valor;

	if((int)totCompras/50 == quantos50) {
		pontos += (int) valor/taxaPremio;
	} else {
		pontos += (5*quantos50) + (int) valor/taxaPremio;
	}
}

public void descarregaPontos(CartaoCliente crt, int pts) {
	pontos += pts;
	crt.tiraPontos(pts);
}

public String toString() {
	StringBuilder s = new StringBuilder();

	s.append("----- Cartão de Cliente -----\n");
	s.append("Código: " + codigo + "\n");
	s.append("Titular: " + titular + "\n");
	s.append("Total Compras: " + totCompras + " Euros\n");
	s.append("Pontos: " + pontos + "\n");
	s.append("Taxa Actual: " + taxaPremio + "\n");
	s.append("----------------------------\n");

	return s.toString();
}

public CartaoCliente clone(CartaoCliente crt) {
	return new CartaoCliente(this);
}
}

E o código que eu usei para testar foi o seguinte:

CartaoCliente c1 = new CartaoCliente("ABC", "Ricardo", 10.0);
CartaoCliente c2 = new CartaoCliente("DEF", "Jonas", 15.0);

c1.compra(10000);
c2.compra(5000);

System.out.println(c1.toString());
System.out.println(c2.toString());

c2.descarregaPontos(c1, 100);

System.out.println(c1.toString());
System.out.println(c2.toString());

Isto está a funcionar e faz o que é suposto mas é precisamente ai que a minha dúvida começa. Mais precisamente no método descarregaPontos(). Como é que é possível fazer crt.tiraPontos(pts);? Não percebo... Tipo, o método tiraPontos é privado e nos estamos a enviar a mensagens "tiraPontos" ao objecto "crt", logo, este método não deveria ser acessível.

Tanto quanto eu sei, os métodos privados, só podem ser acedidos por métodos dentro da própria classe e não com mensagens enviadas ao objecto. Ou seja, poderia ter um método público qualquer, por exemplo, abc() e fazia crt.abc() em vez de crt.tiraPontos() e dentro do método abc() é que iria invocava o método tiraPontos que é privado.

O que me está a escapar aqui?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Exacto os métodos private apenas podem ser acedidos de dentro da própria classe ou através de um outro método public. Nesse caso é isso mesmo que acontece o método descarregaPontos que é public chama o método tiraPontos enviando o objecto ao qual esse método é executado.

Realmente é uma mecanismo estranho eu pessoalmente não faria assim mas tem toda a lógica no âmbito do Java.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Estás a falar da invocação do método tiraPontos dentro do método descarregaPontos, certo?

Nesse caso repara, estás invocar o método privado dentro da classe, tal como disseste que era possível, só te falta compreender que, quando dentro da classe, é possível aceder a qualquer elemento privado de uma instância dessa classe. Vou dar o exemplo da implementação comum do método equals usando a tua classe.

public boolean equals(Object obj) {

    if(this == obj) {

        return true;

    }

    if(obj instanceof CartaoCliente) {

        CartaoCliente outro = (CartaoCliente)obj; //apenas para ter uma referência mais simples de usar

        return this.codigo == outro.codigo && this.titular == outro.titular && this.totCompras == outro..totCompras

                                        && this.pontos = outro.pontos && this.taxaPremio = outro.taxaPremio;

    }

    return false;

Neste caso estou a aceder aos elementos privados da classe CartaoCliente através da referência outro, isto só é possível porque estou dentro da classe CartaoCliente. Quando dizemos que os métodos ou atributos públicos são apenas visíveis dentro da classe, significa que a visibilidade se estende às instâncias da própria classe que estão a ser usadas dentro dela.

Confuso? :P

Edit:

Não é um mecanismo estranho, está a ser usado o conceito de POO, e neste caso até faz muito sentido ser assim :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O que me esta a confundir é que eu estou a passar um objecto (ou o apontador?) como argumento... Tipo, estou no main() e tenho o objecto c1. Dentro do main() eu não posso fazer c1.tiraPontos(), mas depois mais à frente passo como argumento a variável c1 para um método do c2 (descarregaPontos()) o descarregaPontos é publico do c2 e não do c1. O c1 foi passado como argumento (CartaoCliente crt) e fazer c1.tiraPontos() no main() (que não é permitido) é a mesma coisa que fazer crt.tiraPontos() dentro do descarregaPontos() do c2. Isto para mim claro, é assim que eu vejo as coisas...

Ao fazer:

c2.descarregaPontos(c1, 100);

Nós não vamos estar dentro do método público descarregaPontos() do c1 mas sim do c2, logo, não entendo como é possível chamar o método privado tiraPontos() do c1 estando nós dentro do método público descarregaPontos() do c2...

Basicamente, estou dentro de um objecto A a chamar um método privado de um objecto B, não consigo entender como isso é possível.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não interessa a que instância estás a aceder, a nível de visibilidade tens acesso a todos os elementos, privados/públicos/protegidos, quando o acesso é feito dentro da classe onde esses elementos estão disponíveis. Isto significa que para qualquer código que faças dentro da classe, independentemente da instância, tens acesso aos elementos.

Não sei como explicar isto de outra forma, estou a perceber a tua dúvida, mas não consigo dizer isto de outra forma. Apesar de serem dois objectos diferentes são os dois instâncias da mesma classe e dentro da classe tens acesso a todos os campos das suas instâncias.

Não interessa qual a instância em que o código está a executar, interessa é se a classe tem o acesso necessário, neste caso a visibilidade não é determinada pela instância, neste caso e em caso algum, a visibilidade é determinada pela classe e pela estrutura/hierarquia de classes e nunca pelas instâncias. Se assim fosse não era fácil determinar as visibilidades, como é que seria possível determinar o parentesco de dois objectos para os atributos protegidos, ou o package ao qual os objectos pertencem para os atributos de visibilidade package? Não seria, um objecto é apenas uma instância de uma classe e quem define o acesso e visibilidade de um elemento é a classe e não as suas instâncias.

Se pensares nisso como sendo da classe e não das instâncias, como estás a fazer, talvez seja mais fácil, não importa em que instância foi invocado mas sim a que classe pertence e se estás e executar código dentro da classe certa ou não.

EDIT:

Reforçando, não é por estares dentro do método main() que não tens acesso mas sim por estares dentro da classe que tem o método e que não tem acesso aos atributos da classe CartaoCliente.

E seria objecto ou referência, não apontador, já que não possuem uma relação directa com os ponteiros de C. Por acaso nunca achei piada "apontador", se olharmos para o sentido da palavra não fica muito certo... mas acho que isto não interessa para o caso :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sabes no fundo o Nazgulled tem toda a razão. Até acho estranho o javac não dar nenhum warning...

Porque independentemente de estares a mexer em "crt" dentro duma instancia da mesma classe, estás a violar o encapsulamento.

Mais estranho é que tens um método "descPontos" que serve para isso mesmo. Por isso em vez de usares "crt.tiraPontos(pts)", deverias usar o método que falei.

: D

E faria ainda mais sentido o código estar assim:

private void tiraPontos(int pts) {
	pontos -= pts;
}

public void descPontos(int pts) {
	tiraPontos(pts);
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não estás a violar encapsulamento nenhum, nem sequer está relacionado com ecampsulamento mas sim com a visibilidade dos atributos e o código que colocaste, parece-me, não estar de acordo com o objectivo.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Então diz-me o que pensas disto. Achas que por estarmos a trabalhar com uma instância dessa classe,

podemos aceder aos atributos/métodos privados?

Porque basicamente este é um exemplo simples de que o que disseste não faz sentido..

class Pessoa
{
private String _nome
private int _idade;

public Pessoa(String nome, int idade)
{
	_nome = nome;
	_idade = idade;
}

public String getNome()  { return _nome; }
public int    getIdade() { return _idade; }

public int comparaIdade(Pessoa p)
{
	// Alterar atributos privados assim à vontade?
	p._idade = 1;

	// O que seria de esperar..
	// return p.getIdade() - this.getIdade();
}
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sim podemos, e faz todo o sentido.

A visibilidade dos métodos/atributos é definida pela classe e não pela instância, por isso sim, o código que tens é possível, é extremamente útil, não viola qualquer encapsulamento.

Se me disseres que com esse exemplo estamos a danificar uma instância sem intenção e que estamos a introduzir um bug no sistema, claro que concordo contigo, o uso desse tipo de construções é perigoso e pode dar origem a esses erros, como indicaste. Isso não o torna errado. É tão errado com usar aritmética de ponteiros, que pode ser o suficiente para te oferecer a arma, as balas e puxar o gatilho, no entanto é correcta, útil e faz parte da estrutura da linguagem.

Este caso é o mesmo, pode parecer estranho que tal permissão existe, seria certamente mais seguro usar os métodos de acesso e não aceder directamente ao atributo mas, não, essa não é a forma "que seria de esperar".

É perigoso?, sim pode ser, e muito. Faz confusão?, se não perceberes como funciona a visibilidade de atributos/métodos, acredito que sim. É uma violação de encapsulamento?, não, o encapsulamento é referente à visibilidade por outras classes e não por instâncias, e como disse antes, se a visibilidade funcionasse por classes então alguns tipos de visibilidade não seriam possíveis.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Repara que estás a tentar dar a volta ao assunto ao falar de que não sei o que é visibilidade.

O que está aqui em causa é o que o Nazgulled perguntou. E o que disse é o que está CORRECTO. Existe um método público para o que se pretende.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Peço desculpa mas não estou a dar a volta a nada, talvez me tenha perdido no que escreveste e não tenha percebido. Falei da visibilidade porque esse pareceu-me ser o problema.

A dúvida do Nazgulled era referente a ser possível aceder ao um atributo privado de uma instância dentro da sua própria classe, e isso é possível e não está errado.

Agora estou confuso e não sei a que te referes, disseste que o Nazgulled tinha razão, pelo que vejo no que ele escreveu ele não tem razão no que afirma, ele simplesmente não estava a perceber o que é visibilidade e como é que isso afecta o acesso a elementos de uma classe. Quanto ao compilar dar avisos, como disse não faz sentido uma vez que é um mecanismo da linguagem, um mecanismo válido e que não é errado.

Tendo em conta o código, não está mais correcto aceder pelo método público ou pelo método privado, é apenas uma questão de escolha do programador. Poderia perguntar porque é que existem dois métodos que à partida possuem o mesmo objectivo, aí talvez criasse apenas um dependendo da necessidade.

Se não existisse um método público para aceder ao valor já considerarias correcto usar o método privado? É que agora nem sei qual é a discussão, afinal onde está o problema?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Quando chegarem a alguma conclusão, façam um resumo se faz favor porque já me estão a confundir...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Eu deixei a discussão em aberto, estava à espera de uma resposta :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sabes no fundo o Nazgulled tem toda a razão. Até acho estranho o javac não dar nenhum warning...

Porque independentemente de estares a mexer em "crt" dentro duma instancia da mesma classe, estás a violar o encapsulamento.

Eu não considero isso uma violação do encapsulamento.

Quando usas um método private, sabes que mesmo se o alterares, os efeitos dessa alteração continuam a estar contidos no ficheiro da classe, que é "teu". Assim, não há qualquer violação do encapsulamento em usar um método private noutro objecto que não o próprio, desde que dentro do ficheiro.

Nessas situações, vais ter que analisar as chamadas ao método existentes no ficheiro, e é indiferente se são sobre o próprio objecto, ou se são sobre outro.

Eu vejo as restrições de acesso, como uma forma de dizer ao programador qual o alcance das alterações a uma classe, i.e., quais os ficheiros que podem ser afectados pela alteração de um método/campo. Nos métodos private é a classe, quando não especificas é a package, nos protected é a package+subclasses, ...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora