Dúvida conceitual!

Pessoal, fazendo exercícios da Caelum e do livro da Kathy, me surgiu uma dúvida no código a seguir.

[code]abstract class Funcionario{
private int idade;
public abstract void setIdadeFuncionario(int idade);
}

class Gerente extends Funcionario{
public void setIdadeFuncionario(int idade){
this.idade = idade; //erro variável de instância private
}
}[/code]

A minha dúvida é que se declaro uma classe Funcionário, com um método abstrato terei que implementá-lo na subclasse concreta.
Mas não poderei fazer a implementação correta, devido a variável de instância ser private.
Uma solução que pensei, seria transformar a variável de instância em protected, mas isto não estaria violando o encapsulamento da minha classe Funcionario?

Pessoal, desculpe se a dúvida é simples, mas não estou enxergando uma boa solução.
Se algum amigo puder me ajudar.

[quote=rmalati]Pessoal, fazendo exercícios da Caelum e do livro da Kathy, me surgiu uma dúvida no código a seguir.

[code]abstract class Funcionario{
private int idade;
public abstract void setIdadeFuncionario(int idade);
}

class Gerente extends Funcionario{
public void setIdadeFuncionario(int idade){
this.idade = idade; //erro variável de instância private
}
}[/code]

A minha dúvida é que se declaro uma classe Funcionário, com um método abstrato terei que implementá-lo na subclasse concreta.
Mas não poderei fazer a implementação correta, devido a variável de instância ser private.
Uma solução que pensei, seria transformar a variável de instância em protected, mas isto não estaria violando o encapsulamento da minha classe Funcionario?

Pessoal, desculpe se a dúvida é simples, mas não estou enxergando uma boa solução.
Se algum amigo puder me ajudar.[/quote]

Teu código ficaria melhor assim:

[code]abstract class Funcionario{
private int idade;
public void setIdadeFuncionario(int idade) {
this.idade = idade;
}
}

class Gerente extends Funcionario{
//Não vai nada nessa classe, além dos métodos específicos de gerentes. void mandarEmbora(Funcionario f) é um exemplo :wink:

}[/code]

Se o método setIdadeFuncionario vai ser comum a todos os herdeiros da classe Funcionario, você não precisa reescrever esse método para todo herdeiro, precisa?

Abraço

Olá rmalati, apenas complementando o que nosso amigo asaudate lhe disse, faz sentido a classe Funcionário ser abstrata, afinal em uma empresa todos são Funcionários, porém um funcionário pode ser: gerente, supervisor, faxineiro, etc…

Faz sentido criarmos um objeto do tipo gerente, supervisor, faxineiro,etc… Mas não faz sentido nesse caso instanciarmos uma classe Funcionário, por isso concordo com você quando disse q sua classe Funcionário seria abstract. Vale lembrar que uma classe abstract pode conter métodos abstracts ou não.

seu método setIdadeFuncionário() será igual para todos os funcionários, afinal independente da posição hierárquica dos funcionários em uma empresa um método que “seta” a idade pra eles funcionaria da mesma maneira, tanto pro Dono da empresa quanto pra um faxineiro. Nosso colega asaudate explicou bem isso.

Usando um exemplo da apostila da Caelum ( vi que você está estudando por ela ) eles usam o método getBonificacao, para um funcionário. Nesse caso é interessante deixar esse método abstract porque nem todos os funcionários são bonificados da mesma maneira, mas eles são bonificados, ai você diz pra sua classe Funcionário : Quando houver alguma classe concreta que herde de mim, ( por ex: Gerente) ela será obrigada a reescrever o método getBonificacao.

Ficaria + ou - assim:

public abstract class Funcionario {
private double salario; 
abstract double getBonificacao(); 

public double getSalario(){
return salario;
}
}

Herdando a classe Funcionário e reescrevendo o método getBonificação

class Gerente extends Funcionario {
public double getBonificacao() { //método reescrito para o funcionário Gerente
return this.getSalario() * 1.4 + 1000;
}
}

Você terá atributos private em sua classe Funcionario, por ex:
private double salario;
E quando precisar manipulá-lo ou acessá-lo, pode fazer isso com métodos gets e sets e não quebrará o enclapsulamento, que era sua preocupação inicial.

Espero ter ajudado.
Até.

Então pelo que entendi de vocês é que basicamente métodos set e get não devem ser abstract pois manipulam variáveis de instância private, considerando o encapsulamento da classe.
Só faria ter sentido eu ter métodos abstract que realmente tem que ser sobrescritos nas subclasses, como um método de bonificação que foi citado.
Foi isso mesmo que vocês tentaram me passar?
Obrigado.

