Pregunta En Java, la diferencia entre el paquete privado, público, protegido y privado


En Java, ¿existen reglas claras sobre cuándo usar cada uno de los modificadores de acceso, es decir, el predeterminado (paquete privado), public, protected y privatemientras haces class y interface y lidiando con la herencia?


2490
2017-10-18 19:53


origen


Respuestas:


El tutorial oficial puede ser de alguna utilidad para ti.

            │ Clase │ Paquete │ Subclase │ Subclase │ Mundo
            │ │ same (mismo paquete) │ (paquete diff) │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
público │ + │ + │ + │ + │ +
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
protegido │ + │ + │ + │ + │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
sin modificador │ + │ + │ + │ │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
privado │ + │ │ │ │

+: accesible
blanco: no accesible

4645
2017-10-18 19:57



(Advertencia: no soy un programador de Java, soy un programador de Perl. Perl no tiene protecciones formales, tal vez sea por eso que entiendo el problema muy bien :))

Privado

Como pensarías, solo el clase en el que se declara puede verlo.

Paquete privado

Solo puede ser visto y utilizado por el paquete en el que fue declarado. Este es el valor predeterminado en Java (que algunos ven como un error).

Protegido

El paquete privado + se puede ver por subclases o miembros del paquete.

Público

Todos pueden verlo.

Publicado

Visible fuera del código que controlo. (Si bien no es la sintaxis de Java, es importante para esta discusión).

C ++ define un nivel adicional llamado "amigo" y cuanto menos sepa acerca de eso, mejor.

¿Cuándo deberías usar qué? La idea general es encapsular para ocultar información. En la medida de lo posible, desea ocultar el detalle de cómo sus usuarios hacen algo. ¿Por qué? Porque entonces puedes cambiarlos más tarde y no romper el código de nadie. Esto le permite optimizar, refactorizar, rediseñar y corregir errores sin preocuparse de que alguien esté usando ese código que acaba de revisar.

Entonces, la regla de oro es hacer que las cosas sean tan visibles como deben ser. Comience con privado y solo agregue más visibilidad según sea necesario. Solo haga público lo que es absolutamente necesario que el usuario sepa, cada detalle que haga público obstaculiza su capacidad para rediseñar el sistema.

Si desea que los usuarios puedan personalizar los comportamientos, en lugar de hacer públicos los aspectos internos para que puedan anularlos, a menudo es una mejor idea meter esas agallas en un objeto y hacer que esa interfaz sea pública. De esa forma, simplemente pueden conectar un nuevo objeto. Por ejemplo, si estaba escribiendo un reproductor de CD y deseaba que el bit "ir a buscar información sobre este CD" se personalizara, en lugar de hacer públicos esos métodos, pondría toda esa funcionalidad en su propio objeto y haría que su objeto getter / setter public . De esta manera, ser tacaño al exponer tus entrañas alienta una buena composición y separación de preocupaciones

Personalmente, me quedo solo con "privado" y "público". Muchos lenguajes de OO simplemente tienen eso. "Protegido" puede ser útil, pero en realidad es una trampa. Una vez que una interfaz es más que privada, está fuera de su control y debe buscar el código de otras personas para encontrar usos.

Aquí es donde entra en juego la idea de "publicado". Para cambiar una interfaz (refactorizarla) es necesario que encuentre todo el código que la está usando y también la cambie. Si la interfaz es privada, no hay problema. Si está protegido, debes buscar todas tus subclases. Si es público, debes buscar el código que usa tu código. A veces esto es posible, por ejemplo, si está trabajando con un código corporativo que es para uso interno, no importa si la interfaz es pública. Puede tomar todo el código del repositorio corporativo. Pero si una interfaz está "publicada", si hay un código que la usa fuera de su control, entonces usted está contaminado. Debe admitir esa interfaz o arriesgarse a descifrar el código. Incluso las interfaces protegidas se pueden considerar publicadas (y es por eso que no me preocupo por las protegidas).

Muchos idiomas consideran que la naturaleza jerárquica de public / protected / private es demasiado limitada y no está en línea con la realidad. Para ese fin existe el concepto de una clase de rasgo, pero ese es otro espectáculo.


357
2017-10-18 21:17



Aquí hay una mejor versión de la tabla. (Prueba de futuro con una columna para módulos).

Java Access Modifiers

