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 package
public 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 Bird
public 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 Bird
public 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 Bird
3: public class Swan extends Bird { // but subclass of bird
4: public void swim() {
5: floatInWater(); // package access to superclass
6: System.out.println(text); // package access to superclass
7: }
8: public void helpOtherSwanSwim() {
9: Swan other = new Swan();
10: other.floatInWater(); // package access to superclass
11: System.out.println(other.text);// package access to superclass
12: }
13: public void helpOtherBirdSwim() {
14: Bird other = new Bird();
15: other.floatInWater(); // DOES NOT COMPILE
16: System.out.println(other.text); // DOES NOT COMPILE
17: }
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!