outer Por que as classes Java externas podem acessar membros privados da classe interna?




nested class java (8)

A lógica por trás das classes internas é que, se você criar uma classe interna em uma classe externa, é porque elas precisarão compartilhar algumas coisas e, portanto, faz sentido que elas tenham mais flexibilidade do que as classes "comuns".

Se, no seu caso, não faz sentido para as classes serem capazes de ver o funcionamento interno do outro - o que basicamente significa que a classe interna poderia simplesmente ter sido transformada em uma classe regular, você pode declarar a classe interna como static class XYZ . Usar static significa que eles não compartilharão o estado (e, por exemplo, o new ABC().new XYZ() não funcionará e você precisará usar o new ABC.XYZ() .
Mas, se for esse o caso, você deve pensar se o XYZ deve realmente ser uma classe interna e que talvez mereça seu próprio arquivo. Às vezes, faz sentido criar uma classe interna estática (por exemplo, se você precisar de uma pequena classe que implemente uma interface que sua classe externa esteja usando e que não será útil em nenhum outro lugar). Mas em cerca de metade do tempo deveria ter sido feito uma aula externa.

Observei que as classes externas podem acessar variáveis ​​de instâncias privadas de classes internas. Como isso é possível? Aqui está um código de exemplo demonstrando o mesmo:

class ABC{
    class XYZ{
        private int x=10;
    }

    public static void main(String... args){
        ABC.XYZ xx = new ABC().new XYZ();
        System.out.println("Hello :: "+xx.x); ///Why is this allowed??
    }
}

Por que esse comportamento é permitido?


Porque seu método main() está na classe ABC , que pode acessar sua própria classe interna.


A classe interna é considerada um atributo da classe Outer. Portanto, não importa se a variável de instância da classe Inner é privada ou não, a classe Outer pode acessar sem qualquer problema, assim como acessar seus outros atributos privados (variáveis).

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}

Se você gosta de esconder os membros privados da sua classe interna, você pode definir uma interface com os membros públicos e criar uma classe interna anônima que implemente essa interface. Exemplo abaixo:

class ABC{
    private interface MyInterface{
         void printInt();
    }

    private static MyInterface mMember = new MyInterface(){
        private int x=10;

        public void printInt(){
            System.out.println(String.valueOf(x));
        }
    };

    public static void main(String... args){
        System.out.println("Hello :: "+mMember.x); ///not allowed
        mMember.printInt(); // allowed
    }
}

Thilo adicionou uma boa answer para sua primeira pergunta "Como isso é possível?". Desejo elaborar um pouco sobre a segunda pergunta feita: por que esse comportamento é permitido?

Para começar, vamos deixar claro que esse comportamento não é permitido apenas para classes internas, que por definição são tipos aninhados não estáticos. Esse comportamento é permitido para todos os tipos aninhados, incluindo enums aninhadas e interfaces que devem ser estáticas e não podem ter uma instância delimitadora. Basicamente, o modelo é uma simplificação até a seguinte instrução: O código aninhado tem acesso total ao código de fechamento - e vice-versa.

Então, por que então? Eu acho que um exemplo ilustra melhor o ponto.

Pense no seu corpo e no seu cérebro. Se você injetar heroína em seu braço, seu cérebro fica alto. Se a região da amígdala do cérebro vê o que ele acredita ser uma ameaça à sua segurança pessoal, digamos, uma vespa por exemplo, ele fará seu corpo girar ao contrário e correr para as colinas sem que você "pense" duas vezes sobre isso.

Então, o cérebro é uma parte intrínseca do corpo - e estranhamente, o contrário também. O uso do controle de acesso entre entidades intimamente relacionadas perde sua reivindicação de relacionamento. Se você precisa de controle de acesso, então você precisa separar as classes mais em unidades verdadeiramente distintas. Até então, eles são a mesma unidade. Um exemplo de condução para estudos futuros seria verificar como um Iterator Java geralmente é implementado.

O acesso ilimitado de incluir código em código aninhado torna, na maior parte, um pouco inútil adicionar modificadores de acesso a campos e métodos de um tipo aninhado. Fazer isso é adicionar confusão e fornecer uma falsa sensação de segurança para os recém-chegados da linguagem de programação Java.


Um importante caso de uso da IMHO para classes internas é o padrão de fábrica. A classe envolvente pode preparar uma instância da classe interna sem restrições de acesso e passar a instância para o mundo externo, onde o acesso privado será honrado.

Em contradição ao abyx declarar que a classe estática não altera as restrições de acesso à classe envolvente, como mostrado abaixo. Além disso, as restrições de acesso entre classes estáticas na mesma classe de inclusão estão funcionando. Eu estava surpreso ...

class MyPrivates {
    static class Inner1 { private int test1 = 2; }
    static class Inner2 { private int test2 = new Inner1().test1; }

    public static void main(String[] args) {
        System.out.println("Inner : "+new Inner2().test2);
    }
}

A classe interna é (para fins de controle de acesso) considerada como parte da classe que a contém. Isso significa acesso total a todos os privates.

A maneira como isso é implementado está usando métodos sintéticos protegidos por pacotes: A classe interna será compilada para uma classe separada no mesmo pacote (ABC $ XYZ). A JVM não suporta esse nível de isolamento diretamente, de modo que no nível de bytecode ABC $ XYZ terá métodos protegidos por pacote que a classe externa usa para obter os métodos / campos privados.


Restrições de acesso são feitas por turma. Não há como um método declarado em uma classe não conseguir acessar todos os membros da instância / classe. É lógico que as classes internas também tenham acesso irrestrito aos membros da classe externa, e a classe externa tenha acesso irrestrito aos membros da classe interna.

Ao colocar uma turma dentro de outra turma, você está firmemente vinculada à implementação, e qualquer coisa que faça parte da implementação deve ter acesso às outras partes.





private-members