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?
new ABC().new XYZ()
Respuestas:
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:
Dados estos requisitos, las clases internas tienen acceso completo a su clase externa. Dado que son básicamente un miembro de la clase externa, tiene sentido que tengan acceso a los métodos y atributos de la clase externa, incluidos los privados.
fuente
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 a continuación:
fuente
x
es público aquí, no está permitido comomMember.x
.La clase interna se considera (para fines de control de acceso) como parte de la clase que la contiene. Esto significa acceso completo a todos los privados.
La forma en que esto se implementa es mediante métodos sintéticos protegidos por 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.
fuente
Hay una respuesta correcta que aparece 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 :
fuente
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 declarar 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ó ...
fuente
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 ilimitado a los miembros de la clase externa, y que la clase externa tenga acceso ilimitado a los miembros de la clase interna.
Al colocar una clase dentro de otra clase, la está estrechamente vinculada a la implementación, y todo lo que sea parte de la implementación debe tener acceso a las otras partes.
fuente
La lógica detrás de las clases internas es que si creas una clase interna en una clase externa, es porque necesitarán compartir algunas cosas y, por lo tanto, tiene sentido que puedan tener más flexibilidad que las clases "regulares".
Si, en su caso, no tiene sentido que las clases puedan ver el funcionamiento interno de los demás, lo que básicamente significa que la clase interna simplemente podría haberse convertido en una clase regular, puede declarar la clase interna como
static class XYZ
. El usostatic
significará que no compartirán el estado (y, por ejemplonew ABC().new XYZ()
, no funcionará, y tendrá que usarlonew ABC.XYZ()
.Pero, si ese es el caso, debe pensar si
XYZ
realmente debería ser una clase interna y si tal vez merece su propia). 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 eso no será útil en ningún otro lado). Pero aproximadamente la mitad del tiempo Debería haberse hecho una clase externa.fuente
Thilo agregó una buena respuesta para su primera pregunta "¿Cómo es esto posible?". Deseo profundizar un poco en la segunda pregunta: ¿Por qué se permite este comportamiento?
Para empezar, seamos perfectamente claros de que este comportamiento no se limita a 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 de 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 eleva. 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.
Entonces, el cerebro es una parte intrínseca del cuerpo y, curiosamente, también al revés. El uso del control de acceso entre esas entidades estrechamente relacionadas pierde su reclamo de 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
Iterator
se implementa generalmente un Java .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.
fuente
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).
fuente
Porque su
main()
método está en laABC
clase, que puede acceder a su propia clase interna.fuente
ABC
clase pueden acceder a las clases anidadas en laABC
clase, sino por qué pueden acceder a los miembros privados de las clases anidadas en laABC
clase en Java.