objetos - que es una instancia en java
¿Por qué las variables de instancia en Java son siempre privadas? (9)
Soy novato en Java y estoy aprendiendo sobre la encapsulación y vi un ejemplo donde las variables de instancia se declaran como privadas en una clase.
http://www.tutorialspoint.com/java/java_encapsulation.htm
Tengo 2 consultas:
- ¿Por qué son privadas las variables de instancia? ¿Por qué no público?
- ¿Qué pasa si las variables de instancia se hacen públicas y se accede directamente? ¿Vemos alguna restricción?
¿Puede explicar con un ejemplo lo que irá mal en caso de que las variables de instancia se declaren públicas en una clase en Java?
Hacer que las variables de instancia sean públicas o privadas es un compromiso de diseño que el diseñador hace cuando declara las clases. Al hacer públicas las variables de la instancia, expone los detalles de la implementación de la clase, lo que proporciona una mayor eficiencia y concisión de la expresión a expensas de obstaculizar los futuros esfuerzos de mantenimiento. Al ocultar los detalles de la implementación interna de una clase, tiene la posibilidad de cambiar la implementación de la clase en el futuro sin romper ningún código que use esa clase.
Para usuario de clase.
Nosotros, que estamos utilizando ide como eclipse, netbins ..... vimos que nos sugiere un método público, por lo que si el creador de la clase proporciona getter y setter para la variable de instancia privada, no tiene que memorizar el nombre de la variable. simplemente escriba set, presione ctrl + espacio y obtendrá todos los métodos de creación creados por el creador de esa clase y elija el método que desee para establecer el valor de la variable.
Para creador de clase.
A veces es necesario especificar alguna lógica para establecer el valor de la variable. "Supongamos que tienes una variable entera que debería almacenar 0
Porque si cambias la estructura de la clase (quitando campos etc.); causará errores. Pero si tiene un método
getX()
, puede calcular el valor necesario allí (si se eliminó el campo).Usted tiene el problema, entonces, que la clase no sabe si algo ha cambiado y no puede garantizar la integridad.
Como ya han señalado varios respondedores, las variables de instancia no tienen que ser private
, pero por lo general no se hacen public
para preservar la encapsulación.
Vi un ejemplo en (creo) Código limpio, que ilustra muy bien esto. Si recuerdo correctamente, era un tipo complejo (como en a+bi
); En cualquier caso, algo muy parecido a eso, no tengo el libro a mano. Expuso métodos para obtener el valor de las partes reales e imaginarias, así como un método para establecer el valor de la instancia. La gran ventaja de esto es que permite que la implementación se reemplace por completo sin afectar a ningún consumidor del código. Por ejemplo, los números complejos se pueden almacenar en una de dos formas: como coordenadas en el plano complejo ( a+bi
), o en forma polar ( φ
y |z|
). Mantener el formato de almacenamiento interno como un detalle de implementación le permite cambiar de un lado a otro mientras expone el número en ambos formularios, lo que le permite al usuario de la clase elegir el que sea más conveniente para la operación que está realizando actualmente.
En otras situaciones, puede tener un conjunto de campos relacionados, como el campo x
debe tener ciertas propiedades si el campo y
está dentro de un rango determinado. Un ejemplo simplista sería donde x
debe estar en el rango y
hasta y+z
, para valores numéricos y algún valor arbitrario z
. Al exponer accesores y mutadores, puede imponer esta relación entre los dos valores; Si expone las variables de instancia directamente, el invariante se desintegra inmediatamente, ya que no puede garantizar que alguien establezca una pero no la otra, o las establezca para que la invariante ya no sea válida.
Por supuesto, considerando la reflexión, todavía es posible acceder a miembros que no debería, pero si alguien está reflexionando sobre su clase para acceder a miembros privados, es mejor que se den cuenta de que lo que están haciendo puede romper las cosas. Si están utilizando la interfaz pública, pueden pensar que todo está bien, y luego terminan con errores desagradables porque, sin saberlo, no se adhirieron completamente a los detalles de implementación de su implementación en particular.
En el diseño tradicional orientado a objetos, una clase encapsulará tanto los datos (variables) como el comportamiento (métodos). Tener datos privados le dará flexibilidad en cuanto a cómo se implementa el comportamiento, por lo que, por ejemplo, un objeto podría almacenar una lista de valores y tener un método getAverage () que calcula y devuelve la media de estos valores. Más adelante, podría optimizar y almacenar en caché el promedio calculado en la clase, pero el contrato (es decir, los métodos) no tendría que cambiar.
Se ha vuelto más popular en los últimos años (para bien o para mal) el uso de modelos de datos anémicos , donde una clase no es más que un montón de campos y los captadores y definidores correspondientes. Yo diría que en este diseño estarías mejor con los campos públicos, ya que los captadores y definidores no proporcionan una encapsulación real, sino que te hacen creer que estás haciendo OO real.
ACTUALIZACIÓN: El ejemplo dado en el enlace de la pregunta es un ejemplo perfecto de esta encapsulación degenerada. Me doy cuenta de que el autor está tratando de proporcionar un ejemplo simple, pero al hacerlo, no logra transmitir ningún beneficio real de la encapsulación (al menos no en el código de ejemplo).
En primer lugar, no es cierto que todas las variables de instancia sean privadas. Algunos de ellos están protegidos, lo que aún conserva la encapsulación.
La idea general de la encapsulación es que una clase no debe exponer su estado interno. Solo debe usarlo para realizar sus métodos. La razón es que cada clase tiene un llamado "espacio de estado". Es decir, un conjunto de valores posibles para sus campos. Puede controlar su espacio de estado, pero si lo expone, otros podrían ponerlo en un estado no válido.
Por ejemplo, si tiene dos campos booleanos y la clase puede funcionar correctamente solo en 3 casos: [falso, falso], [falso, verdadero] y [verdadero, falso]. Si hace que los campos sean públicos, otro objeto puede establecer [verdadero, verdadero], sin conocer las restricciones internas, y el siguiente método llamado en el objeto original activará resultados inesperados.
Las variables de instancia se hacen privadas para obligar a los usuarios de esa clase a usar métodos para acceder a ellas. En la mayoría de los casos, existen captadores y definidores sencillos, pero también se pueden utilizar otros métodos.
El uso de métodos le permitiría, por ejemplo, restringir el acceso a solo lectura, es decir, un campo puede leerse pero no escribirse, si no hay un configurador. Eso no sería posible si el campo fuera público.
Además, puede agregar algunas verificaciones o conversiones para el acceso de campo, lo que no sería posible con un acceso simple a un campo público. Si un campo era público y luego desea forzar todo el acceso a través de algún método que realice verificaciones adicionales, etc., tendría que cambiar todos los usos de ese campo. Si lo haces privado, tendrías que cambiar los métodos de acceso más adelante.
Si el phone
era privado:
Considere este caso:
class Address {
private String phone;
public void setPhone(String phone) {
this.phone = phone;
}
}
//access:
Address a = new Address();
a.setPhone("001-555-12345");
Si comenzáramos con una clase como esta y luego se requeriría realizar verificaciones en el Número de teléfono (por ejemplo, una longitud mínima, solo dígitos, etc.) solo tendría que cambiar el configurador:
class Address {
private String phone;
public void setPhone(String phone) {
if( !isValid( phone) ) { //the checks are performed in the isValid(...) method
throw new IllegalArgumentException("please set a valid phone number");
}
this.phone = phone;
}
}
//access:
Address a = new Address();
a.setPhone("001-555-12345"); //access is the same
Si el phone
fuera público:
Alguien podría configurar un phone
como este y no podrías hacer nada al respecto:
Address a = new Address();
a.phone="001-555-12345";
Si ahora quiere forzar que se realicen las verificaciones de validación, tendrá que hacerlo privado y quien haya escrito las líneas anteriores tendría que cambiar la segunda línea a esto:
a.setPhone("001-555-12345");
Por lo tanto, no podría simplemente agregar las comprobaciones sin romper otro código (ya no se compilaría más).
Además, si accede a todos los campos / propiedades de una clase a través de métodos, mantendrá el acceso consistente y el usuario no tendrá que preocuparse de si la propiedad está almacenada (es decir, es un campo de instancia) o calculada (solo hay métodos y no hay campos de instancia). ).
Mantener los campos privados tiene muchas ventajas como se sugirió anteriormente. El siguiente mejor nivel es mantener el paquete privado usando el nivel de acceso predeterminado de Java.
El nivel predeterminado evita el desorden en su propio código y evita que los clientes de su código establezcan valores no válidos.
No tienen que ser privados, pero deberían serlo. Un campo es un detalle de implementación , por lo que debe mantenerlo en privado. Si desea permitir que los usuarios obtengan o establezcan su valor, utiliza las propiedades para hacerlo (métodos de obtención y configuración): esto le permite hacerlo de manera segura (por ejemplo, validando la entrada) y también le permite cambiar los detalles de la implementación (por ejemplo, delegar algunos de los valores a otros objetos, etc.) sin perder la compatibilidad con versiones anteriores.