¿Por qué se puede acceder a un miembro privado en un método estático?


25

El siguiente es un pseudocódigo, lo probé en Java y PHP y ambos funcionaron:

class Test { 

    private int a = 5;

    public static function do_test(){
        var t = new Test();
        t.a = 1;
        print t.a // 1
    }

}

Test::do_test();

¿Por qué puedes hacer esto en el paradigma OOP y de qué sirve?


66
¿Por qué no lo sería? En Java, los miembros privados no son privados para la instancia, sino privados para el archivo fuente . El primer uso que viene a la mente es equalsque tiene que verificar los campos privados de otra instancia. (Publicación como comentario, ya que es breve, y nada sobre la OOP-ness de este enfoque)
Ordous

2
Tenga en cuenta que los métodos estáticos no tienen un this, por lo que los únicos objetos de su propia clase a los que pueden acceder son los que crean ellos mismos (o que se pasan como un parámetro). Entonces, si considera que esto es una violación de la encapsulación o un agujero de seguridad, no es que sea muy grande, y puede que no valga la pena taparlo.
Kilian Foth

44
No estoy seguro de por qué esto fue rechazado. La pregunta puede ser trivial (ish), pero el OP pasó por la molestia de probar el comportamiento en dos idiomas antes de preguntar. Eso es mucho más esfuerzo de lo que generalmente vemos en los recién llegados.
yannis

1
@YannisRizos De acuerdo, y de hecho no creo que la pregunta sea trivial. Tiene implicaciones para seguir el "principio del mínimo privilegio". Significa que las funciones auxiliares que no necesitan acceso a las partes internas de una instancia deben definirse en una clase separada y, por el contrario, cuando se sigue esta convención, sabría que siempre que existe un método estático dentro de la misma clase, está accediendo al estado interno.
Doval

1
De hecho, cuando pregunté a mis colegas, todos dijeron que esto era imposible. Es por eso que no pensé que fuera trivial
Ben

Respuestas:


17

En Java, las variables privadas son visibles para toda la clase. Se puede acceder desde métodos estáticos y desde otras instancias de la misma clase.

Esto es, por ejemplo, útil en los métodos de fábrica . Un método de fábrica generalmente inicializa un objeto que es tan complejo que no desea dejarlo en el código de la aplicación. Para realizar la inicialización, el método de fábrica a menudo necesita acceso a los elementos internos de clase que no desea exponer. Ser capaz de acceder a las variables privadas directamente hace que su vida sea mucho más fácil.

Sin embargo, cuando desea ocultar los detalles de implementación de una clase incluso de métodos estáticos o de otras instancias de esa clase, puede seguir el patrón de datos de la clase privada . Coloque todas las variables privadas de una clase en una clase interna privada y delegue cualquier getters o setters a getters y setters de esa clase interna.

Otra opción es definir una interfaz para la clase que declare todos los métodos públicos de la clase y luego solo haga referencia a la clase bajo esa interfaz siempre que sea posible. Una referencia al tipo de interfaz no se puede utilizar para acceder directamente a nada no declarado en la interfaz, sin importar dónde (excepto con reflexión, por supuesto). Cuando utiliza un lenguaje de programación orientado a objetos que no tiene interfaces (como C ++, por ejemplo), se pueden simular con una clase base abstracta que la clase real hereda.

interface ITest {
     public int getA();
}

class Test implements ITest { 

    private int a = 5;

    public int getA() { return a; } // implementation of method declared in interface

    public static void main(){
        ITest t = new Test();
        t.a = 1; // syntax error: Interface ITest has no "a"
        System.out.println(t.getA()); // calls Test.getA, visible because ITest declares it
    }

}

¿Puedes pensar en una situación en la que el patrón de datos de clase privada es útil? Yo personalmente uso clases internas solo en GUI como configuraciones (Swing, etc.) o clases internas estáticas en ejercicios de codificación ya que no quiero que un ejercicio abarque múltiples archivos fuente.
InformadoA

1
Ocultar las partes internas de una clase de otras instancias elimina una de las ventajas que las clases tienen sobre las interfaces sin obtener nada a cambio. Una solución más simple y flexible es usar una interfaz.
Doval

3

Algunos lenguajes y frameworks de tiempo de ejecución (por ejemplo, Java, .NET) suponen que cualquier persona que esté compilando el código para una clase en particular puede confiar en que no usará ningún miembro privado de ninguna instancia de esa clase de manera que sea perjudicial para su correcto operación. Otros lenguajes y marcos son más restrictivos en ese sentido, y no permiten el acceso a miembros privados de una instancia, excepto por el código que se ejecuta en esa instancia . Ambos diseños tienen ventajas y desventajas.

La mayor ventaja de permitir que cualquier código dentro de una clase acceda a miembros privados de cualquier instancia es que hay casos en los que ese nivel de acceso es apropiado, y tener privatetrabajo de esa manera elimina la necesidad de tener un calificador de acceso diferente disponible para ese propósito o de lo contrario, forzará el código para exponer a los miembros de manera más amplia de lo que sería ideal.

Una ventaja de no permitir dicho acceso (como fue el caso en el Modelo de objetos comunes de Microsoft (COM)) es que permite que el código externo trate las clases como interfaces. Si una clase ImmutableMatrixcontiene un double[][]campo de respaldo privado o protegido , y si el código dentro de la clase examina la matriz de respaldo de otras instancias, entonces no será posible definir una clase sin respaldo de matriz (por ejemplo ZeroMatrix, IdentityMatrix) que el código externo podría usar como an Immutable2dMatrix, sin que esa clase tenga que incluir el campo de respaldo. Si nada en el interior Immutable2dMatrixutiliza miembros privados de cualquier otra instancia que no sea this, entonces sería posible cambiar el nombre de la clase ImmutableArrayBackedMatrixy definir una nueva ImmutableMatrixclase abstracta que podría tener ImmutableArrayBackedMatrixcomo subtipos las clases no respaldadas por matriz mencionadas anteriormente.

Tenga en cuenta que dicha refactorización no se evitaría si el lenguaje "permitiera" ImmutableMatrixexaminar la matriz de respaldo para instancias distintas this, a menos que el lenguaje aprovechara esa capacidad y realmente examinara instancias externas. El efecto principal de tener un lenguaje que restringe dicho uso es que hará que el compilador grazne inmediatamente en cualquier intento de escribir código que no sea susceptible de tal refactorización.


2

Java no es estrictamente un lenguaje orientado a objetos, sino un lenguaje basado en clases : la clase determina las operaciones y el acceso al comportamiento en lugar de la instancia.

Así que no se sorprenda demasiado de que le permita hacer cosas que no estén estrictamente orientadas a objetos.

Dado que el método está en el mismo ámbito de clase que la instancia, tiene acceso completo a miembros privados. Reglas similares gobiernan instancias de clases internas que acceden a datos de instancias de clases externas: una instancia de una clase interna puede acceder a miembros privados de la clase externa.

Esto se hereda de C ++, donde es útil para crear constructores de copiar y mover. También es útil para comparar o combinar dos objetos en los que su valor depende de miembros a los que no se puede acceder públicamente de manera eficiente (por ejemplo, el captador de una matriz en Java debe copiar la matriz para que el código del cliente no pueda modificarla, cambiando el estado interno del objeto, pero tener que copiar matrices para comparar la igualdad de objetos no es eficiente)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.