Dúvida no livro de Kathy do exame do programador

Seguinte na página 21 da tradução do livro da Kathy esta escrito:

“quando uma subclasse de fora do pacote herda um membro protegido, este membro torna-se essencialmente privado dentro da subclasse, de forma tal que apenas a subclasse e as suas subclasses podem acessá-lo”

tipo… se o trem se torna privado para o subclasse como que as subclasses dela vão ter acesso? O trem não é privado? Só a subclasse que deveria ter acesso então, uai! Ou não… enfim… alguém me explica isso?

Acredito que isso seja uma regra, no livro fala:

“Depois que a subclasse de fora do pacote herda o membro protegido, ele torna-se privado para qualquer código FORA DA SUBCLASSE, com a excessão das subclasses desta subclasse.”

Ou seja, ele fica disponível apenas para acesso usando herança, você não consegue dar um new na classe e acessar o atríbuto protected, é neste caso que ele fica private, não na herança.

Sacou?!?

É muito simples (espero que você já saiba bem como funciona um membro protected).

Isso: “quando uma subclasse de fora do pacote herda um membro protegido, este membro torna-se essencialmente privado dentro da subclasse, de forma tal que apenas a subclasse e as suas subclasses podem acessá-lo”

É o mesmo que isso:

“Quando uma classe (subclasse) herda de outra classe (super classe), os membros protected da superclasse permanecem sendo protected na subclasse. Isso também se aplica aos membros public.”

É realmente simples, a principal coisa que tu tens que entender é: o “tipo de acesso” de uma variável de instância não pode mudar quando aplicadas na herança. Um atributo que é public ou protected em uma classe será assim não importa quantos níveis de subclasse atinja. Modificadores de acesso em circunstância alguma mudam.

Mas gente… ele falou que fica privado na subclasse. E ninguém herda de privado. E se fosse o caso das subclasses da subclasse herdarem o membro teria que ser protected. A frase não esta correta.

Em um outro forum eu fiz a mesma pergunta, o cara me colocou o trecho do livro em inglês referente a mesma parte:

The bottom line: when a subclass-outside-the-package inherits a protected member, the member is essentially private inside the subclass, such that only the subclass? own code can access it.

Neste trecho não fala nada de subclasses de uma subclasse acessando coisas privadas. É erro de edição. Eu vou em uma livraria verificar isso. (todo mundo fala que o livro é buggado mesmo… :roll: )

Acho que ela só quis dizer que esses membros não vão ser acessados por outras classes dentro do pacote, como aconteceria se a subclasse estivesse no mesmo pacote da superclasse.

Mas concordo que ela foi infeliz ao usar a palavra “privado”, pois esse é também o nome de um modificador de acesso do Java, e isso pode gerar confusão.

Poderia até ser que ela quis dizer privado privado mesmo e não private (o que já é um absurdo,) mas a versão original em inglês não fala nada de subclasses de uma subclasse herdando coisas. A versão em inglês esta bem clara: o membro protected do pai se torna private no filho. O que faz muito sentido, alias.

Acho que talvez a forma como está escrito que gera a confusão de mebro privado sendo herdado… Vou tentar reescrever o trecho do livro que você postou, da forma como imagino que a Kathy quis passar:

O lance é o seguinte: Primeiro de tudo, temos que lembrar como é o acesso a um membro protected. Membros protected de uma classe X só podem ser acessados por classes que se encaixem em pelo menos um destes requisitos:

  1. A classe que quer acessar o membro protected de X está no mesmo pacote onde se encontra a classe X.
  2. A classe que quer acessar o membro protected de X deve ser uma subclasse (não importa se filha, neta, bisneta, etc) de X
    A situação suposta pela Kathy é um caso em que apenas o requisito 2 se aplica. Pra facilitar, um exemplo seria isso aqui:
01 /**
02  * @author Mantu
03  */
04 package help.guj.ArianeFelix.protectedTest.pack01;
05 
06 public class Father {
07   protected int i;
08   
09   protected int getI() {
10     return i;
11   }
12   
13   public String toString() {
14     return "Value: " + i;
15   }
16 }
1 /**
2  * @author Mantu
3  */
4 package help.guj.ArianeFelix.protectedTest.pack02;
5 
6 import help.guj.ArianeFelix.protectedTest.pack01.Father;
7 
8 public class Son extends Father {
9 }

