¿Qué son los modificadores de acceso?
Básicamente declaran la accesibilidad de un método, clase, constructor o campo en el proyecto, y sirven para definir de que manera el cliente debería o no tener acceso.
public
No hay mucho que explicar de este modificador, su nombre ya nos dice todo, una clase, método, constructor o campo declarado con el modificador public
será en efecto, público, es decir, que cualquier otra clase podrá acceder a él, independiente del paquete en el que se encuentre la clase que acceda a este.
Ej: Crearemos una clase pública, que se encontrará en el package org.A
.
package org.A;
public class A {
public int value; // <--- campo público!
public A() { // <-- constructor público!
this.value = 5;
}
public void changeValue(int value) { // <-- método público
this.value = value;
}
}
Luego creamos la clase no pública D
en el package org.poo.D
y crearemos una instancia de A
y usaremos sus campos y métodos.
package org.poo.D;
class D {
A a = new A();
int val = a.value;
int myOtherMethod() {
a.changeValue(4);
}
}
La clase A
es totalmente publica, es decir, que podemos utilizarla en otras clases sin excepción.
private
Sólo la misma clase que contiene el método, constructor, clase o campo, puede tener acceso.
Siguiendo el ejemplo anterior, ahora le cambiaremos el modificador public
por private
al campo value
.
package org.A;
public class A {
public int value;
private int value;
public A() {
this.value = 5;
}
public void changeValue(int value) {
this.value = value;
}
}
Como cambiamos el modificador del campo value
a private
, ahora la clase D
no podrá acceder a este campo y el compilador o IDE nos mostrará un error.
package org.C.D;
class D {
A a = new A();
int val = a.value; // el campo pubValue no es accesible
int myOtherMethod() {
a.changeValue(4);
}
}
Cabe destacar que aún se puede cambiar el valor del campo value
en la clase D
, llamando al método changeValue
, ya que, este método sigue siendo público, y como su implementación existe dentro de la clase A
, puede acceder al campo value
.
package-private
Quizás te haz hecho la pregunta, ¿Qué pasa si no declara ningún modificador?
El código sigue siendo valido, cuando no se declara ningún modificador, el acceso por defecto es package-private
.
Este acceso hace que los elementos de la clase sean public
a nivel de paquete, pero private
para clases de paquetes externos.
Ej. Supongamos que creamos otra clase llamada B
en el paquete org
, la clase B
estará al mismo nivel que la clase A
.
package org.A;
class A {
int value;
A() {
this.value = 5;
}
void changeValue(int value) {
this.value = value;
}
}
package org.B;
class B {
A a = new A();// Accesible!
int val = a.value;// Accesible!
}
Ahora crearemos otra clase E
y esta vivirá en el paquete com
.
package com.E;
class E {
A a = new A(); // el constructor no es accesible
int val = a.pubValue; // el campo pubValue no es accesible
int myOtherMethod() {
a.changePubValue(4); // el método no es accesible
}
}
Por lo tanto, el modificador de acceso por defecto package-private
, sólo permite el acceso a clases de su mismo paquete.
protected
El elemento en cuestión será solo accesible por otras clases si:
- Existe en el mismo paquete.
- Extiende a la clase.
Ej. Tomaremos la clase A
y agregaremos al método changeValue
el modificador protected
.
package org.A;
public class A {
int value;
public A() {
this.value = 5;
}
void changeValue(int value) {
protected void changeValue(int value) {
this.value = value;
}
}
el método changeValue
será sólo accesible a través de la extension de la clase A
o si existe en el mismo paquete, en este ejemplo, el paquete org
es donde coexisten estas clases, por lo tanto, F
no tiene necesidad de extender a A
para acceder al método con el modificador protected
y puede acceder a través de la creación de una instancia de A
.
package org.F;
class F {
A a = new A();
int myOtherMethod() {
a.changeValue(3); // Accesible!
}
}
Pero si movemos la clase F
a otro paquete, esta perderá el acceso a los elementos con el modificador protected
.
package poo.F;
class F {
A a = new A();
int myOtherMethod() {
a.changeValue(3); // Method'setValue(int)' has protected access in 'org.A'
}
}
La única forma de poder acceder al elemento con el modificador protected
es extendiendo la clase A
.
package poo.F;
class F extends A {
F(int value) {
super(value)
}
int myOtherMethod() {
this.changeValue(3); // Accesible!
}
}
Como se puede observar, este modificador es parecido modificador por defecto package-private
, con la única diferencia que package-private
no posee la opción de acceder a los elementos extendiendo la clase.
Conclusión
Recordar que en la clase donde se declaren los elementos, estos siempre serán accesibles. Las restricciones de acceso siempre son externas, es decir, restringen el acceso a otras clases que hagan uso del elemento.
Crear constructores con private
puede ayudarte a declarar que no deberían crearse instancias de esa clase, o también para implementar el patrón de diseño Singleton.
Siempre es buena idea partir construyendo los métodos y campos con el modificador más restrictivo en este caso private
e ir cambiándolo a medida que sea necesario.