Acceder al campo privado de otro objeto de la misma clase

91
class Person 
{
   private BankAccount account;

   Person(BankAccount account)
   {
      this.account = account;
   }

   public Person someMethod(Person person)
   {
     //Why accessing private field is possible?

     BankAccount a = person.account;
   }
}

Olvídate del diseño. Sé que OOP especifica que los objetos privados son privados para la clase. Mi pregunta es, ¿por qué se diseñó OOP de manera que los campos privados tengan acceso a nivel de clase y no acceso a nivel de objeto ?

Nageswaran
fuente
5
Creo que el OP considera que el objeto "Persona" pasado a "algún método" es un objeto separado y, por lo tanto, el método no debería tener acceso a sus miembros privados ... aunque está dentro de la clase "Persona".
Inisheer
1
Algunos idiomas no hacen esto (Newspeak, por ejemplo). No es probable que obtenga una buena respuesta sobre el por qué. Obtendrá respuestas trabajando al revés de lo que se especifique.
Tom Hawtin - tackline
El someMethodno es válido. No devuelve nada. Debe ser void.
Nicolas Barbulesco
1
Si este no fuera el caso, sería muy difícil escribir el constructor de copia y el operador de asignación imo.
rozina

Respuestas:

69

También tengo un poco de curiosidad por la respuesta.

La respuesta más satisfactoria que encuentro es de Artemix en otra publicación aquí (estoy cambiando el nombre de la clase AClass con la clase Person): ¿Por qué tener modificadores de acceso a nivel de clase en lugar de nivel de objeto?

El modificador privado aplica el principio de encapsulación.

La idea es que el 'mundo exterior' no debería realizar cambios en los procesos internos de Person porque la implementación de Person puede cambiar con el tiempo (y tendría que cambiar todo el mundo exterior para corregir las diferencias en la implementación, lo cual es casi imposible).

Cuando la instancia de Person accede a los componentes internos de otra instancia de Person, puede estar seguro de que ambas instancias siempre conocen los detalles de la implementación de Person. Si se cambia la lógica de los procesos internos de Persona, todo lo que tiene que hacer es cambiar el código de Persona.

EDITAR: vote la respuesta de Artemix. Solo lo estoy copiando y pegando.

Iwan Satria
fuente
4
Probablemente esta sea la razón. Pero esta es una mala idea . Esto fomenta las malas prácticas. Un desarrollador que accede a un campo de Person, en la clase Person, no tiene que conocer la implementación de toda la clase. La buena práctica es utilizar el descriptor de acceso, sin tener que saber qué operaciones realiza.
Nicolas Barbulesco
16
@NicolasBarbulesco Creo que la razón dada en la respuesta es sólida. Digamos, por ejemplo, que desea implementar el equals(Object)método en una clase Java para verificar la igualdad de un Personobjeto con otra instancia de Person. Es posible que desee habilitar el mundo exterior para verificar si las dos instancias son iguales, pero es posible que no desee exponer todos los campos privados de la clase necesarios para verificar la igualdad con el mundo exterior utilizando métodos de acceso público. Tener acceso a los privatecampos a nivel de clase permite implementar tal método sin la necesidad inducida de implementar tales métodos públicos.
Malte Skoruppa
1
@MalteSkoruppa: este es un buen ejemplo (implementación del método equals).
Nicolas Barbulesco
@MalteSkoruppa: sin embargo, la implementación del método equalsse puede realizar llamando a los accesos privados.
Nicolas Barbulesco
@NicolasBarbulesco Sí, por supuesto, pero el punto es que, ya sea que use accesos privados o acceda directamente a campos privados para implementar el método, privatedebe otorgar acceso a nivel de clase. Estoy de acuerdo en que usar accesos es generalmente un buen hábito, aunque en este caso es principalmente una cuestión de contexto y estilo personal. Tenga en cuenta que tanto Joshua Bloch en Effective Java (elemento 8) como Tal Cohen en este artículo del Dr. Dobbs acceden directamente a los campos privados en sus listas de códigos cuando discuten cómo implementar equals.
Malte Skoruppa
17

Consulte la Especificación del lenguaje Java, Sección 6.6.1. Determinar la accesibilidad

Afirma

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

Haga clic en el enlace de arriba para obtener más detalles. Entonces la respuesta es: porque James Gosling y los otros autores de Java decidieron que fuera así.

jlordo
fuente
17

Buena pregunta. Parece que el modificador de acceso a nivel de objeto aplicaría el principio de encapsulación aún más.

Pero en realidad es al revés. Pongamos un ejemplo. Suponga que desea realizar una copia profunda de un objeto en un constructor, si no puede acceder a los miembros privados de ese objeto. Entonces, la única forma posible es agregar algunos accesores públicos a todos los miembros privados. Esto hará que sus objetos estén desnudos para todas las demás partes del sistema.