A classe Father tem um campo i e um método getI, ambos protected. A classe Son herda de Father esses membros.
A Kathy quis atentar para um raciocínio que parece certo, mas que no fundo está errado. Vamos ver isso:

Até aqui o programador está certo. Veja a classe que ele fez:

01 /**
02  * @author Programador
03  */
04 package help.guj.ArianeFelix.protectedTest.pack01;
05 
06 public class FatherInvader {
07   public static void main(String[] args) {
08     Father father = new Father();
09     father.i = 10;
10     System.out.println(father.getI());
11   }
12 }

Este programa dele vai compilar e rodar certinho.
Mas eis que o programador, pensando apenas nos requisitos para se acessar um membro protected, pensa o seguinte:

É aí que o Programador se engana… Veja a classe SonInvader:

01 /**
02  * @author Mantu
03  */
04 package help.guj.ArianeFelix.protectedTest.pack02;
05 
06 public class SonInvader {
07   public static void main(String[] args) {
08     Son son = new Son();
09     son.i = 20;
10     System.out.println(son.getI());
11   }
12 }

Esse código não chegará a ser compilado. Nas linhas 9 e 10 serão apontados erros de compilação. No eclipse, teremos as respectivas mensagens:

Tá doidão não. O lance é que o programador se enganou no momento em que achou que Son [color=darkred]tinha em si[/color] todos os membros públicos e protegidos de Father. Isso não é bem verdade. A classe Son é uma extensão - daí o extends - da classe Father. Os membros da calsse Father não são replicados na classe Son, como imaginou o programador.
Uma subclasse funciona como se fosse um “remendo” na superclasse. Os membros definidos na na superclasse continuam definidos e pertencentes à superclasse. Quando o método main de SonInvader tenta acessar o campo i de Son, ele está na verdade tentando acessar o campo i de Father, pois este campo está definido somente em Father. Sendo assim, SonInvader não “enxerga” i porque (1) ele é um campo definido protected em Father, que (2) por sua vez está em um pacote diferente da classe SonInvader, a qual (3) não é subclasse de Father.
Consegue entender agora o que a Kathy quis dizer? Perceba que, nessas circunstâncias, o campo i, que é protected e herdado de Father, se comporta, em termos de visibilidade, como se o fosse um campo private definido em Son. De um jeito ou de outro, SonInvader não tem acesso ao campo i, seja porque é um campo privado definido em Son, seja porque é um campo protected definido em Father - que está em outro pacote.
Só mais uma coisinha:

Isso não é bem verdade…
O que você não pode fazer em uma subclasse é diminuir a visibilidade de um método definido na superclasse. E veja: Isto se aplica somente a métodos sobrescritos, uma vez que não existe sobrescrição de campos (conseqüentemente, não há polimorfismo em campos).
Veja as seguintes classes:

01 /**
02  * @author Mantu
03  */
04 package help.guj.ArianeFelix.protectedTest.pack03;
05 
06 import help.guj.ArianeFelix.protectedTest.pack01.Father;
07 
08 public class DeadSon extends Father {
09   private int i;
10   
11   private int getI() {
12     return i;
13   }
14 
15 }

O meu Eclipse aqui acusa um erro de compilação nesta classe:

Agora, veja esta classe aqui:

01 /**
02  * @author Mantu
03  */
04 package help.guj.ArianeFelix.protectedTest.pack04;
05 
06 import help.guj.ArianeFelix.protectedTest.pack01.Father;
07 
08 public class RecklessSon extends Father {
09   public int i;
10   
11   public int getI() {
12     return i;
13   }
14 }

Esta classe aqui compila certinho. Perceba que alteramos a visibilidade tanto do campo i, quanto do método getI, ampliando-a para public. Isso é permitido em Java, pois você pode ter uma classe pai com um método cuja implementação você só quer disponibilizar para as classes filhas, e as classes filhas é que aproveitem a “boiada” deixada pela pai e sobrescrevam o método, ampliando sua visibilidade para public.
No caso da classe RecklessSon, aí sim a classe SonInvader, se fizesse os acessos sobre RecklessSon, compilaria numa boa:

01 /**
02  * @author Mantu
03  */
04 package help.guj.ArianeFelix.protectedTest.pack02;
05 
06 import help.guj.ArianeFelix.protectedTest.pack04.RecklessSon;
07 
08 public class SonInvader {
09   public static void main(String[] args) {
10     /*
11      * Não deu certo....
12      */
13     //Son son = new Son();
14     
15     RecklessSon son = new RecklessSon();
16     son.i = 20;
17     System.out.println(son.getI());
18   }
19 }

