Vraag In Java, verschil tussen pakket privé, openbaar, beschermd en privé


Zijn er in Java duidelijke regels voor het gebruik van toegangsmodificatoren, namelijk de standaard (privépakket), public, protected en private, tijdens het maken class en interface en omgaan met erfenis?


2490
2017-10-18 19:53


oorsprong


antwoorden:


De officiële zelfstudie kan nuttig voor u zijn.

            │ Klasse │ Pakket │ Subklasse │ Subklasse │ Wereld
            │ │ │ (zelfde pkg) │ (verschil pkg) │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
openbaar │ + │ + │ + │ + │ +
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
beschermd │ + │ + │ + │ + │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
geen modificatie │ + │ + │ + │ │
────────────┼───────┼─────────┼──────────┼──────── ──┼────────
privé │ + │ │ │ │

+: toegankelijk
blanco: niet toegankelijk

4645
2017-10-18 19:57



(Waarschuwing: ik ben geen Java-programmeur, ik ben een Perl-programmeur, Perl heeft geen formele bescherming en daarom begrijp ik misschien het probleem zo goed :))

Privaat

Zoals je zou denken, alleen de klasse waarin het is verklaard kan het zien.

Pakket privé

Kan alleen worden gezien en gebruikt door de pakket waarin het werd verklaard. Dit is de standaard in Java (die sommigen als een fout zien).

beschermde

Pakket Privé + is te zien per subklasse of pakketlid.

Openbaar

Iedereen kan het zien.

Gepubliceerd

Zichtbaar buiten de code die ik bestuur. (Hoewel dit geen Java-syntaxis is, is het belangrijk voor deze discussie).

C ++ definieert een extra niveau genaamd "vriend" en hoe minder je daarover weet, hoe beter.

Wanneer moet je wat gebruiken? Het hele idee is inkapseling om informatie te verbergen. U wilt zo veel mogelijk het detail verbergen van hoe iets wordt gedaan door uw gebruikers. Waarom? Omdat je ze later kunt wijzigen en niemand de code kunt overtreden. Hiermee kunt u bugs optimaliseren, opnieuw aanpassen, opnieuw ontwerpen en repareren zonder dat u zich zorgen hoeft te maken dat iemand die code gebruikte die u zojuist hebt gereviseerd.

Dus, vuistregel is om dingen alleen zo zichtbaar te maken als ze moeten zijn. Begin met privé en voeg alleen meer zichtbaarheid toe als dat nodig is. Maak alleen dat openbaar wat absoluut noodzakelijk is voor de gebruiker om te weten, elk detail dat u openbaar maakt, bemoeilijkt uw vermogen om het systeem opnieuw te ontwerpen.

Als u wilt dat gebruikers gedrag kunnen aanpassen, in plaats van internals openbaar te maken zodat ze deze kunnen overschrijven, is het vaak een beter idee om die ingewanden in een object te duwen en die interface openbaar te maken. Op die manier kunnen ze eenvoudig een nieuw object aansluiten. Als u bijvoorbeeld een cd-speler schrijft en wilt dat de "go find-info over deze cd" bit aanpasbaar is, in plaats van die methoden openbaar te maken, zou u al die functionaliteit in een eigen object plaatsen en alleen uw object-getter / setter openbaar maken . Op deze manier stimuleert gierig over het blootstellen van uw lef een goede samenstelling en scheiding van zorgen

Persoonlijk blijf ik gewoon "privé" en "publiek". Veel OO-talen hebben dat gewoon. "Beschermd" kan handig zijn, maar het is echt een cheat. Als een interface eenmaal meer dan privé is, bevindt deze zich buiten jouw controle en moet je in de code van anderen zoeken om toepassingen te vinden.

Dit is waar het idee van "gepubliceerd" om de hoek komt kijken. Een interface veranderen (opnieuw maken) vereist dat je alle code vindt die het gebruikt en dat ook verandert. Als de interface privé is, is dat geen probleem. Als het beveiligd is, moet je al je subklassen zoeken. Als het openbaar is, moet je alle code vinden die je code gebruikt. Soms is dit mogelijk, bijvoorbeeld als u werkt aan bedrijfscodes die alleen voor intern gebruik zijn, maakt het niet uit of een interface openbaar is. Je kunt alle code uit de bedrijfsrepository halen. Maar als een interface wordt "gepubliceerd", als er code is die deze buiten je controle gebruikt, dan wordt je afgespannen. U moet die interface of risico-brekende code ondersteunen. Zelfs beschermde interfaces kunnen als gepubliceerd worden beschouwd (vandaar dat ik me niet druk maak over beschermd).