Entonces, la encapsulación no significa estar cerrado al resto del mundo. Significa ser selectivo sobre a quién quiere estar abierto.

Wei Qiu
fuente
2
¡Esta respuesta debe ser votada a favor! Otras respuestas simplemente reafirman la 'regla', pero solo esta realmente revela la razón detrás de la regla y da en el clavo.
mzoz
4
Pero, ¿no sería mejor que un objeto se encargara de proporcionar copias de sí mismo? Entonces, si necesita una copia profunda de un objeto, no importa si es otro objeto de la misma clase o un objeto de una clase diferente: es el mismo mecanismo, o.deepCopy()o lo que sea.
dirtside
4

Esto funciona porque estás en el class Person- una clase tiene permitido hurgar dentro de su propio tipo de clase. Esto realmente ayuda cuando desea escribir un constructor de copia, por ejemplo:

class A
{
   private:
      int x;
      int y;
   public:
      A(int a, int b) x(a), y(b) {}
      A(A a) { x = a.x; y = y.x; }
};

O si queremos escribir operator+y operator-para nuestra clase de números grandes.

Mats Petersson
fuente
Esto es algo similar a la inyección de dependencia. En el que también puede inyectar el objeto de otra clase, donde no puede acceder a la variable privada.
Nageswaran
Claro, si está tratando de construir una clase A a partir de un objeto de clase B, y B tiene un componente privado, entonces A debe ser declarado amigo o solo puede ver partes públicas [posiblemente protegidas, si A se deriva de B ].
Mats Petersson
En java y .net no existe el concepto de amigo. En tales casos, ¿cómo manejar esto?
Nageswaran
1

Solo mis dos centavos sobre la cuestión de por qué la semántica de la visibilidad privada en Java es a nivel de clase en lugar de a nivel de objeto.

Diría que la comodidad parece ser la clave aquí. De hecho, una visibilidad privada a nivel de objeto habría obligado a exponer métodos a otras clases (por ejemplo, en el mismo paquete) en el escenario ilustrado por el OP.

En verdad, no pude ni inventar ni encontrar un ejemplo que muestre que la visibilidad a nivel de clase privada (como la que ofrece Java) crea problemas si se compara con la visibilidad a nivel de objeto privado.

Dicho esto, los lenguajes de programación con un sistema más detallado de políticas de visibilidad pueden permitir tanto la visibilidad de objetos a nivel de objeto como a nivel de clase.

Por ejemplo , Eiffel ofrece exportación selectiva: puede exportar cualquier elemento de clase a cualquier clase de su elección, desde {NINGUNO} (objeto privado) a {CUALQUIER} (el equivalente de público, y también el predeterminado), a {PERSON} (class-private, vea el ejemplo de OP), a grupos específicos de clases {PERSON, BANK}.

También es interesante señalar que en Eiffel no es necesario hacer que un atributo sea privado y escribir un captador para evitar que otras clases le asignen. Los atributos públicos en Eiffel son accesibles por defecto en modo de solo lectura, por lo que no necesita un captador solo para devolver su valor.

Por supuesto, todavía necesita un establecedor para establecer un atributo, pero puede ocultarlo definiéndolo como "asignador" para ese atributo. Esto le permite, si lo desea, utilizar el operador de asignación más conveniente en lugar de la invocación del establecedor.

Agilista temporal
fuente
0

Porque el private modificador de acceso lo hace visible solo dentro de la clase . Este método todavía está EN la clase .

darijan
fuente
Mi pregunta es por qué está diseñado como "dentro de la clase", pero ¿por qué no como "solo dentro del objeto"?
Nageswaran
Porque así es como se hace Java.
darijan
¿Y por qué java hizo java así?
Nageswaran
Java no lo hizo, lo hicieron los creadores de Java. ¿Por qué? ¡Porque son el rock!
darijan
1
Los creadores de Java no lo harán sin ningún motivo, y tiene que haber algún motivo para hacerlo; Estoy preguntando la razón
Nageswaran
0

el privatecampo es accesible en la clase / objeto en el que se declara el campo. Es privado para otras clases / objetos fuera de aquel en el que se encuentra.

ola
fuente
-1

Lo primero que tenemos que entender aquí es que todo lo que tenemos que hacer es seguir los principios oops, por lo que la encapsulación es decir que se envuelven los datos dentro del paquete (es decir, la clase) y luego se representan todos los datos como Objetos y de fácil acceso. por lo que si hacemos que el campo no sea privado, entonces se accede de forma individual. y resulta en mal paratice.

Sachin Jadhav
fuente