Domanda In Java, differenza tra pacchetto privato, pubblico, protetto e privato


In Java, ci sono regole chiare su quando utilizzare ciascuno dei modificatori di accesso, vale a dire l'impostazione predefinita (pacchetto privato), public, protected e private, mentre si fa class e interface e si occupano di ereditarietà?


2488
2017-10-18 19:53


origine


risposte:


Il tutorial ufficiale potrebbe essere di qualche utilità per voi.

            │ Classe │ Pacchetto │ Sottoclasse │ Sottoclasse │ Mondo
            │ │ │ (stesso pkg) │ (diff pkg) │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
public │ + │ + │ + │ + │ +
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
protetto │ + │ + │ + │ + │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
nessun modificatore │ + │ + │ + │ │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
privato │ + │ │ │ │

+: accessibile
vuoto: non accessibile

4642
2017-10-18 19:57



(Caveat: Io non sono un programmatore Java, sono un programmatore Perl. Perl non ha protezioni formali che è forse il motivo per cui capisco il problema così bene :))

Privato

Come penseresti, solo il classe in cui è dichiarato può vederlo.

Pacchetto privato

Può essere visto e usato solo da pacchetto in cui è stato dichiarato. Questo è il default in Java (che alcuni vedono come un errore).

protetta

Il pacchetto Private + può essere visto da sottoclassi o membri del pacchetto.

Pubblico

Tutti possono vederlo.

Pubblicato

Visibile al di fuori del codice che controllo. (Anche se non è la sintassi Java, è importante per questa discussione).

Il C ++ definisce un livello aggiuntivo chiamato "amico" e meno ne sai e meglio è.

Quando dovresti usare cosa? L'intera idea è l'incapsulamento per nascondere le informazioni. Per quanto possibile, si desidera nascondere i dettagli di come viene fatto qualcosa dai propri utenti. Perché? Perché allora puoi cambiarli più tardi e non infrangere il codice di nessuno. Questo ti consente di ottimizzare, refactoring, riprogettare e correggere bug senza preoccuparti che qualcuno stia usando quel codice che hai appena revisionato.

Quindi, la regola generale è di rendere le cose solo visibili come devono essere. Inizia con privato e aggiungi solo più visibilità se necessario. Rendi pubblico solo ciò che è assolutamente necessario che l'utente sappia, ogni dettaglio che rendi crampi pubblici la tua capacità di ridisegnare il sistema.

Se si desidera che gli utenti siano in grado di personalizzare i comportamenti, piuttosto che rendere pubblici gli interni in modo che possano sovrascriverli, è spesso un'idea migliore spingere quegli intestini in un oggetto e rendere pubblica tale interfaccia. In questo modo possono semplicemente inserire un nuovo oggetto. Ad esempio, se stavi scrivendo un lettore CD e volessi il bit "vai a trovare informazioni su questo CD" personalizzabile, piuttosto che rendere pubblici quei metodi, inseriresti tutte queste funzionalità nel proprio oggetto e renderebbe pubblico solo il tuo oggetto getter / setter . In questo modo essere avidi nell'esporre le tue viscere incoraggia una buona composizione e separazione delle preoccupazioni

Personalmente, rimango solo con "privato" e "pubblico". Molte lingue OO hanno questo. "Protetto" può essere utile, ma è davvero un trucco. Una volta che un'interfaccia è più che privata, è fuori dal tuo controllo e devi cercare nel codice di altre persone per trovare gli usi.

È qui che entra in gioco l'idea di "pubblicato". Cambiare un'interfaccia (refactoring) richiede che tu trovi tutto il codice che lo sta usando e lo cambi anche. Se l'interfaccia è privata, nessun problema. Se è protetto devi trovare tutte le sottoclassi. Se è pubblico devi trovare tutto il codice che usa il tuo codice. A volte questo è possibile, ad esempio se stai lavorando su un codice aziendale che è solo per uso interno, non importa se un'interfaccia è pubblica. Puoi estrarre tutto il codice dal repository aziendale. Ma se un'interfaccia è "pubblicata", se c'è del codice che la utilizza al di fuori del tuo controllo, allora tu verrai disinformato. È necessario supportare tale interfaccia o rischiare di violare il codice. Anche le interfacce protette possono essere considerate pubblicate (motivo per cui non mi preoccupo di proteggere).

