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?

Foi útil?

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 Outerclasse. 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top