Explicaciones

  • UN privado miembro es solamente accesible dentro de la misma clase que se declara.

  • Un miembro con sin modificador de acceso solo es accesible dentro de las clases en el mismo paquete.

  • UN protegido miembro es accesible dentro de todas las clases en el mismo paquete y dentro de subclases en otros paquetes.

  • UN público miembro es accesible para todas las clases (a menos que resida en un módulo eso no exporta el paquete en el que está declarado).


¿Qué modificador elegir?

Los modificadores de acceso son una herramienta para ayudarlo a prevenir la ruptura accidental de la encapsulación(*). Pregúntese si tiene la intención de que el miembro sea algo interno a la clase, paquete, jerarquía de clases o no interna en absoluto, y elija el nivel de acceso correspondiente.

Ejemplos:

  • Un campo long internalCounter debería ser privado, ya que es mutable y un detalle de implementación.
  • Una clase que solo debería ser instanciada en una clase de fábrica (en el mismo paquete) debería tener un constructor de paquete restringido, ya que no debería ser posible llamarlo directamente desde fuera del paquete.
  • Un interno void beforeRender() El método llamado justo antes de la representación y utilizado como un gancho en las subclases debe estar protegido.
  • UN void saveGame(File dst) método que se llama desde el código GUI debe ser público.

(*) ¿Qué es la encapsulación exactamente?


243
2017-11-10 10:27



                | highest precedence <---------> lowest precedence
*———————————————+———————————————+———————————+———————————————+———————
 \ xCanBeSeenBy | this          | any class | this subclass | any
  \__________   | class         | in same   | in another    | class
             \  | nonsubbed     | package   | package       |    
Modifier of x \ |               |           |               |       
————————————————*———————————————+———————————+———————————————+———————
public          |              |          |              |      
————————————————+———————————————+———————————+———————————————+———————
protected       |              |          |              |   ✘   
————————————————+———————————————+———————————+———————————————+———————
package-private |               |           |               |
(no modifier)   |              |          |       ✘       |   ✘   
————————————————+———————————————+———————————+———————————————+———————
private         |              |     ✘     |       ✘       |   ✘    

165
2018-01-09 21:42



Regla fácil. Comience declarando todo privado. Y luego avanza hacia el público a medida que surgen las necesidades y el diseño lo garantiza.

Al exponer a los miembros, pregúntese si está exponiendo opciones de representación u opciones de abstracción. El primero es algo que desea evitar ya que introducirá demasiadas dependencias en la representación real en lugar de su comportamiento observable.

Como regla general trato de evitar la implementación de métodos por subclasificación; es muy fácil arruinar la lógica. Declare métodos abstractos protegidos si tiene la intención de que se anule.

Además, use la anotación @Override al anular para evitar que las cosas se rompan cuando refactorice.


130
2017-10-18 20:00



En realidad es un poco más complicado de lo que muestra una grilla simple. La grilla le dice si se permite un acceso, pero ¿qué constituye exactamente un acceso? Además, los niveles de acceso interactúan con las clases anidadas y la herencia de formas complejas.

El acceso "predeterminado" (especificado por la ausencia de una palabra clave) también se llama paquete-privado. Excepción: en una interfaz, ningún modificador significa acceso público; modificadores que no sean públicos están prohibidos. Las constantes de Enum son siempre públicas.

Resumen

¿Se permite el acceso a un miembro con este especificador de acceso?

  • Miembro es private: Solo si el miembro está definido dentro de la misma clase que el código de llamada.
  • El miembro es un paquete privado: solo si el código de llamada se encuentra dentro del paquete adjunto inmediato del miembro.
  • Miembro es protected: El mismo paquete, o si el miembro se define en una superclase de la clase que contiene el código de llamada.
  • Miembro es public: Sí.

Qué especificadores de acceso se aplican a

Las variables locales y los parámetros formales no pueden tomar especificadores de acceso. Como son intrínsecamente inaccesibles para el exterior según las reglas de alcance, son efectivamente privadas.

Para clases en el alcance superior, solo public y paquete privado están permitidos. Esta elección de diseño es presumiblemente porque protected y private sería redundante a nivel de paquete (no hay herencia de paquetes).

Todos los especificadores de acceso son posibles en los miembros de la clase (constructores, métodos y funciones miembro estáticas, clases anidadas).

Relacionado: Accesibilidad de clase de Java