Molte lingue trovano la natura gerarchica di pubblico / protetto / privato troppo limitante e non in linea con la realtà. A tal fine c'è il concetto di a classe dei tratti, ma questo è un altro spettacolo.


357
2017-10-18 21:17



Ecco una versione migliore del tavolo. (Prova futura con una colonna per i moduli.)

Java Access Modifiers

spiegazioni

  • UN privato membro è solo accessibile all'interno della stessa classe dichiarata.

  • Un membro con nessun modificatore di accesso è accessibile solo all'interno delle classi nello stesso pacchetto.

  • UN protetta membro è accessibile all'interno di tutte le classi nello stesso pacchetto e all'interno di sottoclassi in altri pacchetti.

  • UN pubblico membro è accessibile a tutte le classi (a meno che non risieda in a modulo che non esporta il pacchetto in cui è dichiarato).


Quale modificatore scegliere?

I modificatori di accesso sono uno strumento che ti aiuta a prevenire l'incapsulamento accidentale(*). Chiediti se intendi che il membro sia qualcosa che è interno alla classe, al pacchetto, alla gerarchia di classi o non sia interno e scegli il livello di accesso di conseguenza.

Esempi:

  • Un campo long internalCounter dovrebbe probabilmente essere privato poiché è mutabile e un dettaglio di implementazione.
  • Una classe che dovrebbe essere istanziata solo in una classe factory (nello stesso pacchetto) dovrebbe avere un costruttore a pacchetto limitato, dal momento che non dovrebbe essere possibile chiamarlo direttamente dall'esterno del pacchetto.
  • Un interno void beforeRender() il metodo chiamato prima del rendering e usato come un hook in sottoclassi dovrebbe essere protetto.
  • UN void saveGame(File dst) il metodo che viene chiamato dal codice della GUI dovrebbe essere pubblico.

(*) Cos'è esattamente l'incapsulamento?


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



Regola facile Inizia con dichiarare tutto privato. E poi progredire verso il pubblico man mano che sorgono i bisogni e il design lo garantisce.

Quando esponi i membri chiedi a te stesso se stai esponendo le scelte di rappresentazione o le scelte di astrazione. Il primo è qualcosa che si vuole evitare in quanto introdurrà troppe dipendenze dalla rappresentazione reale piuttosto che dal suo comportamento osservabile.

Come regola generale, cerco di evitare di sovrascrivere le implementazioni del metodo tramite la sottoclasse; è troppo facile rovinare la logica. Dichiarare metodi protetti astratti se si intende farlo sovrascrivere.

Inoltre, utilizzare l'annotazione @ Override quando si esegue l'override per evitare che le cose si rompano quando si effettua il refactoring.


130
2017-10-18 20:00



In realtà è un po 'più complicato di una semplice griglia. La griglia ti dice se è permesso un accesso, ma cosa costituisce esattamente un accesso? Inoltre, i livelli di accesso interagiscono con le classi e l'ereditarietà nidificate in modi complessi.

Viene anche chiamato l'accesso "predefinito" (specificato dall'assenza di una parola chiave) Pacchetto-privato. Eccezione: in un'interfaccia, nessun modificatore significa accesso pubblico; i modificatori diversi dal pubblico sono vietati. Le costanti Enum sono sempre pubbliche.

Sommario

È consentito l'accesso a un membro con questo identificatore di accesso?

  • Membro è private: Solo se il membro è definito all'interno della stessa classe del codice di chiamata.
  • Il membro è privato del pacchetto: solo se il codice chiamante si trova nel pacchetto che include immediatamente il membro.
  • Membro è protected: Lo stesso pacchetto, o se il membro è definito in una superclasse della classe che contiene il codice chiamante.
  • Membro è public: Sì.

A chi si applicano gli specificatori di accesso

Le variabili locali e i parametri formali non possono prendere gli identificatori di accesso. Dal momento che sono intrinsecamente inaccessibili all'esterno secondo le regole dell'ambito, sono effettivamente privati.

