En Java, ¿por qué los miembros protegidos se hicieron accesibles a las clases del mismo paquete?

14

De la documentación oficial ...

Modifier    Class   Package Subclass    World 
public      Y       Y       Y           Y 
protected   Y       Y       Y           N 
no modifier Y       Y       N           N 
private     Y       N       N           N 

El problema es que no recuerdo haber tenido un caso de uso en el que tuviera que acceder a miembros protegidos de una clase dentro del mismo paquete.

¿Cuáles fueron las razones detrás de esta implementación?

Editar: Para aclarar, estoy buscando un caso de uso específico en el que tanto una subclase como una clase dentro del mismo paquete necesiten acceder a un campo o método protegido.

package some.package;
public class A {
 protected void protectedMethod(){
  // do something
 }
}

package another.package;
public class B extends A{
 public void someMethod(){
  // accessible because B is a subclass of A
  protectedMethod();
 }
} 

package some.package;
public class C {
 public void anotherMethod(){
  // accessible because C is in the same package as A
  protectedMehtod();
 }
}
    
pregunta jramoyo 22.07.2013 - 11:55

7 respuestas

4
  

buscando un caso de uso específico en el que tanto una subclase como una clase dentro del mismo paquete necesiten acceder a un campo o método protegido ...

Bueno, para mí, este caso de uso es más bien general que específico, y se deriva de mis preferencias para:

  1. Comience con el modificador de acceso más estricto posible, recurriendo a uno o más puntos débiles solo más tarde según se considere necesario.
  2. Haga que las pruebas unitarias residan en el mismo paquete que el código probado.

Desde arriba, puedo comenzar a diseñar para mis objetos con los modificadores de acceso predeterminados (comenzaría con private pero eso complicaría las pruebas de unidad):

public class Example {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        void doSomething() {} // default access
    }
    static class Unit2 {
        void doSomething() {} // default access
    }

    static class UnitTest {
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

Nota al margen del fragmento anterior, Unit1 , Unit2 y UnitTest son anidado dentro de Example para simplificar la presentación, pero en un proyecto real, es probable que tenga estas clases en archivos separados (y UnitTest incluso en un directorio separado ).

Luego, cuando surja una necesidad, debilitaría el control de acceso del valor predeterminado a protected :

public class ExampleEvolved {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        protected void doSomething() {} // made protected
    }
    static class Unit2 {
        protected void doSomething() {} // made protected
    }

    static class UnitTest {
        // ---> no changes needed although UnitTest doesn't subclass
        // ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

Verá, puedo mantener el código de prueba de la unidad en ExampleEvolved sin cambios debido a que se puede acceder a los métodos protegidos desde el mismo paquete, aunque acceder al objeto no es una subclase .

Se necesitan menos cambios = > modificación más segura; después de todo, solo cambié los modificadores de acceso y no modifiqué los métodos que realizan Unit1.doSomething() y Unit2.doSomething() , por lo que es natural esperar que el código de prueba de la unidad continúe ejecutándose sin modificaciones.

    
respondido por el gnat 22.07.2013 - 18:40
5

Yo diría que esto tiene dos partes:

  1. El acceso predeterminado, "paquete", es útil en una amplia gama de casos, porque las clases no siempre son una buena unidad de encapsulación. Varios objetos compuestos en los que algunos objetos actúan como una colección de otros objetos, pero los elementos no deben ser modificables públicamente, porque hay algunas invariantes en toda la colección, por lo que la colección debe tener acceso elevado a los elementos. C ++ tiene amigos, Java tiene acceso a paquetes.
  2. Ahora el ámbito de acceso del "paquete" es básicamente independiente del ámbito "subclase" (protegido). Por lo tanto, necesitaría especificadores de acceso adicionales solo para paquete, solo subclases y paquete y subclases. El alcance del "paquete" está más restringido, ya que el conjunto de clases en un paquete es generalmente definido, mientras que una subclase puede aparecer en cualquier lugar. Así que para mantener las cosas simples, Java simplemente incluye el acceso al paquete en el acceso protegido y no tiene un especificador adicional para subclases pero no paquetes. Aunque casi siempre deberías pensar en protected como exactamente eso.
respondido por el Jan Hudec 22.07.2013 - 13:29
5

En mi humilde opinión, esta fue una mala decisión de diseño en Java.

Solo estoy especulando, pero creo que querían que los niveles de acceso estuvieran en una progresión estricta: privado - "paquete" - protegido - público. No querían tener una jerarquía, donde algunos campos estarían disponibles para el paquete pero no las subclases, algunos estarían disponibles para las subclases, pero no el paquete, y otros dos.

Aun así, en mi humilde opinión, deberían haber ido por el otro lado: dicho protegido está visible solo para la clase y las subclases, y ese paquete es visible para la clase, las subclases y el paquete.

A menudo tengo datos en una clase que deben ser accesibles para las subclases, pero no para el resto del paquete. Me cuesta mucho pensar en un caso en el que lo contrario fuera cierto. He tenido algunas raras ocasiones en las que he tenido un conjunto de clases interrelacionadas que necesitan compartir datos pero que deberían mantenerlos a salvo fuera del conjunto. Así que está bien, póngalos en un paquete, etc. Pero nunca he tenido un caso en el que quiera que el paquete comparta datos, pero quiero evitarlo de las subclases. Está bien, puedo imaginar la situación por venir. Supongo que si este paquete es parte de una biblioteca que podría extenderse por clases de las que no sé nada, por las mismas razones por las que haría que los datos de una clase fueran privados. Pero es mucho más común querer que los datos estén disponibles solo para la clase y sus hijos.

Hay muchas cosas que mantengo en privado entre mis hijos y yo y que no compartimos con los vecinos. Hay muy poco de lo que mantengo en privado entre los vecinos y yo, y no lo comparto con mis hijos. :-)

    
respondido por el Jay 14.03.2016 - 05:46
0

Un buen ejemplo que me viene a la mente de inmediato es que las clases de utilidad se usan mucho en el paquete, pero no desea el acceso público (detrás de las escenas, carga de disco, creación / destrucción de identificadores) clases, etc.) en lugar de hacer que todo [el equivalente de Java friend access modifier or idiom en C++ ] de todas las demás clases, todo esté disponible automáticamente.

    
respondido por el Casey 22.07.2013 - 12:37
0

