Es casi seguro que si usted, querido lector, esta en busqueda de trabajo como desarrollador java, una de las cosas que le preguntaran en las entrevistas será sobre los modificadores de acceso de java. Y es que un buen desarrollador java sabrá aplicar los principios de encapsulamiento y desacoplamiento de la programación orientada a objetos usando estas simples palabras reservadas del lenguaje y una correcta organización de paquetes.
Este articulo se enfoca principalmente en el modificador de acceso “protected” y sobre como usarlo correctamente, para que exista un entendimiento mas profundo de sus implicaciones, y no solo quede solo como una rima pegajosa en la mente de los desarrolladores que lo visiten.
En Java, los campos, constructores, métodos y clases se pueden marcar con modificadores de acceso. Si bien los elementos declarados como private solo pueden ser accedidos por la clase en la que se declaran, la palabra clave protected permite el acceso desde subclases y miembros del mismo paquete.
Al usar la palabra clave protected, tomamos decisiones sobre qué métodos y campos deben considerarse internos de un paquete o jerarquía de clases, y cuáles están expuestos a código externo.
Declaración de campos, métodos y constructores protected
Primero, creemos una clase llamada PrimeraClase que contenga un campo, un método y constructor protegidos:
public class PrimeraClase {
protected String nombre;
protected PrimeraClase (String nombre) {
this.nombre= nombre;
}
protected String getNombre() {
return nombre;
}
}
Con este ejemplo, al usar la palabra clave protected, hemos otorgado acceso a estos campos a las clases en el mismo paquete que PrimeraClase y a las subclases de PrimeraClase.
Acceso a campos, métodos y constructores protegidos
1. Desde el mismo paquete
Ahora, veamos cómo podemos acceder a los campos protegidos creando una nueva ClaseGenerica declarada en el mismo paquete que PrimeraClase:
public class ClaseGenerica{
public static void main(String[] args) {
PrimeraClase primera = new PrimeraClase("Lorenzo Lamas");
System.out.println("el nombre de PrimeraClase es: " + primera.getNombre());
primera.nombre = "El Renegado";
}
}
Como esta clase fue instanciada en el mismo paquete que PrimeraClase , se le permite ver e interactuar con todos los campos, métodos y constructores protected.
2. Desde un paquete diferente
Ahora intentemos interactuar con estos campos desde una clase declarada en un paquete diferente al de PrimeraClase:
public class SegundaClaseGenerica{
public static void main(String[] args) {
PrimeraClase primera = new PrimeraClase("Melissa Joan Hart");
System.out.println("el nombre de PrimeraClase es: " + primera.getNombre());
primera.nombre = "Clarissa Lo Explica Todo";
}
}
Y al tratar de compilar esto obtendremos el error siguiente:
The constructor PrimeraClase(String) is not visible
The method getNombre() from the type PrimeraClaseis not visible
The field PrimeraClase.nombre is not visible
Eso es exactamente lo que esperábamos al usar la palabra clave protected. Esto se debe a que SegundaClaseGenerica no está en el mismo paquete que PrimeraClase y no lo subclasifica.
3. Desde una sub-clase
Veamos ahora qué sucede cuando declaramos una clase que extiende PrimeraClase pero declarada en un paquete diferente:
public class SegundaClase extends PrimeraClase {
public SegundaClase(String nombre ) {
super(nombre );
System.out.println("el nombre de SegundaClase es: " + this.getNombre());
this.nombre = "Bel Air Prince";
}
}
Como se esperaba, podemos acceder a todos los campos, métodos y constructores protected. Esto se debe a que SegundaClase es una subclase de PrimeraClase.
Esto ademas cumple con uno de los princpios SOLID que es el que pone la O en el acronimo el principio Open Close, que discutiremos en algún otro post.
Clase protegida interna
En los ejemplos anteriores, vimos campos protegidos, métodos y constructores en acción. Hay un caso particular más: una clase interna protegida.
Creemos esta clase interna vacía dentro de nuestra PrimeraClase:
package com.ricardogeek.modificadores;
public class PrimeraClase {
// ...
protected static class ClaseInterna {
}
}
Como podemos ver, esta es una clase interna estática, por lo que se puede construir desde fuera de una instancia de PrimeraClase. Sin embargo, como está protegido, solo podemos crear una instancia del código en el mismo paquete que PrimeraClase.
1. Desde el mismo paquete
Para probar esto, editemos nuestra ClaseGenerica:
public class ClaseGenerica{
public static void main(String[] args) {
// ...
PrimeraClase.ClaseInterna interna = new PrimeraClase.ClaseInterna ();
}
}
Como podemos ver, podemos crear una instancia de la clase interna sin ningún problema porque la ClaseGenerica está en el mismo paquete que PrimeraClase.
2. Desde un paquete distinto
Intentemos crear una instancia de ClaseInterna desde SegundaClaseGenerica que, como recordamos, está fuera del paquete de PrimeraClase:
public class SegundaClaseGenerica {
public static void main(String[] args) {
// ...
PrimeraClase.ClaseInterna interna = new PrimeraClase.ClaseInterna ();
}
}
Como se esperaba, obtenemos un error de compilación:
The type PrimeraClase.ClaseInterna is not visible
Desde una sub-clase
Tratemos de hacer lo mismo con nuestra SegundaClase:
public class SegundaClase extends PrimeraClase {
public SegundaClase(String nombre) {
// ...
PrimeraClase.ClaseInterna interna = new PrimeraClase.ClaseInterna ();
}
}
Esperábamos crear una instancia de ClaseInterna con facilidad. Sin embargo, también estamos obteniendo un error de compilación aquí:
The constructor PrimeraClase.ClaseInterna() is not visible
Echemos un vistazo a nuestra declaración de ClaseInterna:
protected static class ClaseInterna {
}
La razón principal por la que recibimos este error es que el constructor predeterminado de una clase protegida está implícitamente protegido. Además, SegundaClase es una subclase de PrimeraClase pero no es una subclase de ClaseInterna. Finalmente, también declaramos SegundaClase fuera del paquete PrimeraClase.
Por todas estas razones, SegundaClase no puede acceder al constructor ClaseInterna protegido.
Si quisiéramos resolver este problema y permitir que nuestra SegundaClase instanciara un objeto ClaseInterna, podríamos declarar explícitamente un constructor público:
protected static class ClaseInterna {
public ClaseInterna() {
}
}
Al hacer esto, ya no obtenemos un error de compilación, y ahora podemos crear una instancia de ClaseInterna desde SegundaClase.