Veel talen vinden de hiërarchische aard van openbaar / beschermd / privé te beperkend en niet in overeenstemming met de werkelijkheid. Daartoe is er het concept van a eigenschap klasse, maar dat is weer een show.


357
2017-10-18 21:17



Hier is een betere versie van de tabel. (Toekomstbestendig met een kolom voor modules.)

Java Access Modifiers

verklaringen

  • EEN privaat lid is enkel en alleen toegankelijk binnen dezelfde klasse als het is gedeclareerd.

  • Een lid met geen toegangsmodificator is alleen toegankelijk binnen klassen in hetzelfde pakket.

  • EEN beschermde lid is toegankelijk binnen alle klassen in hetzelfde pakket en binnen subklassen in andere pakketten.

  • EEN openbaar lid is toegankelijk voor alle klassen (tenzij het woont in een module die het pakket waarin het is gedeclareerd niet exporteert).


Welke modifier om te kiezen?

Access modifiers is een hulpmiddel om te voorkomen dat per ongeluk inkapseling wordt verbroken(*). Stel jezelf de vraag of je van plan bent dat het lid iets is dat intern is in de klasse, het pakket, de klassenhiërarchie of helemaal niet, en kies dienovereenkomstig een toegangsniveau.

Voorbeelden:

  • Een veld long internalCounter zou waarschijnlijk privé moeten zijn, omdat het veranderbaar is en een detail van de implementatie.
  • Een klasse die alleen moet worden geïnstantieerd in een fabrieksklasse (in hetzelfde pakket) moet een constructor hebben die is beperkt tot het pakket, omdat het niet mogelijk zou moeten zijn om hem rechtstreeks van buiten het pakket te bellen.
  • Een intern void beforeRender() methode die vlak voor weergave wordt aangeroepen en die wordt gebruikt als haak in subklassen, moet worden beschermd.
  • EEN void saveGame(File dst) methode die wordt aangeroepen vanuit de GUI-code moet openbaar zijn.

(*) Wat is inkapseling precies?


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



Makkelijke regel. Begin met alles privé te verklaren. En ga dan verder naar het publiek als de behoeften zich voordoen en ontwerp dit rechtvaardigt.

Wanneer blootgestelde leden zich afvragen of je representatie-keuzes of abstractie-keuzes blootlegt. De eerste is iets dat je wilt vermijden omdat het te veel afhankelijkheden van de werkelijke weergave introduceert in plaats van het waarneembare gedrag.

Als algemene regel probeer ik te voorkomen dat implementaties van methoden worden overschreven door subclassering; het is te gemakkelijk om de logica te verpesten. Verklaar abstracte beschermde methoden als u van plan bent deze te overschrijven.

Gebruik ook de annotatie @Override om te voorkomen dat dingen breken wanneer u refactor.


130
2017-10-18 20:00



Het is eigenlijk een beetje ingewikkelder dan een eenvoudig raster. Het raster geeft aan of een toegang is toegestaan, maar wat is precies een toegang? Toegangsniveaus werken ook op complexe manieren samen met geneste klassen en overerving.

De "standaard" toegang (gespecificeerd door de afwezigheid van een sleutelwoord) wordt ook wel genoemd package-private. Uitzondering: in een interface betekent geen enkele wijziging openbare toegang; andere modifiers dan publiek zijn verboden. Enum-constanten zijn altijd openbaar.

Overzicht

Is toegang tot een lid met deze toegangsspecificatie toegestaan?

  • Lid is private: Alleen als lid is gedefinieerd in dezelfde klasse als de oproepcode.
  • Lid is privépakket: alleen als de aanroepcode zich binnen het direct omsluitende pakket van het lid bevindt.
  • Lid is protected: Hetzelfde pakket, of als het lid is gedefinieerd in een superklasse van de klasse die de aanroepcode bevat.
  • Lid is public: Ja.

Welke toegangsspecificaties zijn van toepassing op