Solo per le classi nell'ambito top public e il pacchetto-privato è permesso. Questa scelta di design è presumibilmente perché protected e private sarebbe ridondante a livello di pacchetto (non esiste l'ereditarietà dei pacchetti).

Tutti gli specificatori di accesso sono possibili sui membri della classe (costruttori, metodi e funzioni dei membri statici, classi nidificate).

Relazionato: Accessibilità della classe Java

Ordine

Gli specificatori di accesso possono essere ordinati rigorosamente

pubblico> protetto> pacchetto-privato> privato

intendendo che public fornisce il massimo accesso, private il minimo. Qualsiasi riferimento possibile su un membro privato è valido anche per un membro privato del pacchetto; qualsiasi riferimento a un membro privato del pacchetto è valido su un membro protetto e così via. (Dare l'accesso ai membri protetti ad altre classi nello stesso pacchetto è stato considerato un errore).

Gli appunti

  • I metodi di una classe siamo permesso di accedere a membri privati ​​di altri oggetti della stessa classe. Più precisamente, un metodo di classe C può accedere a membri privati ​​di C su oggetti di qualsiasi sottoclasse di C. Java non supporta la limitazione dell'accesso per istanza, solo per classe. (Confrontati con Scala, che supporta il suo utilizzo private[this].)
  • È necessario accedere a un costruttore per costruire un oggetto. Pertanto, se tutti i costruttori sono privati, la classe può essere costruita solo dal codice che vive all'interno della classe (in genere metodi di factory statici o inizializzatori di variabili statiche). Allo stesso modo per i costruttori di pacchetti privati ​​o protetti.
    • Solo avere costruttori privati ​​significa anche che la classe non può essere sottoclassata esternamente, dal momento che Java richiede ai costruttori di una sottoclasse di chiamare implicitamente o esplicitamente un costruttore di superclasse. (Può tuttavia contenere una classe nidificata che la sottoclasse).

Classi interne

Devi anche prendere in considerazione nidificato ambiti, come le classi interne. Un esempio della complessità è che le classi interne hanno membri, che a loro volta possono prendere modificatori di accesso. Quindi puoi avere una classe privata interna con un membro pubblico; si può accedere al membro? (Vedi sotto). La regola generale è guardare lo scope e pensare in modo ricorsivo per vedere se è possibile accedere ad ogni livello.

Tuttavia, questo è abbastanza complicato e per tutti i dettagli, consultare la specifica della lingua Java. (Sì, ci sono stati errori nel compilatore in passato.)

Per un assaggio di come questi interagiscono, considera questo esempio. È possibile "perdere" classi interne private; questo di solito è un avvertimento:

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();
    }
}

Uscita del compilatore:

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

Alcune domande correlate:


94
2017-09-13 07:38



Come regola generale:

  • privato: ambito di classe.
  • predefinito (o Pacchetto-privato): ambito del pacchetto.
  • protetta: ambito del pacchetto + bambino (come pacchetto, ma possiamo creare una sottoclasse da pacchetti diversi). Il modificatore protetto mantiene sempre la relazione "genitore-figlio".
  • pubblico: ovunque.

