Mi entrevistador me preguntó sobre las clases internas. Después de explicarle todo, me detuvo en mi única oración: si las clases internas pueden acceder a miembros privados de la clase externa, ¿no viola la privacidad? No pude responderlo.

1
Rishabh Jain 9 sep. 2018 a las 10:36

5 respuestas

La mejor respuesta

Desde una perspectiva JVM, sí, una clase interna que accede a un miembro privado de la clase externa viola la privacidad.

Pero, desde una perspectiva de Java, no, no viola la privacidad.

Perspectiva JVM

La especificación de la máquina virtual Java, sección 5.4.4. Control de acceso dice:

Un campo o método R es accesible para una clase o interfaz D si y solo si alguno de los siguientes es verdadero:

  • [...]

  • R es private y se declara en D .

Por lo tanto, la JVM solo permitirá el acceso a miembros private desde el código de la misma clase, es decir, una clase anidada no puede acceder a los miembros private de la clase externa.

Perspectiva Java

La especificación del lenguaje Java, sección 6.6.1. Determinando la accesibilidad dice:

Un miembro (clase, interfaz, campo o método) de un tipo de referencia, o un constructor de un tipo de clase, es accesible solo si el tipo es accesible y se declara que el miembro o constructor permite el acceso:

  • [...]

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

Entonces, un miembro private en una clase de nivel superior y / o clase anidada es accesible desde el código en cualquier lugar dentro de esa clase de nivel superior. Dado que las clases anidadas, por definición, ocurren dentro del cuerpo de la clase de nivel superior adjunta, el código en las clases anidadas puede acceder a los miembros private de la clase externa.

Acceso sintético

Para resolver la discrepancia, el compilador de Java crea métodos ocultos (sintéticos) para permitir el acceso "privado" entre clases estrechamente relacionadas, es decir, entre una clase de nivel superior y todas sus clases anidadas.

Este es un truco interno del compilador y no está realmente documentado en las especificaciones. JVMS, sección 4.7.8 . El atributo sintético dice:

[...] Un miembro de la clase que no aparece en el código fuente debe marcarse con un atributo Synthetic, o debe tener establecido su indicador ACC_SYNTHETIC. [...]

El atributo Synthetic se introdujo en JDK 1.1 para admitir clases e interfaces anidadas.

Para obtener más información, realice una búsqueda en la web para java synthetic accessor.

Consulte también: Advertencia del método de acceso sintético

1
Andreas 9 sep. 2018 a las 08:18

Si observa detenidamente las afirmaciones #1 y #2, encontrará que la única diferencia entre ellas es de un objeto adicional (de clase interna) que se crea en #1, Descanse todo lo relacionado con el acceso es exactamente lo mismo .

No hay violación porque en algún lugar intencionalmente está dejando la puerta abierta a través de algún tipo de especificador de acceso como public o protected. La clase interna no actúa (o no es capaz de actuar) como una solución alternativa allí, por lo que sin violación absolutamente.

public class AccessPrivateMemberThruInnerClass {

    private int getUniqueId() {
        return 101;
    }
    private class AnInnerClass {
        public int getParentID() {
            return getUniqueId();  // invokes private method inside a public method.
        }
    }
    public int getUniqueIdForce() {
        return getUniqueId();      // invokes private method inside a public method.
    }
    public AnInnerClass getInnerClassObject(){
        return new AnInnerClass();
    }
    public static void main(String[] args) {
        AccessPrivateMemberThruInnerClass obj = new AccessPrivateMemberThruInnerClass();
        System.out.println(obj.getInnerClassObject().getParentID());   // #1
        System.out.println(obj.getUniqueIdForce());   // #2
    }
}
0
Saurav Sahu 9 sep. 2018 a las 09:25

La respuesta es No ya que la clase interna es parte de la clase externa, al igual que otras variables y métodos son

Se puede acceder a todas las private variable / método de una clase dentro de todos los métodos de la misma clase. Una clase interna es un caso especial en el que una instancia de InnerClass solo puede existir dentro de una instancia de OuterClass. Por lo tanto, tiene acceso directo a los métodos y campos de su instancia adjunta.

1
Ashishkumar Singh 9 sep. 2018 a las 07:58

La respuesta es NO , porque la clase interna tiene un enlace interno con la clase externa y la clase interna no existe sin una instancia concreta de la clase externa.

Pero si agrega estática a la declaración de clase interna, significa que no tiene un enlace a la clase externa y esto es lo mismo cuando declara la clase en su propio archivo.

Eso es todo, claro y simple.

0
oleg.cherednik 9 sep. 2018 a las 09:22

Respuesta: Ninguna clase interna no viola la privacidad de la clase externa.

Explicación: Todos los métodos de instancia definidos en una clase pueden acceder a los campos y métodos privados o no privados definidos en la clase. Esto sucede ya que todos los métodos y campos de instancia pertenecen al objeto actual de la clase. Lo mismo es cierto para cualquier clase interna (no estática), tiene una referencia implícita del objeto actual de la clase externa. Esta es la razón por la cual solo puede crear el objeto de clase interna (no estática) con la ayuda de un objeto de clase externa. Si crea el objeto de clase interna dentro de cualquier método de instancia de clase externa, entonces se crea con la ayuda de la referencia implícita de objeto actual de la clase externa.

Si tiene una clase interna que es estática, entonces no tiene referencia implícita al objeto actual de la clase externa. Cualquier campo o método de instancia pertenece a un Objeto de la clase. Por lo tanto, la clase interna estática no puede acceder a ningún campo de instancia privada o no privada o método de clase externa.

Puede establecer la referencia del objeto de clase contenedor externo explícitamente y luego puede acceder. Ahora, con la ayuda de esta referencia explícitamente establecida de clase externa, puede acceder a los campos y métodos privados.

Entonces, ahora modifiquemos la pregunta como ¿por qué la clase estática interna con una referencia explícita de la clase externa puede acceder y modificar los métodos y campos privados ?

La respuesta está relacionada con nuestra decisión de tener dicho diseño. La intención de definir cualquier entidad dentro del alcance de una clase es pertenencia . Si falta pertenencia , debe reconsiderar su decisión de hacer que la clase sea interna (estática o no estática). Las clases internas deben hacerse cuando deseamos encapsular una responsabilidad secundaria a una entidad. Esto hace que la responsabilidad relacionada siga siendo coherente. Iterator es parte de cualquier Colección y, por lo tanto, es una clase interna. La clase AsyncTask personalizada definida en la clase de actividad personalizada en Android a menudo se realiza como estática privada (con una referencia débil de actividad de clase externa) para la fuga de actividad anterior, ya que la intención es modificar los campos que son privados.

P.S: el compilador de Afer compila el código que genera archivos separados para la clase interna y puede consultar el enlace para entender cómo la interacción de los campos de una clase accesibles a otra clase ocurre cuando otra clase se define como clase interna https://stackoverflow.com/a/24312109/504133. En realidad, el compilador inyecta getters y setters sintéticos en el código para que la clase estática anidada pueda acceder a los campos privados utilizando estos. Pero aún así, esta es una tarea de backend realizada por herramientas de idioma.

0
nits.kk 4 oct. 2018 a las 22:28