Orden

Los especificadores de acceso pueden ordenarse estrictamente

público> protegido> paquete-privado> privado

significa que public proporciona el mayor acceso, private El menos. Cualquier referencia posible en un miembro privado también es válida para un miembro privado del paquete; cualquier referencia a un miembro privado del paquete es válida para un miembro protegido, y así sucesivamente. (Dar acceso a miembros protegidos a otras clases en el mismo paquete se consideró un error).

Notas

  • Los métodos de una clase son permitido acceder a miembros privados de otros objetos de la misma clase. Más precisamente, un método de clase C puede acceder a miembros privados de C en objetos de cualquier subclase de C. Java no admite restringir el acceso por instancia, solo por clase. (Compare con Scala, que sí lo admite utilizando private[this].)
  • Necesitas acceso a un constructor para construir un objeto. Por lo tanto, si todos los constructores son privados, la clase solo se puede construir mediante código que viva dentro de la clase (por lo general, métodos de fábrica estáticos o inicializadores de variables estáticas). Del mismo modo para constructores privados o protegidos por paquetes.
    • Solo tener constructores privados también significa que la clase no se puede subclasificar externamente, ya que Java requiere que los constructores de una subclase invoquen implícita o explícitamente un constructor de superclase. (Sin embargo, puede contener una clase anidada que lo subclasifica).

Clases internas

También debes considerar anidado ámbitos, como las clases internas. Un ejemplo de la complejidad es que las clases internas tienen miembros, que a su vez pueden tomar modificadores de acceso. Entonces puedes tener una clase privada interna con un miembro público; ¿se puede acceder al miembro? (Consulte a continuación.) La regla general es mirar el alcance y pensar recursivamente para ver si puede acceder a cada nivel.

Sin embargo, esto es bastante complicado, y para más detalles, consultar la Especificación de Lenguaje Java. (Sí, ha habido errores de compilación en el pasado).

Para conocer cómo interactúan, considere este ejemplo. Es posible "filtrar" clases internas privadas; esto usualmente es una advertencia:

class Test {
    public static void main(final String ... args) {
        System.out.println(Example.leakPrivateClass()); // OK
        Example.leakPrivateClass().secretMethod(); // error
    }
}

class Example {
    private static class NestedClass {
        public void secretMethod() {
            System.out.println("Hello");
        }
    }
    public static NestedClass leakPrivateClass() {
        return new NestedClass();
    }
}

Salida del compilador:

Test.java:4: secretMethod() in Example.NestedClass is defined in an inaccessible class or interface
        Example.leakPrivateClass().secretMethod(); // error
                                  ^
1 error

Algunas preguntas relacionadas:


94
2017-09-13 07:38



Como una regla de oro:

  • privado: alcance de clase
  • defecto (o paquete-privado): alcance del paquete.
  • protegido: alcance del paquete + niño (como el paquete, pero podemos subclasificarlo de diferentes paquetes). El modificador protegido siempre mantiene la relación "padre-hijo".
  • público: en todos lados.