assim, de private pra protected vc quebra a regra de encapsulamento… entao isso nao é valido… blz?

A outra regra toda classe abstract que tiver um metodo absctract, a primeira subclasse concreta deve implementar esse metodo… isso é uma regra… ate pq class nao abstract nao tem e nao podem ter metodos abstract por isso que a implementacao é obrigatoria…

Agora a sua parte comentada é o seguinte… quando vc poe um metodo private ele pertece a class, apenas a ela e a mais ninguem… mesmo atraves da herança a subclasse nao tem acesso a ela… um exemplo que sempre costumo dar.

imagine agora o seguinte: Seu pai tem uma cueca entao essa cueca é private pq é de seu pai, é algo particular, pessoal vc é filho dele, porem nao herda a cueca do seu pai… e outra nao sabe nem que tipo de cueca ele tem ou se realmente ele usa…

class Pai{
private  String cueca;
}
class Filho extends Pai{
//será que meu pai usa cueca? nao sei.
/*nao consigo ver isso.. ele ta de calça,short nao dar para saber.. se pelo menos ele mostrasse  alguma coisa declarando como public ou protected ai ficaria mais facil */

flw! espero ter ajudado :smiley:

[quote=rmalati]Então pelo que entendi de vocês é que basicamente métodos set e get não devem ser abstract pois manipulam variáveis de instância private, considerando o encapsulamento da classe.
Só faria ter sentido eu ter métodos abstract que realmente tem que ser sobrescritos nas subclasses, como um método de bonificação que foi citado.
Foi isso mesmo que vocês tentaram me passar?
Obrigado.[/quote]

Isso mesmo, você entendeu o que eu queria passar. :slight_smile:
vlws

LPJava, esse exemplo da cueca é muito bom. hauahau
Entendi sim, acho que vou praticar mais pois estou com muita teoria na cabeça.

Agora mais uma dúvida.

public static void ImprimeDadosFuncionario(Funcionario funcionario){ System.out.println(funcionario);
Quando mando imprimir um subtipo de funcionário, ele imprime o subtipo e mais uns números.
Desse modo: Diretor@b89838 , Gerente@93dcd ou Gerente@12dacd1
O número depois do @ seria o endereço de memória ou seria sujeira mesmo?
Suponho que seja o endereço do objeto, pois instanciei objetos do mesmo subtipo Gerente e me retornaram números diferentes.
Então imagino o seguinte objetoteste@12acd1 seria objetoteste no endereço 12acd1.
Tô viajando muito? :slight_smile:
Tem como filtrar para exibir somente o tipo do objeto?
Obrigado novamente.

hahaahhaha Olá rmalati, tbm curti exemplo da cueca do pai, qual seria o nome legal do método que conseguisse ver a cueca do pai em vez de usar um getCueca() que tal um abaixaAsCalcasDoVeio()? hahaahha

Quanto a sua outra dúvida, existe um método chamado toString() vem de java.lang.Object (escrito na classe Object, mãe de todas as classes) e um dos propósitos desse método é justamente esse: retornar uma String que possa ser compreendida pelo usuário, mas para isso você precisa sobrescrevê-lo da maneira que melhor lhe convém.

Quanto ao objeto que está tentando imprimir funcionario, diretor ou gerênte, muitas pessoas dizem que o resultado: Diretor@b89838 , Gerente@93dcd ou Gerente@12dacd1 é o endereço de memória, mas na verdade isso é a uma representação textual do objeto.

dah uma olhada no método toString()
http://java.sun.com/j2se/1.3/docs/api/java/lang/Object.html#toString()

Espero ter ajudado + que complicado rs.
abrass

Hauhau, esse nome é fera, muito bom! rs
Cara ajudou sim, vou dar uma lida neste link da Sun sobre os métodos de Object e tentar aplicar.
Obrigado a todos ai pela força!

so vou complementar o que o colega falou la em cima… quando vc for pesquisa sobre Object vai ver que apenas String e Wrappers implementam a toString () por padrao entao por isso quando vc manda imprimir algo que é do tipo String sai bonitinho devido a essa regra acima…

As suas classes por padrao nao implementa toString() ah nao ser que vc declare isso :smiley: subscrevendo a classe!! flw!

flw!

Mas esse método toString() você verá melhor lá pelo capítulo 6 (acho que é esse), por isso não se preocupe com isso agora, deixe para mais adiante, mas se realmente estiver interessado dê uma olhada lá que está muito bem explicado e exemplificado.

Abraços.

Valeu galera!
Vou fazer como o Higor disse, esperar até o capítulo 6 para estudar melhor este assunto.
Obrigado a todos pelas respostas.