Não posso acessar a classe interna protegida enquanto herda
-
18-09-2019 - |
Pergunta
Lendo "Thinking in Java", fiquei no Ex: 6 do Capítulo das Classes Internas.
Exercício 6: (2) Crie uma interface com pelo menos um método, em seu próprio pacote. Crie uma classe em um pacote separado. Adicione uma classe interna protegida que implementa a interface. Em um terceiro pacote, herde da sua classe e, dentro de um método, retorne um objeto da classe interna protegida, upcasting para a interface durante o retorno.
Este é o meu código:
Ione.java
interface
package intfpack;
public interface IOne{
void f();
}
Cone.java
Classe com classe interna protegida que implementa a interface
package classpack;
import intfpack.*;
public class COne{
protected class Inner implements IOne{
public void f(){System.out.println("Inner class of COne");}
}
}
Ctwo.java
Herdando da aula com a classe interna protegida
package thirdpack;
import classpack.*;
import intfpack.*;
public class CTwo extends COne{
public IOne getInner(){
IOne io = new Inner();
return io;
}
public static void main(String[] args){
CTwo ct = new CTwo();
ct.getInner();
}
}
Copmiler diz a seguir:
javac CTwo.java
CTwo.java:9: Inner() has protected access in classpack.COne.Inner
IOne io = new Inner();
^
1 error
Mas o livro diz que posso acessar as classes internas protegidas na classe derivada. Onde está o erro?
Solução
A mensagem de erro está reclamando que o construtor está sendo protegido, não a classe. Mas você não definiu explicitamente um construtor no código que você postou. Nesse caso, De acordo com o JLS, o construtor padrão será protegido (o mesmo que a classe).
Outras dicas
Você precisa definir um public
construtor para o Inner
class
:
public class COne {
protected class Inner implements IOne{
public Inner() { }
public void f(){System.out.println("Inner class of COne");}
}
}
Isso é claro. Mas aqui está uma coisa realmente estranha.
De acordo com o JLS Se o CTWO estender o Cone.inner, espera -se que acesse o construtor protegido do Inner, mas na prática não ... veja abaixo.
package p1;
public class COne {
public static class Inner {
protected Inner() {}
}
}
package p2;
public class CTwo extends COne.Inner {
public void getIface() {
new COne.Inner();
// Compile time error anyway with the same complains:
// "Inner() has protected access in p1.COne.Inner"
// ...unlike my expectations...
}
}
O problema não é sobre a classe interna, mas a herança.
Vamos fazer alguns experimentos.
Primeiro Inner
e Outer
classe ambos têm acesso total um para o outro. Portanto, o código a seguir funciona bem.
package com.ciaoshen.packA;
public class Outer {
protected class Inner {
public void foo() { System.out.println("Hello Ronald!"); }
}
protected Inner inner() {
return new Inner();
}
public static void main(String[] args) {
new Outer().inner().foo(); // Output: Hello Ronald!
}
}
Agora em outro pacote, DerivedOuter
é derivado de Outer
. DerivedOuter
chamadas inner()
Método herdado de Outer
classe. Ainda funciona!
package com.ciaoshen.packB;
class DerivedOuter extends Outer {
public static void main(String[] args) {
new DerivedOuter().inner().foo(); // Output: Hello Ronald!
}
}
Mas Quando eu substituo o inner()
método em DerivedOuter
classe, o mesmo erro ocorre!
package com.ciaoshen.packB;
class DerivedOuter extends Outer {
@Override
public Inner inner() { // this is not the inner() of Outer class. BOOM!
return new Inner();
}
public static void main(String[] args) {
new DerivedOuter().inner().foo(); // ERROR: Outer.Inner() has protected access in Outer.Inner
}
}
Conclusão, o construtor interno protegido é acessível apenas no original Outer
escopo da classe. Qualquer método adicional (ex: seu getInner()
método) não tem acesso a protegidos Inner
construtor.
O ponto principal é que quando DerivedOuter
herdar de um Outer
, você pode imaginar isso DerivedClass
É UM Outer
, e contém um Inner
classe dentro como seu membro. Mas de fato, DerivedOuter
não tem acesso direto a Inner
classe, mas só funciona usando sua super classe Outer
.