Pregunta

Observé que las clases externas pueden acceder a las variables de instancia privada de las clases internas. ¿Cómo es esto posible? Aquí hay un código de muestra que demuestra lo mismo:

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 qué se permite este comportamiento?

¿Fue útil?

Solución

La clase interna es solo una forma de separar limpiamente alguna funcionalidad que realmente pertenece a la clase externa original. Están diseñados para usarse cuando tienes 2 requisitos:

  1. Alguna pieza de funcionalidad en su clase externa sería más clara si se implementara en una clase separada.
  2. Aunque está en una clase separada, la funcionalidad está muy relacionada con la forma en que funciona la clase externa.

Dados estos requisitos, las clases internas tienen acceso completo a su clase externa. Dado que básicamente son miembros de la clase externa, tiene sentido que tengan acceso a los métodos y atributos de la clase externa, incluidos los privados.

Otros consejos

Si desea ocultar los miembros privados de su clase interna, puede definir una interfaz con los miembros públicos y crear una clase interna anónima que implemente esta interfaz. Ejemplo de abajo:

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
    }
}

La clase interna se considera (para fines de control de acceso) como parte de la clase que la contiene. Esto significa acceso total a todos los privados.

La forma en que esto se implementa es mediante métodos sintéticos protegidos con paquetes: la clase interna se compilará en una clase separada en el mismo paquete (ABC $ XYZ). La JVM no admite este nivel de aislamiento directamente, de modo que en el nivel de código de bytes ABC $ XYZ tendrá métodos protegidos por paquete que la clase externa usa para llegar a los métodos / campos privados.

Aparece una respuesta correcta en otra pregunta similar a esta: ¿Por qué los métodos de la clase adjunta pueden acceder al miembro privado de una clase anidada?

Dice que hay una definición de alcance privado en JLS - Determinación de la accesibilidad :

  

De lo contrario, si el miembro o constructor se declara privado, se permite el acceso si y solo si ocurre dentro del cuerpo de la clase de nivel superior (§7.6) que encierra la declaración del miembro o constructor.

Un caso de uso importante de la OMI para las clases internas es el patrón de fábrica. La clase adjunta puede preparar una instancia de la clase interna sin restricciones de acceso y pasar la instancia al mundo exterior, donde se respetará el acceso privado.

En contradicción con abyx declarando que la clase estática no cambia las restricciones de acceso a la clase adjunta, como se muestra a continuación. También están funcionando las restricciones de acceso entre clases estáticas en la misma clase adjunta. Me sorprendió ...

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);
    }
}

Las restricciones de acceso se realizan por clase. No hay forma de que un método declarado en una clase no pueda acceder a todos los miembros de la instancia / clase. Es lógico que las clases internas también tengan acceso sin restricciones a los miembros de la clase externa, y que la clase externa tenga acceso sin restricciones a los miembros de la clase interna.

Al poner una clase dentro de otra clase, la estás atando estrechamente a la implementación, y todo lo que sea parte de la implementación debería tener acceso a las otras partes.

La lógica detrás de las clases internas es que si creas una clase interna en una clase externa, eso se debe a que necesitarán compartir algunas cosas y, por lo tanto, tiene sentido que puedan tener más flexibilidad que "regular" ; las clases tienen.

Si, en su caso, no tiene sentido que las clases puedan ver el funcionamiento interno de las demás, lo que básicamente significa que la clase interna podría haberse convertido simplemente en una clase regular, puede declarar la clase interna como < código> clase estática XYZ . El uso de static significa que no compartirán el estado (y, por ejemplo, new ABC (). New XYZ () no funcionará, y deberá usar nuevo ABC.XYZ () .
Pero, si ese es el caso, debe pensar si XYZ debería ser realmente una clase interna y que tal vez se merece su propio archivo. A veces tiene sentido crear una clase interna estática (por ejemplo, si necesita una clase pequeña que implemente una interfaz que esté usando su clase externa y que no sea útil en ningún otro lugar). Pero aproximadamente la mitad del tiempo debería haberse convertido en una clase externa.

Thilo agregó una buena respuesta para su primera pregunta "¿Cómo es esto posible?". Deseo desarrollar un poco sobre la segunda pregunta: ¿Por qué se permite este comportamiento?

Para empezar, seamos perfectamente claros de que este comportamiento no solo está permitido para las clases internas que, por definición, son tipos anidados no estáticos. Este comportamiento está permitido para todos los tipos anidados, incluidas las enumeraciones e interfaces anidadas que deben ser estáticas y no pueden tener una instancia de cierre. Básicamente, el modelo es una simplificación hasta la siguiente declaración: el código anidado tiene acceso completo al código adjunto, y viceversa.

Entonces, ¿por qué entonces? Creo que un ejemplo ilustra mejor el punto.

Piensa en tu cuerpo y tu cerebro. Si inyectas heroína en tu brazo, tu cerebro se pone alto. Si la región de la amígdala de su cerebro ve lo que él cree que es una amenaza para su seguridad personal, por ejemplo, una avispa, hará que su cuerpo gire al revés y corra hacia las colinas sin que usted "piense". dos veces al respecto.

Por lo tanto, el cerebro es una parte intrínseca del cuerpo y, por extraño que parezca, al revés también. El uso del control de acceso entre entidades estrechamente relacionadas pierde el derecho a reclamar la relación. Si necesita control de acceso, entonces necesita separar las clases más en unidades verdaderamente distintas. Hasta entonces, son la misma unidad. Un ejemplo de conducción para futuros estudios sería observar cómo un Java Iterator generalmente se implementa.

El acceso ilimitado desde el código adjunto al código anidado hace que, en su mayor parte, sea bastante inútil agregar modificadores de acceso a los campos y métodos de un tipo anidado. Hacerlo es agregar desorden y puede proporcionar una falsa sensación de seguridad para los recién llegados del lenguaje de programación Java.

La clase interna se considera como un atributo de la clase externa. Por lo tanto, no importa que la variable de instancia de clase interna sea privada o no, la clase externa puede acceder sin ningún problema al igual que acceder a sus otros atributos privados (variables).

class Outer{

private int a;

class Inner{
private int b=0;
}

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

Porque su método main () está en la clase ABC , que puede acceder a su propia clase interna.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top