viernes, 19 de julio de 2013

Modificador de Acceso: Protected y Default en Java

Modificador de Acceso: Protected y Default en Java

Los niveles de control de acceso protected y por defecto son en mayoría idénticos, pero con una diferencia crítica. Un miembro default puede ser accedido solo si la clase que accede al miembro pertenece al mismo paquete, mientras que un miembro protected puede ser accedido (a través de la herencia) por una subclase incluso si la subclase está en un paquete diferente.
Vamos a ver un ejemplo en estas 2 clases:
--------------------------------------------------
package certification;
 
public class OtherClass {
    void testIt(){
        System.out.println("OtherClass");
    }
}
-------------------------------------------------- 
package somethingElse;
import certification.OtherClass;
 
class AccessClass {
    static public void main (String[] args){
        OtherClass o = new OtherClass();
        o.testIt();
    }
}
--------------------------------------------------
Como podemos ver, el método testIt() en el primer archivo tiene acceso default. Vemos tambien que estáne n diferentes paquetes. ¿Podrá la clase AccessClass usar el método testIt()?¿Creará un error de compilación?.
Probandolo vemos que la clase AccessClass no puede usar el método testIt() de la clase OtherClass porque testIt() tiene acceso default, y AccessClass no está en el mismo paquete que OtherClass.
Default y protected difieren solo cuando hablamos de subclases. Si se usa protected para definir un miembro, cualquier subclase de la clase que declare el miembro puede acceder a el a través de la herencia. No importa si la superclase y la subclase están en diferentes paquetes, el miembro protected de la superclase sigue siendo visible a la subclase (aunque sea visible en una manera muy específica como veremos luego). Esto es un contraste para el comportamientodefault, el cual no permite a una subclase acceder al miembro de la superclase a no ser que la subclase esté en el mismo paquete que al superclase.
Mientras que el acceso por defecto no extiende ninguna consideración especial a las subclases, el modificador protected respeta la relación padre-hijo, incluso cuando el hijo se ha movido fuera y se une a otro paquete. Así, cuando pensemos en el acceso default pensemos en la restricción del paquete, sin excepciones. Pero cuando pensemos en protected, pensemos en paquetes+hijos.
Una clase con un miembro protected está marcando que el miembro está teniendo un acceso a nivel de paquete para todas las clases, pero con una excepción especial para las subclases fuera dl paquete.
Pero ¿Qué significa que una subclase fuera de un paquete tenga acceso a un miembro de la superclase? Significa que la subclase hereda el miembro. Por ejemplo si una subclase fuera de paquete crea una referencia (creando una isntancia de la superclase en algún lugar de su código), la subclase no puede usar el operador (.) en la referencia de la superclase para aceder al miembro protected. Para la subclase fuera de paquete, un miembro protected podría ser tambien default, cuando la subclase esté usando una referencia a la superclase. La subclase puede ser el miembro protected solo a través de la herencia.

Detalles protected

Vamos a ver una variable de instancia protected de una superclase:

package certification;
 
public class Parent {
    protected int x = 9; //acceso protected
}

El código anterior declara la variable x como protected. Esto hace a la variable ser accesible por las otras clases que estén dentro de su mismo paquete (certification), al igual que a todas aquellas subclases que por herencia heredan de la clase Parent fuera del paquete. Ahora vamos a intentar crear una subclase en un paquete diferente, y vamos a hacer el intento de usar la variable x (que la subclase ha heredado):

package other;
import certification.Parent;
public class Child extends Parent{
    public void testIt(){
        System.out.println("x is " + x); //No hay problemas, Child hereda a x
    }    
}
El código anterior compila bien. veamos sin embargo que la clase Child está accediendo a la variable protected por herencia. Vamos a ver que pasa si al subclase Child (fuera del paquete de la superclase) intenta acceder a la variable protected usando una referencia de la clase Parent:

package other;
import certification.Parent;
public class Child extends Parent{
    public void testIt(){
        System.out.println("x is " + x); //No hay problema
        Parent p = new Parent(); // ¿Podremos acceder a x?
        System.out.println("x in Parent is " + p.x); //Error de compilación
    }
}

Como vemos no se puede acceder a un miembro protected por medio de una referencia a la superclase con el miembro protegido si está fuera del paquete.

"Para una subclase fuera del paquete, el miembro protected solo puede ser accedido por herencia."

Pero puede surgir aun un problema peor, ¿Qué pasa si una subclase que está en el mismo paquete que Child, hereda a Child y quiere tener acceso a la variablex? Una vez que la subclase fuera del paquete ha heredado un miembro protected, este miembro (heredado por la subclase) se hace privado a cualquier código que esté fuera de la subclase, con la excepción de las subclases de la subclase. Por lo que si la clase Neighbor instanciara un objeto Child, entonces incluso si la Neighbor está en el mismio paquete que la clase Child, la clase Neighbor no tendrá acceso a la variable protected que ha heredado Child.

Detalles default

Vamos a ver el comportamiento de un miembro con default en una superclase. Vamos a modificar la clase Parent:

package certification;
 
public class Parent {
    int x = 9; //acceso
}

Vemos que no hemos puesto ningún modificador delante de la variable x. Ahora vamos a intentar acceder al miembro desde la clase Child que vimos antes.
Cuando compilamos el archivo Child, tendremos un error. Este error es el mismo que cuando el miembro se declarara como private. La subclase Child (en diferente paquete que la superclase Parent) no puede ver o usar el miembro de la superclase x. Ahora, ¿Qué pasaría con 2 clases en un mismo paquete?:
package certification;
 
public class Parent {
    int x = 9; //acceso default
}
En la siguiente clase tenemos lo siguiente:
package certification;
 
public class Child extends Parent{
    static public void main (String[] args){
        Child sc = new Child();
        sc.testIt();
    }
     
    public void testIt(){
        System.out.println("Variable x is " + x);//No hay problema
    }
}
El anterior archivo compila bien, y la clase Child se ejecuta y muestra el valor de x. Solo hay que recordar que los miembros default son visible a las subclases solo si estas subclases están en el mismo paquete que la superclase.
ESCRITO POR:  David Sastre
TOMADO DE: sekthdroid.wordpress.com/