Di conseguenza, se dividiamo il diritto di accesso in tre diritti:

  • (Diretto (invoca da un metodo all'interno della stessa classe).
  • (Riferimento (invoca un metodo usando un riferimento alla classe, o tramite la sintassi "punto").
  • (Eredità (tramite sottoclasse).

allora abbiamo questa semplice tabella:

+—-———————————————+————————————+———————————+
|                 |    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



In brevissimo

  • public: accessibile da ogni dove.
  • protected: accessibile dalle classi dello stesso pacchetto e delle sottoclassi che risiedono in qualsiasi pacchetto.
  • default (nessun modificatore specificato): accessibile dalle classi dello stesso pacchetto.
  • private: accessibile solo nella stessa classe.

43
2017-10-27 17:49



Il modificatore di accesso più incompreso in Java è protected. Sappiamo che è simile al modificatore predefinito con un'eccezione in cui le sottoclassi possono vederlo. Ma come? Ecco un esempio che si spera chiarisca la confusione:

  • Supponiamo di avere 2 classi; Father e Son, ciascuno nel proprio pacchetto:

    package fatherpackage;
    
    public class Father
    {
    
    }
    
    -------------------------------------------
    
    package sonpackage;
    
    public class Son extends Father
    {
    
    }
    
  • Aggiungiamo un metodo protetto foo() a Father.

    package fatherpackage;
    
    public class Father
    {
        protected void foo(){}
    }
    
  • Il metodo foo() può essere chiamato in 4 contesti:

    1. All'interno di una classe che si trova nello stesso pacchetto dove foo() è definito (fatherpackage):

      package fatherpackage;
      
      public class SomeClass
      {
          public void someMethod(Father f, Son s)
          {
              f.foo();
              s.foo();
          }
      }
      
    2. All'interno di una sottoclasse, nell'istanza corrente tramite this o super:

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod()
          {
              this.foo();
              super.foo();
          }
      }
      
    3. Su un riferimento il cui tipo è della stessa classe:

      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. Su un riferimento il cui tipo è la classe genitore ed è dentro il pacchetto dove foo() è definito (fatherpackage) [Questo può essere incluso all'interno del contesto n. 1]:

      package fatherpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo();
          }
      }
      
  • Le seguenti situazioni non sono valide.

    1. Su un riferimento il cui tipo è la classe genitore ed è al di fuori il pacchetto dove foo() è definito (fatherpackage):

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo(); // compilation error
          }
      }
      
    2. Una non sottoclasse all'interno di un pacchetto di una sottoclasse (una sottoclasse eredita i membri protetti dal suo genitore e li rende privati ​​di non sottoclassi):

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

32
2017-11-15 20:06



Privato

  • Metodi, Variabili e Costruttori

Metodi, variabili e costruttori dichiarati privati ​​sono accessibili solo all'interno della classe dichiarata.

  • Classe e interfaccia

Il modificatore di accesso privato è il livello di accesso più restrittivo. La classe e le interfacce non possono essere private.

Nota

Le variabili dichiarate private sono accessibili al di fuori della classe se nella classe sono presenti metodi getter pubblici. Variabili, metodi e costruttori che sono dichiarati protetti in una superclasse sono accessibili solo dalle sottoclassi di un altro pacchetto o di qualsiasi classe all'interno del pacchetto della classe dei membri protetti.


protetta

  • Classe e interfaccia

Il modificatore di accesso protetto non può essere applicato alla classe e alle interfacce.

Metodi, i campi possono essere dichiarati protetti, tuttavia i metodi e i campi in un'interfaccia non possono essere dichiarati protetti.

Nota

L'accesso protetto consente alla sottoclasse di utilizzare il metodo o la variabile helper, impedendo al contempo a una classe non correlata di tentare di utilizzarla.


Pubblico

Una classe, un metodo, un costruttore, un'interfaccia, ecc., Dichiarato pubblico, è accessibile da qualsiasi altra classe. 

Pertanto è possibile accedere a campi, metodi, blocchi dichiarati all'interno di una classe pubblica da qualsiasi classe appartenente all'universo Java.

  • Pacchetti diversi

Tuttavia, se la classe pubblica a cui stiamo tentando di accedere si trova in un pacchetto diverso, la classe pubblica deve ancora essere importata.

A causa dell'ereditarietà delle classi, tutti i metodi pubblici e le variabili di una classe sono ereditati dalle sue sottoclassi.


Predefinito -Nessuna parola chiave:

Il modificatore di accesso predefinito significa che non dichiariamo esplicitamente un modificatore di accesso per una classe, un campo, un metodo, ecc.

  • All'interno degli stessi pacchetti

Una variabile o un metodo dichiarato senza alcun modificatore del controllo di accesso è disponibile per qualsiasi altra classe nello stesso pacchetto. I campi di un'interfaccia sono implicitamente statici finali pubblici e i metodi in un'interfaccia sono di pubblico dominio.

Nota

Non possiamo sovrascrivere i campi Statici. Se provi a ignorarlo, non viene visualizzato alcun errore ma non funziona quello che noi eccetto.

Risposte correlate

Link di riferimenti

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



La differenza può essere trovata nei collegamenti già forniti, ma quale da usare di solito si riferisce al "Principio di minima conoscenza". Consenti solo la minima visibilità necessaria.


15
2017-10-18 20:00