Los casos de uso del modificador de acceso protegido / paquete son similares a los de los modificadores de acceso amigo en C ++.

Un caso de uso es cuando se implementa el patrón Memento .

El objeto de recuerdo necesita acceder al estado interno de un objeto, para mantenerlo, a fin de servir como un punto de control para las operaciones de deshacer.

Declarar la clase en el mismo paquete es una de las posibles formas de lograr el patrón Memento, ya que Java no tiene un modificador de acceso "friend" .

    
respondido por el Tulains Córdova 22.07.2013 - 12:44
-1

simetría?

Es raro que se necesite tal acceso, por lo que el acceso predeterminado se usa tan raramente. Pero a veces los marcos lo desean para el código generado, donde las clases de envoltorio se colocan en el mismo paquete que interactúa con sus clases directamente, yendo a los miembros en lugar de a los que acceden a los elementos de acceso por razones de rendimiento. Piense en GWT.     

respondido por el jwenting 22.07.2013 - 12:12
-1

La jerarquía de encapsulación de Java está bien definida:

Clase - > Paquete - > Herencia

"Protegido" es solo una forma más débil de privacidad que el paquete predeterminado, según lo deciden los diseñadores de Java. El acceso a los elementos predeterminados del paquete está restringido a un subconjunto de las entidades que pueden acceder a los elementos protegidos.

Desde el punto de vista matemático y de la implementación, tiene mucho sentido tener conjuntos de entidades a las que se les permite acceder a cosas para anidar. (No pudo anidar su conjunto de acceso a paquetes dentro de su conjunto de acceso protegido porque las clases pueden heredar de otros paquetes).

Desde un punto de vista conceptual, tiene sentido tener algo en java.util que sea "más amigable" con otra clase en el paquete que algo en com.example.foo.bar que lo clasifique. En el primer caso, es probable que las clases estén escritas por el mismo autor, o al menos por los programadores de la misma organización.

    
respondido por el Rich Smith 22.07.2013 - 17:40

Lea otras preguntas en las etiquetas