Como resultado, si dividimos el derecho de acceso en tres derechos:

  • (Directo (invocar desde un método dentro de la misma clase).
  • (Referencia (invoque un método usando una referencia a la clase, o vía sintaxis "punto").
  • (Herencia (a través de subclases).

entonces tenemos esta simple tabla:

+—-———————————————+————————————+———————————+
|                 |    Same    | Different |
|                 |   Package  | Packages  |
+—————————————————+————————————+———————————+
| private         |   D        |           |
+—————————————————+————————————+———————————+
| package-private |            |           |
| (no modifier)   |   D R I    |           |
+—————————————————+————————————+———————————+
| protected       |   D R I    |       I   |
+—————————————————+————————————+———————————+
| public          |   D R I    |    R  I   |
+—————————————————+————————————+———————————+

63
2017-12-18 18:01



En muy corto

  • public: accesible desde cualquier lugar
  • protected: accesible por las clases del mismo paquete y las subclases que residen en cualquier paquete.
  • predeterminado (no se ha especificado ningún modificador): accesible por las clases del mismo paquete.
  • private: accesible solo dentro de la misma clase.

43
2017-10-27 17:49



El modificador de acceso más incomprendido en Java es protected. Sabemos que es similar al modificador predeterminado con una excepción en la que las subclases pueden verlo. ¿Pero cómo? Aquí hay un ejemplo que con suerte aclara la confusión:

  • Supongamos que tenemos 2 clases; Father y Son, cada uno en su propio paquete:

    package fatherpackage;
    
    public class Father
    {
    
    }
    
    -------------------------------------------
    
    package sonpackage;
    
    public class Son extends Father
    {
    
    }
    
  • Agreguemos un método protegido foo() a Father.

    package fatherpackage;
    
    public class Father
    {
        protected void foo(){}
    }
    
  • El método foo() puede ser llamado en 4 contextos:

    1. Dentro de una clase que se encuentra en el mismo paquete donde foo() se define (fatherpackage)

      package fatherpackage;
      
      public class SomeClass
      {
          public void someMethod(Father f, Son s)
          {
              f.foo();
              s.foo();
          }
      }
      
    2. Dentro de una subclase, en la instancia actual a través de this o super:

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod()
          {
              this.foo();
              super.foo();
          }
      }
      
    3. En una referencia cuyo tipo es la misma clase:

      package fatherpackage;
      
      public class Father
      {
          public void fatherMethod(Father f)
          {
              f.foo(); // valid even if foo() is private
          }
      }
      
      -------------------------------------------
      
      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Son s)
          {
              s.foo();
          }
      }
      
    4. En una referencia cuyo tipo es la clase principal y es dentro el paquete donde foo() se define (fatherpackage) [Esto puede incluirse dentro del contexto no. 1]:

      package fatherpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo();
          }
      }
      
  • Las siguientes situaciones no son válidas.

    1. En una referencia cuyo tipo es la clase principal y es fuera de el paquete donde foo() se define (fatherpackage)

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo(); // compilation error
          }
      }
      
    2. Una subclase no perteneciente a un paquete de una subclase (una subclase hereda los miembros protegidos de su principal y los hace privados para las no subclases):

      package sonpackage;
      
      public class SomeClass
      {
          public void someMethod(Son s) throws Exception
          {
              s.foo(); // compilation error
          }
      }
      

32
2017-11-15 20:06



Privado

  • Métodos, variables y constructores

Los métodos, las variables y los constructores que se declaran privados solo se pueden acceder dentro de la clase declarada.

  • Clase e interfaz

El modificador de acceso privado es el nivel de acceso más restrictivo. La clase y las interfaces no pueden ser privadas.

Nota

Se puede acceder a las variables que se declaran privadas fuera de la clase si hay métodos públicos getter en la clase. A las variables, métodos y constructores que están declarados protegidos en una superclase solo se puede acceder por las subclases en otro paquete o cualquier clase dentro del paquete de la clase de miembros protegidos.


Protegido

  • Clase e interfaz

El modificador de acceso protegido no se puede aplicar a la clase y las interfaces.

Los métodos, los campos pueden declararse protegidos, sin embargo, los métodos y campos en una interfaz no se pueden declarar protegidos.

Nota

El acceso protegido le da a la subclase la posibilidad de usar el método o la variable auxiliar, al tiempo que evita que una clase no relacionada intente usarlo.


Público

Una clase, método, constructor, interfaz, etc. declarados públicos se puede acceder desde cualquier otra clase. 

Por lo tanto, se puede acceder a los campos, métodos y bloques declarados dentro de una clase pública desde cualquier clase que pertenezca al Universo Java.

  • Diferentes paquetes

Sin embargo, si la clase pública a la que intentamos acceder se encuentra en un paquete diferente, entonces la clase pública aún debe importarse.

Debido a la herencia de clases, todos los métodos y variables públicos de una clase son heredados por sus subclases.


Predeterminado -No-palabra clave

Modificador de acceso predeterminado significa que no declaramos explícitamente un modificador de acceso para una clase, campo, método, etc.

  • Dentro de los mismos paquetes

Una variable o método declarado sin ningún modificador de control de acceso está disponible para cualquier otra clase en el mismo paquete. Los campos en una interfaz son implícitamente públicos estáticos finales y los métodos en una interfaz son por defecto públicos.

Nota

No podemos anular los campos estáticos. Si intenta anular, no muestra ningún error. pero no funciona lo que exceptuamos.

Respuestas relacionadas

Enlaces de referencias

http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html http://www.tutorialspoint.com/java/java_access_modifiers.htm 


24
2018-01-22 13:08