Agora, só como um último exemplo, pra vocês refletirem sobre:

01 /**
02  * @author Mantu
03  */
04 package help.guj.ArianeFelix.protectedTest.pack05;
05 
06 import help.guj.ArianeFelix.protectedTest.pack01.Father;
07 
08 public class NotSoRecklessSon extends Father {
09   protected int i;
10   
11   protected int getI() {
12     return i;
13   }
14 }
01 /**
02  * @author Mantu
03  */
04 package help.guj.ArianeFelix.protectedTest.pack05;
05 
06 public class NotSoRecklessSonInvader {
07   public static void main(String[] args) {
08     NotSoRecklessSon son = new NotSoRecklessSon();
09     son.i = 30;
10     System.out.println("son.i:\n\t" + son.i);
11     System.out.println("son.getI():\n\t" + son.getI());
12     System.out.println("son.toString():\n\t" + son.toString());
13   }
14 }

Espero ter ajudado!
Divirtam-se!

a kathy eh meia confusa as vezes mesmo… ou a tradução do ingles para o portugues foi pessima hehe tem esse fato também…!
Mas ja peguei essas frases de indio da kathy…

Bem … eu iria falar mais umas coisinhas masssssssssssss

Depois dessa “explicaçãzinha” do Mantu …

Deixa quieto …

hehehehe

:thumbup:

explicacao? ou uma aula do mantu? hehe

Nú! Eu não esperava uma aula! Muito obrigada! Esperei chegar em casa para responder com calma.

Bom, o exemplo que você colocou no final funciona sim, já que funcionou quando você reescreveu como public, deve funcionar quando é protected. Tá no mesmo pacote então tá valendo. Eu acho né.

O problema da frase realmente foi o private, porque o membro protected herdado tem um comportamento private em relação as outras classes (com exceção das suas filhas) e um comportamento protected com as suas filhas, que vem lá classe pai, como você, Mantu, disse:

Bom, eu entendi em síntese isso e espero ter entendido certo. ^_^.

Mas realmente a Kathy deveria ter explicado direito, ficou confuso e o fato da versão em português não corresponder com a em inglês é bem estranho. Lembrando que o trecho é inglês é:

e em português é:

esta diferente e não deveria estar. Bizarro… vou ir em uma livraria e comparar a tradução com o original.

Obrigada gente! (especialmente o Mantu)

Você é mineira?

Pelo que você disse, me parece que entendeu sim.

Pior que isso é regra… É raro achar uma tradução decente para livros da nossa área. Infelizmente, quem não sabe ler em inglês, vai sofrer um pouco mais do que quem sabe… Eu aconselho fortemente a quem vai seguir a área de computação e não sabe ao menos ler inglês, dar algum jeitinho: fazer um curso baratinho, tirar do baú os volumes do Patchwork, tirar do baú também as suas velhas e surradas Bizz Letras Traduzidas, assistir dvd em inglês com legenda em português, em português com legenda em inglês, em inglês com legenda em inglês também, etc… Procure conseguir pelo menos ler a lingua da “metrópole”(argh)

Eu sou mineira mas, nú é coisa de mineiro?

Tipo, eu leio inglês tranquilamente e realmente faz MUITA falta, na maioria das vezes você não tem a opção de ler em português. Porém, eu me sinto mais confortável lendo em português (apesar de me irritar um pouco as vezes) (obs: saber inglês lendo a tradução ajuda a realmente ler o livro porque eu achei uns trechos que eles não traduziram… :roll: ) Eu tenho a uma edição mais antiga (não sei qual, não acho escrito nele) do livro e que eu saiba a editora troca pela segunda revisada. Vou tentar isso.

ps: você não respondeu se o último exemplo seu roda tranquilo. Eu acho que sim, mas… sei lá, a vida é uma caixinha de surpresas.

Roda tranquilíssimo! É como você disse: NotSoRecklessSonInvader não tem problema nenhum para acessar os campos protected definidos em NotSoRecklessSon, pois estas classes estão no mesmo pacote. Você entendeu certinho! :thumbup:
Mas mesmo assim, leia o código dessas duas classes, execute, e veja se a saída era o que você esperava. Se era, então você realmente entendeu o que rola sobre membros protected. Se ficou alguma dúvida, aí é só você postar aqui!
Divirta-se!