Acesso Protegido:
O acesso protegido permite tudo o que o acesso padrão (pacote privado) permite e muito mais. O modificador de acesso protegido adiciona a capacidade de acessar membros de uma classe pai. Bem abordar a criação de subclasses em profundidade no Capítulo 5. Por enquanto, abordaremos o mais simples possível uso de uma classe infantil. A Figura 4.3 mostra as muitas classes que criaremos nesta seção. Há um número de classes e pacotes, portanto, não se preocupe em mantê-los todos na sua cabeça. Apenas volte com esta figura à medida que avança.
Primeiro, criamos uma classe Bird e oferecemos acesso protegido a seus membros:
package pond.shore;public class Bird { protected String text = "floating"; // protected access protected void floatInWater() { // protected access System.out.println(text); } }Em seguida, criamos uma subclasse:
package pond.goose;import pond.shore.Bird; // in a different packagepublic class Gosling extends Bird { // extends means create subclass public void swim() { floatInWater(); // calling protected member System.out.println(text); // calling protected member } }Esta é uma subclasse muito simples. Ele estende a classe bird. Estender significa criar um subclasse que tem acesso a qualquer membro protected ou public da classe pai. Corrida esse código imprime flutuando duas vezes: uma vez ao chamar floatInWater () e uma vez na impressão declaração em swim() . Como Gosling é uma subclasse de Bird , ele pode acessar esses membros mesmo embora esteja em um pacote diferente. Lembre-se de que protected também nos dá acesso a tudo o que o acesso padrão faz. Isso significa que uma classe no mesmo pacote que o Bird pode acessar seus membros protegidos .
package pond.shore; // same package as Birdpublic class BirdWatcher { public void watchBird() { Bird bird = new Bird(); bird.floatInWater(); // calling protected member System.out.println(bird.text); // calling protected member } }Como Bird e BirdWatcher estão no mesmo pacote, o BirdWatcher pode acessar os membros da variável bird. A definição de protected permite o acesso a subclasses e classes em o mesmo pacote. Este exemplo usa a mesma parte do pacote dessa definição. Agora vamos tentar a mesma coisa em um pacote diferente:
package pond.inland;import pond.shore.Bird; // different package than Birdpublic class BirdWatcherFromAfar { public void watchBird() { Bird bird = new Bird(); bird.floatInWater(); // DOES NOT COMPILE System.out.println(bird.text); // DOES NOT COMPILE } }BirdWatcherFromAfar não está no mesmo pacote que Bird e não herda de Bird . Isso significa que não é permitido acessar membros protegidos da Bird . Percebido? Subclasses e classes no mesmo pacote são as únicas permissão para acessar membros protegidos . Há uma pegadinha para acesso protegido . Considere esta classe:
1: package pond.swan;2: import pond.shore.Bird; // in different package than Bird3: public class Swan extends Bird { // but subclass of bird4: public void swim() {5: floatInWater(); // package access to superclass6: System.out.println(text); // package access to superclass7: }8: public void helpOtherSwanSwim() {9: Swan other = new Swan();10: other.floatInWater(); // package access to superclass11: System.out.println(other.text);// package access to superclass12: }13: public void helpOtherBirdSwim() {14: Bird other = new Bird();15: other.floatInWater(); // DOES NOT COMPILE16: System.out.println(other.text); // DOES NOT COMPILE17: }18: }Respire fundo. Isto é interessante. Swan não está no mesmo pacote que Bird , mas estendê-o - o que implica que ele tem acesso aos membros protegidos da Bird, pois é um subclasse. E faz. As linhas 5 e 6 referem-se a membros protegidos via herança. As linhas 10 e 11 também usam com sucesso membros protegidos da Bird. Isso é permitido porque essas linhas se referem a um objeto Swan . Swan herda de Bird, então está tudo bem. É uma espécie de uma verificação bifásica. A classe Swan tem permissão para usar membros protegidos da Bird e estão se referindo a um objeto Swan . Concedido, é um objeto Swan criado na linha 9 em vez de um herdado, mas ainda é um objeto Swan. As linhas 15 e 16 não são compiladas. Espere um minuto. Eles são quase exatamente o mesmo que linhas 10 e 11! Há uma diferença fundamental. Desta vez, uma referência de Bird é usada. É criado na linha 14. Bird está em um pacote diferente e esse código não é herdado do Bird , portanto não consegue usar membros protegidos. O que dizer agora? Acabamos de dizer repetir comovente que Swan herda de Bird . E faz. No entanto, a referência da variável não é um Swan. Por acaso, o código está na classe Swan .
Não há problema em ficar confuso. Este é sem dúvida um dos pontos mais confusos do exame. Olhando de uma maneira diferente, as regras protegidas se aplicam em dois cenários:
■ Um membro é usado sem se referir a uma variável. É o caso das linhas 5 e 6. Nesse caso, estamos aproveitando a herança e o acesso protegido é permitido.
■ Um membro é usado através de uma variável. É o caso das linhas 10, 11, 15 e 16. Nesse caso, as regras para o tipo de referência da variável são o que importa. Se é uma subclasse, o acesso protegido é permitido. Isso funciona para referências à mesma classe ou a uma subclasse.
Vamos tentar novamente para garantir que você entenda o que está acontecendo. Você pode descobrir por que esses exemplos não são compilados?
package pond.goose;import pond.shore.Bird;public class Goose extends Bird { public void helpGooseSwim() { Goose other = new Goose(); other.floatInWater(); System.out.println(other.text); } public void helpOtherGooseSwim() { Bird other = new Goose(); other.floatInWater(); // DOES NOT COMPILE System.out.println(other.text); // DOES NOT COMPILE } }O primeiro método é bom. De fato, é equivalente ao exemplo do Swan. Goose estende Bird . Como estamos na subclasse Goose e nos referimos a uma referência Goose , ele pode acessar membros protegidos . O segundo método é um problema. Embora o objeto seja Goose, ele é armazenado em uma referência de Bird. Não podemos nos referir a membros da classe Bird, já que não estamos no mesmo pacote e Bird não é uma subclasse de Bird . Que tal este?
package pond.duck;import pond.goose.Goose;public class GooseWatcher { public void watch() { Goose goose = new Goose(); goose.floatInWater(); // DOES NOT COMPILE } }Esse código não é compilado porque não estamos na classe Goose. O método floatInWater() é declarado em Bird. A classe GooseWatcher não está no mesmo pacote que o Bird , nem estende Bird. A Goose estende a Bird. Isso apenas permite que o Goose se refira a floatInWater () e não chamadores de ganso . Se isso ainda for intrigante, experimente. Digite o código e tente compilá-lo. Então reler esta seção. Não se preocupe - também não foi óbvio para os autores pela primeira vez!