2010-08-22 43 views
13

Me gustaría saber qué está sucediendo en el siguiente ejemplo (donde se accede a un miembro protegido desde fuera del paquete a través de una subclase).Java: acceso protegido en los paquetes

Sé para las clases fuera del paquete, la subclase puede ver el miembro protegido solo a través de la herencia.

Hay dos paquetes: package1 y package2.

  1. package1: ProtectedClass.java

    package org.test.package1; 
    
    public class ProtectedClass { 
    
        protected void foo() { 
         System.out.println("foo"); 
        } 
    } 
    
  2. package2: ExtendsprotectedClass.java

    package org.test.package2; 
    
    import org.test.package1.ProtectedClass; 
    
    public class ExtendsprotectedClass extends ProtectedClass { 
    
        public void boo() { 
         foo(); // This works, 
           // since protected method is visible through inheritance 
        } 
    
        public static void main(String[] args) { 
         ExtendsprotectedClass epc = new ExtendsprotectedClass(); 
         epc.foo(); // Why is this working? 
            // Since it is accessed through a reference, 
            // foo() should not be visible, right? 
        } 
    } 
    
  3. package2: UsesExtendedClass.java

    package org.test.package2; 
    
    public class UsesExtendedClass { 
    
        public static void main(String[] args) { 
         ExtendsprotectedClass epc = new ExtendsprotectedClass(); 
         epc.foo(); // CompilationError: 
            // The method foo() from the type ProtectedClass 
            // is not visible 
        } 
    } 
    

Se entiende que el método de boo() en ExtendsprotectedClass puede acceder foo(), ya que los miembros protegidos se puede acceder a través de la herencia solamente.

Mi pregunta es, ¿por qué es el método foo() trabajando muy bien cuando se accede a través de una referencia en el método de ExtendsprotectedClass pero main() no funcionará cuando se accede a través de la referencia epc en UsesExtendedClass?

Respuesta

12

El código dentro de la clase ExtendsprotectedClass tiene permitido el acceso a miembros protegidos de ProtectedClass a través de una referencia de tipo ExtendsprotectedClass. Desde el JLS section 6.6.2:

Un miembro protegido o constructor de un objeto se puede acceder desde el exterior del paquete en el que se declara únicamente por el código que se encarga de la aplicación de dicho objeto.

y

Sea C la clase en la que se declara un miembro protegido m. se permite el acceso sólo dentro del cuerpo de una subclase S de C. Además, si Id denota un campo de instancia o método de instancia, entonces:

  • Si el acceso es por un nombre calificado Q.Id, donde Q es un ExpressionName, entonces el acceso es permitido si y sólo si el tipo de la expresión Q es S o una subclase de S. [...]

UsesExtendedClass dirección no es responsable de la ejecución de ExtendsprotectedClass, por lo tanto, la llamada final falla.

EDITAR: El razonamiento detrás de esto es que el acceso protected está diseñado para ayudar a las subclases a implementar la funcionalidad que necesitan, dando más acceso a las partes internas de la superclase de lo que normalmente estaría disponible.Si estuviese disponible para todo el código, estaría muy cerca de hacer que el método sea público. Básicamente, se confía en que las subclases no rompan la encapsulación; se les da más capacidades dentro de los objetos de su propio tipo. La API pública no debe exponer esos detalles, pero la API protegida solo puede dar más oportunidades a las subclases.

+0

@Jon Gracias. Entiendo que los miembros de la clase de la subclase pueden acceder a los miembros protegidos (como se indica en el método 'boo()'). Pero ¿Tenía curiosidad por saber por qué se le permite acceder al miembro protegido a través de una referencia de la subclase, ** SOLO ** en los métodos de las subclases? cualquier razonamiento detrás de esto? – JWhiz

+0

@JWhiz: Editando ... –

+1

2) Funciona porque se accede al método protegido mediante un puntero de su propia clase. Esto debería fallar:
public static void ExtendsprotectedClass.main (String [] args) { ProtectedClass epc = new ExtendsprotectedClass(); // upcast
epc.foo(); // debería ser un error de compilación?
} –

1

Creo que ha respondido a su propia pregunta; UsesExtendedClass no hereda de ProtectedClass y, por definición, los miembros "protegidos" son accesibles solo en la clase en la que se declaran/definen o en una clase que hereda de la que se declararon o definieron.

+2

'por definición, los miembros" protegidos "son accesibles solo en la clase en la que se declaran/definen'. No estoy del todo de acuerdo con eso, ya que los miembros protegidos son accesibles desde otras clases dentro del mismo paquete sin herencia. – JWhiz

2

Está trabajando en el primer caso porque se está llamando desde la misma clase, incluso se está accediendo al método a través de una referencia. Incluso puede llamar al método private de ExtendsprotectedClass a través de una referencia en el mismo método principal.

+1

Gracias. Ahora veo por qué es capaz de acceder a él a través de la referencia. '+ 1' para eso. Pero, no debería permitirse llamar a métodos 'privados' a través de un derecho de referencia de objeto? ¿Esto no viola el objetivo de hacerlo 'privado'? ¿Alguna razón específica para permitirlo? – JWhiz

+1

@JWhiz los modificadores de acceso de Java funcionan en clase y no a nivel de instancia. Por eso, un método privado es privado para la clase y no una instancia. Si el privado trabajó en instancias, tendrías que hacer públicas más variables y métodos si dos instancias tienen que interactuar. Esto rompería la encapsulación haciendo visible la implementación fuera de la clase. – josefx

Cuestiones relacionadas