Lokale variabelen en formele parameters kunnen geen toegangsspecificaties gebruiken. Omdat ze inherent ontoegankelijk zijn voor de buitenwereld volgens de regels van scoping, zijn ze effectief privé.

Alleen voor klassen in de topscope public en package-private zijn toegestaan. Deze ontwerpkeuze is vermoedelijk omdat protected en private zou op pakketniveau overbodig zijn (er is geen erfenis van pakketten).

Alle toegangsspecificaties zijn mogelijk op klassenleden (constructors, methoden en statische lidfuncties, geneste klassen).

Verwant: Java Class Accessibility

Bestellen

De toegangsspecificaties kunnen strikt worden besteld

openbaar> beveiligd> privépakket> privé

inhoudende dat public biedt de meeste toegang, private het minste. Elke verwijzing die mogelijk is op een privé-lid is ook geldig voor een pakket-privélid; elke verwijzing naar een pakket-privé-lid is geldig op een beschermd lid, enzovoort. (Het geven van toegang tot beschermde leden aan andere klassen in hetzelfde pakket werd als een vergissing beschouwd.)

Notes

  • De methoden van een klasse zijn toegang krijgen tot privé-leden van andere objecten van dezelfde klasse. Nauwkeuriger gezegd, een methode van klasse C heeft toegang tot privéleden van C op objecten van een subklasse van C. Java ondersteunt geen beperking van toegang door instantie, alleen per klasse. (Vergelijk met Scala, die het wel ondersteunt private[this].)
  • U hebt toegang nodig tot een constructor om een ​​object te construeren. Dus als alle constructors privé zijn, kan de klasse alleen worden geconstrueerd door code die in de klasse leeft (meestal statische fabrieksmethoden of statische variabele initializers). Evenzo voor pakket-private of beschermde constructeurs.
    • Alleen het hebben van private constructors betekent ook dat de klasse niet extern kan worden gecategoriseerd, omdat Java een constructor van een subklasse vereist om impliciet of expliciet een superklasse-constructor te callen. (Het kan echter een geneste klasse bevatten die deze subklassen.)

Innerlijke klassen

Je moet ook overwegen genesteld scopes, zoals innerlijke klassen. Een voorbeeld van de complexiteit is dat innerlijke klassen leden hebben die zelf toegang kunnen krijgen tot modifiers. U kunt dus een privé-klas hebben met een openbaar lid; kan het lid worden benaderd? (Zie hieronder.) De algemene regel is om te kijken naar het bereik en recursief te denken om te zien of je toegang hebt tot elk niveau.

Dit is echter vrij ingewikkeld en voor alle details, raadpleeg de Java-taalspecificatie. (Ja, er zijn in het verleden compilerfouten geweest.)

Bekijk dit voorbeeld om te weten hoe deze op elkaar inwerken. Het is mogelijk om private inner classes te "lekken"; dit is meestal een waarschuwing:

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

Compileroutput:

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

Enkele gerelateerde vragen:


94
2017-09-13 07:38



Als vuistregel:

  • privaat: klassenbereik.
  • standaard (of package-private): pakketomvang.
  • beschermde: pakketomvang + kind (zoals pakket, maar we kunnen het van verschillende pakketten subklassen). De beveiligde modifier behoudt altijd de relatie "ouder-kind".
  • openbaar: overal.

Dientengevolge, als we toegangsrecht verdelen in drie rechten:

  • (D) irect (Roep op vanuit een methode binnen dezelfde klasse).
  • (Referentie (Roep een methode aan met behulp van een verwijzing naar de klasse, of via de syntaxis van "punt").
  • (Erfenis (via subclassing).

dan hebben we deze eenvoudige tabel:

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

  • public: overal toegankelijk.
  • protected: toegankelijk voor de klassen van hetzelfde pakket en de subklassen die zich in een pakket bevinden.
  • standaard (geen modifier opgegeven): toegankelijk voor de klassen van hetzelfde pakket.
  • private: alleen toegankelijk binnen dezelfde klasse.

43
2017-10-27 17:49



De meest onbegrepen toegangsmodificator in Java is protected. We weten dat het vergelijkbaar is met de standaardmodifier met één uitzondering, waarin subklassen het kunnen zien. Maar hoe? Hier is een voorbeeld dat hopelijk de verwarring verheldert:

  • Stel dat we 2 klassen hebben; Father en Son, elk in zijn eigen pakket:

    package fatherpackage;
    
    public class Father
    {
    
    }
    
    -------------------------------------------
    
    package sonpackage;
    
    public class Son extends Father
    {
    
    }
    
  • Laten we een beschermde methode toevoegen foo() naar Father.

    package fatherpackage;
    
    public class Father
    {
        protected void foo(){}
    }
    
  • De methode foo() kan in 4 contexten worden aangeroepen:

    1. Binnen een klasse die zich in hetzelfde pakket bevindt waar foo() is gedefinieerd (fatherpackage):

      package fatherpackage;
      
      public class SomeClass
      {
          public void someMethod(Father f, Son s)
          {
              f.foo();
              s.foo();
          }
      }
      
    2. In een subklasse, op de huidige instantie via this of super:

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod()
          {
              this.foo();
              super.foo();
          }
      }
      
    3. Op een referentie waarvan het type dezelfde klasse is:

      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. Op een verwijzing waarvan het type de bovenliggende klasse is en dat is het binnen het pakket waar foo() is gedefinieerd (fatherpackage) [Dit kan worden opgenomen in contextnr. 1]:

      package fatherpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo();
          }
      }
      
  • De volgende situaties zijn niet geldig.

    1. Op een verwijzing waarvan het type de bovenliggende klasse is en dat is het buiten het pakket waar foo() is gedefinieerd (fatherpackage):

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo(); // compilation error
          }
      }
      
    2. Een niet-subklasse binnen een pakket van een subklasse (een subklasse erft de beschermde leden van het bovenliggende element en maakt ze privé voor niet-subklassen):

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

32
2017-11-15 20:06



Privaat

  • Methoden, variabelen en constructors

Methoden, variabelen en constructors die privé zijn verklaard, zijn alleen toegankelijk binnen de aangegeven klasse zelf.

  • Klasse en interface

Modificatie voor privétoegang is het meest beperkende toegangsniveau. Klasse en interfaces kunnen niet privé zijn.

Notitie

Variabelen die privé zijn verklaard, kunnen buiten de klas worden geopend als openbare gettermethoden in de klasse aanwezig zijn. Variabelen, methoden en constructors die als beschermd worden verklaard in een superklasse, kunnen alleen worden geopend door de subklassen in een ander pakket of in een andere klasse binnen het pakket van de klasse beschermde leden.


beschermde

  • Klasse en interface

De beveiligde toegangsmodificator kan niet worden toegepast op klasse en interfaces.

Methoden, velden kunnen als beveiligd worden verklaard, methoden en velden in een interface kunnen echter niet als beveiligd worden verklaard.

Notitie

Beveiligde toegang geeft de subklasse een kans om de helpermethode of variabele te gebruiken, terwijl wordt voorkomen dat een niet-verwante klasse deze probeert te gebruiken.


Openbaar

Een klasse, methode, constructor, interface, enz. Die openbaar is verklaard, is toegankelijk vanuit elke andere klasse. 

Daarom kunnen velden, methoden, blokken die in een openbare klasse zijn gedeclareerd, worden geopend vanuit elke klasse die bij de Java Universe hoort.

  • Verschillende pakketten

Als de openbare klas waartoe we toegang proberen te krijgen zich echter in een ander pakket bevindt, moet de openbare klas nog worden geïmporteerd.

Vanwege class inheritance worden alle openbare methoden en variabelen van een klasse overgenomen door de subklassen.


Standaard - Geen sleutelwoord:

Standaard toegangsmodificator betekent dat we niet expliciet een toegangsmodificator voor een klasse, veld, methode, etc. verklaren.

  • Binnen dezelfde pakketten

Een variabele of methode die is gedeclareerd zonder enige toegangscontrolemodificator is beschikbaar voor elke andere klasse in hetzelfde pakket. De velden in een interface zijn impliciet publieke statische finale en de methoden in een interface zijn standaard openbaar.

Notitie

We kunnen de statische velden niet overschrijven. Als u probeert deze te overschrijven, wordt er geen fout weergegeven maar het werkt niet wat we behalve.

Gerelateerde antwoorden

Verwijzingen links

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



Het verschil is te vinden in de links die al zijn verstrekt, maar die je meestal moet gebruiken komt neer op het 'Principe van de minste kennis'. Laat alleen de minste zichtbaarheid toe die nodig is.


15
2017-10-18 20:00