Modificatori Java. Academia de Programare Modernă

Aici vom încerca să luăm în considerare aproape toate cazurile de utilizare a modificatorilor de acces. Singura excepție este utilizarea lor pentru imbricat ( cuibărit) și intern ( interior), precum și pentru interfețe, deoarece încă nu am luat în considerare aceste subiecte.

Clasele și pachetele utilizate împreună cu modificatorii de acces servesc ca mijloace de încapsulare, adică mijloace de ascundere a detaliilor de implementare în spatele interfață simplă.

Modificatorii de acces pot fi aplicați atât claselor, cât și membrilor acestora - câmpuri și metode. Există în total patru modificatori de acces și aici vom oferi o scurtă descriere a acestora, apoi îi vom analiza în detaliu pe fiecare.

  • public– orice componentă declarată ca public, accesibil din orice cod
  • protejat– permite accesul la componenta din pachet și la clasele sale descendente
  • privat– permite accesul la componentele din cadrul clasei
  • Mod implicit(fără cuvânt cheie) – permite accesul la componentele dintr-un pachet

Clasele moștenitoare sunt clase moștenite dintr-o clasă. Încă nu am studiat moștenirea..

Acces la cursuri

În mod implicit, clasele de nivel superior sunt disponibile în pachetul în care sunt definite. Cu toate acestea, dacă clasa de nivel superior este declarată ca public, atunci este disponibil peste tot (sau oriunde este disponibil pachetul în sine). Am limitat această declarație la clasele de nivel superior, deoarece clasele pot fi declarate ca membri ai altor clase. Deoarece aceste clase interioare sunt membri ai clasei, ele sunt supuse regulilor de control al accesului la membrii clasei.

Accesarea membrilor clasei

Membrii clasei sunt întotdeauna accesibili în cadrul corpului clasei. Mod implicit membrii unei clase sunt de asemenea disponibili în pachetul în care este definită clasa.

modificator public

Pentru o clasă neimbricată, poate fi specificată doar una din două niveluri posibile acces: specificat Mod implicitȘi public . Când o clasă este declarată ca public, el trebuie să fie singurul public o clasă declarată într-un fișier, iar numele fișierului trebuie să se potrivească cu numele clasei.

Cum public pot fi declarate clase, câmpuri, metode și constructori.

Modificator protejat

Vom analiza acest modificator în detaliu în subiectul moștenirii clasei. Dacă moștenirea nu este utilizată, atunci acest modificator funcționează la fel ca modificatorul implicit.

Singurul lucru care poate fi spus pe scurt acum este că componentele declarate ca protejat, va avea acces orice clasa de copii din orice pachet sau orice clasă din același pachet.

Cum protejat pot fi declarate câmpuri, metode, constructori, clase imbricate și interfețe imbricate.

protejat .

Modificator privat

Acesta este cel mai sever modificator în ceea ce privește restricțiile de acces. Elemente declarate ca privat accesibil numai în cadrul aceleiași clase și nu oricui din afara clasei.

Cum privat pot fi declarate câmpuri, metode, constructori, clase imbricate și interfețe imbricate.

Clasele și interfețele de nivel superior nu pot fi declarate ca privat .

În esență, modificatorii de acces sunt temă simplă, dar vom reveni la el mai târziu. Deocamdată era doar o cunoştinţă. Și acum puțină practică...

Am creat clasele Mod02.java, DefMod.java, ProMod.java și PrvMod.java care aparțin pachetului pro.java.pkg002, precum și clasa PubMod.java, care aparține pachetului pro.java.pkg003. Mai jos sunt doar capturi de ecran ale acestor clase și rezultatul programului:

Modificatori de acces public, private, protected

După cum sa discutat mai devreme, prezența unui modificator public înaintea unei metode sau a unui câmp înseamnă că poate fi folosit oriunde, iar un modificator privat înseamnă că poate fi folosit numai în interior din această clasă. De exemplu:

Clasa A ( private int Valoarea mea1; public int Valoarea mea2; ... void f() ( ... Valoarea mea1 = 1; // în interiorul clasei puteți utiliza oricare dintre câmpurile sale Valoarea mea2 = 2; ... A a; a. myValue1 / / acest lucru este posibil... ) ) ... A a; a.myValue1 = 1; // eroare de compilare - câmp privat a.myValue2 = 2; // câmpul public poate fi folosit peste tot

O poveste despre protejat. Partea 1.

Dacă un membru (câmp sau metodă) al unei clase este declarat cu modificatorul protejat, atunci acesta este disponibil nu numai în cadrul clasei în sine, ci și în cadrul tuturor claselor descendente:

Class Base ( protected int myValue; ... ) class Derived extinde Base ( ... myValue = 1; Derived d = ...; d.myValue = 2; // acest câmp poate fi folosit și Base b = ... ; b.myValue = 3; compilare ... }

protejat - un câmp privat (metodă) care este „transparent” pentru succesori. Prin urmare, în acest exemplu va apărea o eroare, indiferent de ce obiect b este de fapt (compilatorul nu poate ști acest lucru). Majoritatea erorilor privind drepturile de acces sunt detectate în etapa de compilare.

Această poveste ar fi corectă dacă ar exista doar trei modificatori de permisiuni în Java - public, privat și protejat - dar acest lucru nu este în întregime adevărat.

Pachete

La început am aflat că atunci când creăm o nouă clasă, trebuie să o plasăm într-un fișier cu același nume, dar aceasta nu este singura caracteristică a Java în ceea ce privește organizarea fișierelor și folderelor.

Când am scris anterior fișierul Main.java, l-am compilat în același folder, lansând compilatorul cu linia javac Main.java. Dar dacă fișierul nostru se află în alt director (de exemplu, dir1/dir2), nu trebuie doar să scriem calea pe linia de comandă, ci și să o indicăm în fișierul în sine, după cum urmează:

Pachetul dir1.dir2; // directiva pachet poate fi doar prima linie din clasa publică a fișierului Main ( ... )

Pentru a compila acum Main.java, introducem javac dir1/dir2/Main.java, care creează fișierul Main.class aflat în dir1/dir2. Și pentru a ne conduce clasa, trebuie să intrăm șir de caractere java dir1.dir2.Main (toate separatoarele de căi se transformă în puncte).

Astfel, numele pachetului specificat în fișier este același cu calea relativă a directorului în care se află. Pachetul conține doar acele fișiere care se află în directorul însuși. Fișierele din subdirectoare nu sunt fișiere din pachetul rădăcină.

dir1.dir2.Main numit numele complet calificat. Dacă este necesar, puteți introduce numele complete ale clasei în program:

Org.amse.np.list.List l = nou org.amse.np.list.List;

Dar este adesea mai convenabil import clasa sau grupul de clase de care avem nevoie pentru a folosi numele lor scurte:

Pachetul org.amse.np.hw10; import org.amse.np.list.List; // import clasa List import org.amse.np.dllist.*; // import toate clasele din pachetul dlllist (clasele subdirectorului nu sunt importate!) class Main ( ... List l = nou Listă(); )

Orice clasă importă întotdeauna toate clasele pachetului în care se află clasa și o parte din standard Biblioteci Java(ca și cum am scris linia import java.lang.*; la începutul fișierului nostru de fiecare dată), ceea ce ne permite să folosim astfel de clase standardși metode precum String, System.out.println() etc.

Pachetele pot fi folosite pentru a grupa clase, dar și pentru a separa spațiile de nume. Clasele cu aceeași nume scurt Lista poate fi distinsă după numele pachetelor lor. Prin urmare, următoarele convenții general acceptate sunt utilizate pentru denumirea pachetelor:

  • recomandat Mereu folosiți pachetul
  • toate numele pachetelor trebuie să înceapă cu litera mica
  • organizațiile comerciale folosesc pachete care încep cu com (de exemplu com.borland), restul - cu org (de exemplu org.amse)

Cu toate acestea, pachetul nu este doar o modalitate de împărțire în directoare, ci și o esență importantă a limbajului.

Permisiuni implicite

Absența unui modificator de drepturi de acces specificat în mod explicit înaintea unui membru al clasei înseamnă că acest membru va fi disponibil în toate clasele de la a acestui pachetși nu este disponibil în afara pachetului. Acest nivel de acces este numit și pachet local.

Astfel, există doar patru niveluri de acces în Java: public, privat, protejat și implicit (pachet local)

O poveste despre protejat. Partea 2

În Java, regula este că o metodă dintr-o clasă de suprascriere trebuie să aibă drepturi nu mai restrictive decât metoda din clasa sa părinte:

Class Base ( public void f() ( ... ) ) class Derived extinde Base ( private void f() ( // eroare de drepturi de acces în timpul compilării... ) )

Prin restrictivitate, nivelurile de acces pot fi distribuite după cum urmează:

Privat< protected, default < public

Dacă credeți că prima parte a poveștii despre protejat, atunci este imposibil să spuneți care nivel de acces - protejat sau implicit - este mai restrictiv. Vă puteți gândi la cazuri când câmpul implicit va fi disponibil și câmpul protejat nu va fi disponibil și invers.

Pentru a evita ambiguitățile cu drepturile de acces, de exemplu în timpul moștenirii, în Java nivelul protejat include și implicit. Adică, membrul protejat este disponibil pentru toate subclasele, plus clasele din pachet.

Ierarhia nivelului de acces este următoarea:

Privat< default < protected < public

Deci, atunci când folosim modificatorul protejat, permitem tuturor claselor dintr-un pachet dat să aibă acces la câmpul/metoda noastră, ceea ce, în cele mai multe cazuri, nu este situația către care ne propunem.

Clase imbricate

Ne vom uita la clasele imbricate doar pe scurt, ca o altă modalitate de a limita utilizarea claselor.

Există două tipuri principale de clase imbricate: clase statice (imbricate) (?) și clase membre simple (interne). Sintaxa generala:

Clasa exterioară ( clasa interioară ( ... ) ... )

Clasele statice private imbricate sunt adesea folosite:

Listă de clasă (clasa statică privată ListElement(...))

Când compilați o clasă cu o clasă imbricată, sunt create două fișiere, în acest caz: List.class și List$ListElement.class. În acest caz, numele complet al clasei imbricate va arăta astfel: org.amse.np.list.List.ListElement

Class Outer ( static class Inner ( int myValue; ... ) ... Inner i = new Inner(); // o instanță a unei clase imbricate poate fi creată în interiorul clasei însăși ... ) ... Outer.Inner i = nou Exterior (); // ...sau afară

Clasele imbricate statice se comportă la fel ca clasele obișnuite, dar au acces la alți membri statici ai acelei clase.

O clasă imbricată non-statică este legată nu de clasa înconjurătoare în sine, ci de instanța acesteia, așa că, pe lângă toate câmpurile sale, are și un implicit acest câmp, indicând instanța specifică din care face parte clasa imbricată. Această clasă imbricată are acces la toata lumea domeniile şi metodele clasei înconjurătoare.

Class Outer ( class Inner ( ... ) ... Inner i = new Inner(); // creează un câmp implicit unde Outer.this este scris) Outer o = ...; Inner i = o.new Inner();

Anexă: Modificatori de acces pentru clasele externe

Pe lângă clasele publice externe obișnuite din Java, puteți crea și așa-numitele clase locale. Ele pot fi localizate în același fișier cu clasa publică și sunt analogi ale claselor imbricate.

Clasa publică A (...) clasa B (...)

Un fișier poate avea o singură clasă publică și câte clase locale se dorește. Fișierul trebuie să aibă același nume ca și clasa publică.

Vom vorbi despre modificatori: care sunt modificatorii, domeniile, modificatorii pentru clase, câmpuri, metode. Cred că nu va fi plictisitor.

Modificatori în Java sunt cuvinte cheie care dau anumite proprietăți unei clase, unui câmp de clasă sau unei metode.

Pentru a indica vizibilitatea unei clase a metodelor și câmpurilor sale, există 4 modificatori de acces:

  • privat membrii clasei sunt accesibili numai în cadrul clasei;
  • pachet-privat sau implicit (implicit) membrii clasei sunt vizibili în interiorul pachetului;
  • protejat membrii clasei sunt disponibili în interiorul pachetului și în clasele descendente;
  • public membrii clasei sunt disponibile pentru toată lumea.

Dacă vă amintiți, la final, când importasem deja clasa Cat, mai aveam o eroare de compilare.

Chestia este că nu am specificat niciun modificator de acces la câmpurile și metodele noastre și au o proprietate implicită (membrii clasei sunt vizibili în interiorul pachetului). Pentru a remedia eroarea de compilare pentru codul nostru și în cele din urmă a-l rula, trebuie să facem publice constructorul și metodele noastre. Apoi pot fi apelate din alte pachete.

Poate începeți să vă întrebați: pentru ce sunt toate acestea? De ce să nu faceți codul vizibil din orice pachet sau clasă, dar trebuie să restricționați accesul? Aceste întrebări vor dispărea de la sine atunci când va veni timpul să scriem proiecte complexe și greoaie. Acum, când scriem aplicații a căror funcționalitate este limitată la una sau două clase, se pare că nu are rost să limităm ceva.

Imaginați-vă că aveți o clasă care afișează un obiect al unui anumit produs. De exemplu o mașină. Masina poate avea un pret. Ați creat un câmp de preț și multe alte câmpuri, o grămadă de metode care sunt responsabile de funcționalitate. Totul pare în regulă. Mașina dvs. de clasă face parte dintr-un proiect uriaș și toată lumea este fericită. Dar să presupunem că cineva a creat accidental sau intenționat o instanță a clasei de mașini și a stabilit un preț negativ. Poate un produs să aibă un preț negativ? Acesta este un exemplu foarte primitiv și este puțin probabil să se întâmple în viata reala, dar cred că ideea este clară. Uneori trebuie să acordați acces nu direct, ci prin anumite metode. Este posibil ca codul să fie responsabil pentru funcționalitatea altui cod și nu doriți ca cineva să schimbe și să editeze o parte din a dvs. În acest scop există o restricție de acces.

Modificatorul de acces pentru constructori, metode și câmpuri poate fi orice. O clasă poate fi doar publică sau implicită și poate exista doar o clasă publică într-un fișier.

Este suficient despre modificatorii de acces pentru moment. În articolul „Programare orientată pe obiecte” vom vorbi despre ele mai detaliat, dar acum să vorbim despre alți modificatori dintre care, apropo, sunt mulți.

Acum vine modificatorul static. Poate fi folosit înaintea unei metode, câmp și chiar a unei clase atunci când dorim să declarăm o clasă imbricată. În Java, puteți scrie clase în interiorul altor clase, iar dacă modificatorul dinaintea clasei din interiorul clasei este static, atunci o astfel de clasă se numește imbricată, dacă un alt modificator este sau implicit, atunci o astfel de clasă se numește intern. Va exista un articol separat despre clasele imbricate și interioare, deoarece totul nu este atât de simplu acolo.

Modificatorul static din fața unei metode sau câmp indică faptul că nu aparține unei instanțe a acelei clase. Ce înseamnă asta pentru noi? Când am declarat un câmp sau o metodă de clasă ca static, acesta poate fi apelat fără a utiliza o instanță a clasei. Adică, în locul acestei construcții: Cat cat = new Cat(); cat.method(), puteți scrie pur și simplu Cat.method(). Cu condiția ca metoda să fie declarată ca fiind statică. Variabilele statice sunt aceleași pentru toate obiectele de clasă. Au un singur link.

    Modificatori de clasă publică (

    static int anotherStaticField = 5 ;

    public static void myStaticMethod() (

    someField = "Câmpul meu" ;

    //nonStaticField = ""; eroare de compilare

    //nu puteți folosi câmpuri non-statice

    //în metode statice

    public void myNonStaticMethod() (

    anotherStaticField = 4; //se pot folosi câmpuri statice

    //în metode non-statice

    //Metoda principală are și un modificator static

    noi Modificatori() .myNonStaticMethod() ;

    Modificators.myStaticMethod(); //apelează metode și câmpuri statice

    //prin Classname.method

O alta notă importantă Un lucru de spus despre modificatorii statici: câmpurile statice sunt inițializate atunci când clasa este încărcată. Adesea, în diferite tipuri de teste Java, puteți găsi următorul cod:

Întrebare: ce va fi scos pe consolă? Trebuie să rețineți că blocul static va fi scos mai întâi în orice caz. Următorul va fi blocul implicit. Apoi, uită-te la ecranul consolei:

Următorul modificator la care ne vom uita va fi final.

Cred că cuvântul final vorbește de la sine. Folosind modificatorul final, spuneți că câmpurile nu pot fi modificate, metodele nu pot fi suprascrise și clasele nu pot fi moștenite (va exista un articol separat despre moștenire). Acest modificator se aplică numai claselor, metodelor și variabilelor (de asemenea, variabilelor locale).

Vom vorbi despre modificatorul final al metodelor și claselor în articolul OOP.

Urmează modificatorii care nu vor fi foarte clari pentru începători sau pentru cei care citesc această serie de articole de la zero. Și, deși încă nu vă voi putea explica totul (din cauza faptului că nu cunoașteți materialul însoțitor), vă sfătuiesc totuși să vă familiarizați cu ele. Când va veni timpul să folosiți acești modificatori, veți înțelege deja majoritatea termenilor folosiți mai jos.

Modificator sincronizate- indică faptul că metoda poate fi folosită doar de un fir la un moment dat. Deși acest lucru poate să nu vă spună nimic, utilitatea acestui modificator va fi văzută atunci când studiem multithreading.

Modificator tranzitoriu— indică faptul că un anumit câmp ar trebui ignorat în timpul serializării obiectului. De regulă, astfel de câmpuri stochează valori intermediare.

Modificator volatil- folosit pentru multithreading. Când un câmp cu modificatorul volatil va fi folosit și modificat de mai multe fire de execuție, acest modificator asigură că câmpul va fi modificat la rândul său și nu va exista confuzie cu acesta.

Modificator nativînainte de a declara o metodă, indică faptul că metoda este scrisă într-un alt limbaj de programare. De obicei în limbaj C.

Modificator strictfp— Asigură că operațiunile pe numere flotante și duble (virgulă mobilă) sunt efectuate conform standardului IEEE 754 Sau, mai simplu, garantează că în cadrul metodei, rezultatele calculelor vor fi aceleași pe toate platformele.

Nu am vorbit încă despre modificator abstract. O să vă povestesc pe scurt, pentru că fără a cunoaște elementele de bază programare orientată Nu văd niciun rost să vorbesc despre el.

O clasă care are modificatorul abstract nu poate crea o instanță. Singurul scop este să fie extins. Clasa abstractă poate conține atât metode abstracte, cât și metode obișnuite.

Vom vorbi mai multe despre modificatorul abstract în articolul OOP.

Aici putem termina articolul despre modificatori. Despre ei nu s-au spus multe. Dar acest lucru se datorează faptului că nu avem încă conceptele de POO. Pe parcursul mai multor articole, vom extinde cunoștințele despre modificatori și vom completa golurile.

Modificatorii nivelului de acces determină dacă alte clase pot folosi un anumit câmp sau invoca o anumită metodă. Există două niveluri de control al accesului:

  • La cel mai înalt nivel public , sau pachet-privat(fără modificator explicit).
  • La nivel de membru public, privat, protejat sau pachet-privat(fără modificator explicit).

O clasă poate fi declarată cu modificator public , caz în care acea clasă este vizibilă pentru toate clasele de pretutindeni. Dacă o clasă nu are modificator (prestabilit, cunoscut și ca pachet-privat), este vizibil numai în propriul pachet (pachetele sunt numite grupuri de clase înrudite pe care le veți afla într-o lecție ulterioară.)

La nivel de membru, puteți folosi și modificatorul public sau niciun modificator ( pachet-privat) la fel ca la clasele de nivel superior și cu același sens. Pentru membri, există doi modificatori de acces suplimentari: privat și protejat. Modificatorul privat specifică faptul că membrul poate fi accesat numai în propria sa clasă. Modificatorul protejat specifică faptul că membrul poate fi accesat numai în cadrul propriului pachet (ca și cu pachet-privat) și, în plus, printr-o subclasă a clasei sale într-un alt pachet.

Următoarele tabelul arată accesul la membrii permis de fiecare modificator.

Niveluri de acces
Modificator Clasă Pachet Subclasă Lume
public Y Y Y Y
protejat Y Y Y N
nici un modificator Y Y N N
privat Y N N N

Prima coloană de date indică dacă clasa în sine are acces la membrul definit de nivelul de acces. După cum puteți vedea, o clasă are întotdeauna acces la propriii membri. A doua coloană indică dacă clasele din același pachet cu clasa (indiferent de originea lor) au acces la membru. A treia coloană indică dacă subclasele clasei declarate în afara acestui pachet au acces la membru. A patra coloană indică dacă toate clasele au acces la membru.

Nivelurile de acces vă afectează în două moduri. În primul rând, atunci când utilizați clase care provin dintr-o altă sursă, cum ar fi clasele din Platforma Java, nivelurile de acces determină ce membri ai acestor clase pot folosi propriile clase. În al doilea rând, atunci când scrieți o clasă, trebuie să decideți ce nivel de acces ar trebui să aibă fiecare variabilă membru și fiecare metodă din clasa dvs.

Să ne uităm la o colecție de clase și să vedem cum nivelurile de acces afectează vizibilitatea. Figura următoare arată cele patru clase din acest exemplu și cum sunt legate.

Următorul tabel arată unde sunt vizibili membrii clasei Alpha pentru fiecare dintre modificatorii de acces care le pot fi aplicați.

Vizibilitate
Modificator Alfa Beta Alphasub Gamma
public Y Y Y Y
protejat Y Y Y N
nici un modificator Y Y N N
privat Y N N N

Sfaturi pentru alegerea unui nivel de acces:

Dacă alți programatori vă folosesc clasa, tu vrei pentru a se asigura că erorile din utilizarea abuzivă nu pot apărea. Nivelurile de acces vă pot ajuta să faceți acest lucru.

  • Utilizați cel mai restrictiv nivel de acces care are sens pentru un anumit membru. Folosiți privat, cu excepția cazului în care aveți un motiv întemeiat să nu o faceți.
  • Evitați câmpurile publice, cu excepția constantelor. (Multe dintre exemplele din tutorial folosesc câmpuri publice. Acest lucru poate ajuta la ilustrarea concisă a unor puncte, dar nu este recomandat pentru codul de producție.) Câmpurile publice tind să vă facă legătura cu o anumită implementare și să vă limiteze flexibilitatea în schimbarea codului.

5

Am văzut câteva discuții pe StackOverflow despre acest subiect, dar nu văd nimic care să mă fi ajutat să înțeleg următorul punct:

Vin dintr-un mediu C++ și recent am început să învăț Java. În C++, când protejat, este folosită doar subclasa care poate accesa membrul (analog unui câmp în Java).

Există, de asemenea, clase „prieten” în C++ care pot avea acces la camere private/protejate de clasă care dau „prietenie”. Acesta este un pic ca modificatorul de câmp „pachet” în Java (modificatorul de câmp implicit), cu excepția faptului că în C++, prietenia oferă acces tuturor membrilor privați, dar în Java, accesul de la clasele din același pachet este specific câmpului de clasă .

Ceea ce nu pot să-mi dau seama, presupunând că vreau doar să acord acces la subclase, este ceea ce pot face în C++ declarând membri protejați într-o clasă care nu „oferă” prietenii.

Dar în Java nu știu cum să fac asta, deoarece folosind un modificator de câmp „protejat” - ofer și acces la toate clasele din pachet. Singura modalitate pe care o găsesc de a face acest lucru este să declar un câmp protejat și să izolez clasa în propriul pachet.

De aici concluzionez că gruparea claselor într-un singur pachet trebuie făcută pe baza „prieteniei” dintre clase. Este acesta cu adevărat factorul determinant în gruparea pachetelor?

Un alt lucru pe care nu îl înțeleg, în Java, presupunând că am două câmpuri în clasa A: b, c. Vreau să-i dau lui B acces la b, dar nu la și vreau să-i dau lui C acces la c, dar nu la b. iar la „Lumea” vreau ca b, c să se ascundă. Cum pot face acest lucru? Bănuiesc că B, C ar trebui să fie în același pachet ca A. dar declarând b, c cu pachet cu modificatorul I permit accesul lui B, C atât la b cât și la k. Există vreo modalitate în Java de a face asta?

Sper să avem niște explicații despre această problemă

11

O întrebare mai bună, dacă vă este mai puțin utilă, ar fi una mai restrânsă și mai specifică. Întrebarea generală „totul despre confidențialitate în Java și C++ și modul în care diferă” este mai mult decât puțin prea largă. Puteți pune o întrebare mai specifică despre o problemă mai specifică? - Yakk 04 mar 15 2015-03-04 16:38:58

  • 4 raspunsuri
  • Triere:

    Activitate

2

În C++, când se utilizează protecția, doar subclasa poate accesa elementul (analog cu un câmp din Java).

Specificatorii de acces sunt, de asemenea, pentru funcțiile/metodele membre, nu doar pentru variabilele membre.

În C++ există și clase „prieten” care pot avea acces la membrii privați/protejați ai unei clase, dând „prietenie”. Acesta este un pic ca modificatorul de câmp „pachet” în Java (modificatorul de câmp implicit), cu excepția faptului că în C++, prietenia oferă acces tuturor membrilor privați, dar în Java, accesul din clasele din același pachet este specific clasei camp.

Nu există doar cursuri de prieteni, ci și funcții.

Este adevărat că accesul la părțile private ale Java este similar, dar nu este un înlocuitor complet. Este mai bine să spunem că aceste două funcții au subset problemele pe care le rezolvă. Sunt probleme care pot fi rezolvate de prieten, dar nu de pachet-privat și invers.

Ceea ce nu mi-am putut da seama, presupunând că vreau doar să acord acces la subclase, este ceea ce pot face în C++ declarând utilizatorii protejați într-o clasă care nu „oferă” prietenie.

Dar în Java, nu știu cum pot face asta,

Răspuns: Nu poți.

deoarece folosind un modificator de câmp „protejat” - ofer și acces la toate clasele din pachet.

Singura modalitate pe care o găsesc este să declar un câmp protejat și să izolați clasa în pachetul său.

Tehnic, da. Dar asta creează alte probleme. Clasa dvs. nu va mai putea accesa părțile pachetului privat din pachetul anterior. Să presupunem că BaseClass a fost în com.example.one . Îl vei muta în com.example.two. Acum nu va mai putea accesa alte pachete de clasă privată com.example.one.

Este acesta cu adevărat factorul determinant în gruparea pachetelor?

Da, Java este conceput astfel. Poti incerca lupta cu regulile limbajului, dar aceasta este o bătălie pierdută în orice limbaj de programare.

Un alt lucru pe care nu îl înțeleg este în Java, presupunând că am două câmpuri în clasa A: b, c. Vreau să-i dau lui B acces la b, dar nu la și vreau să-i dau lui C acces la c, dar nu la b. iar în „Lumea” vreau ca b, c să se ascundă. Cum pot face acest lucru?

Acest lucru nu se poate face într-un mod curat (prin clean vreau să spun: fără hack-uri care ar necesita să verificați stiva de apeluri în timpul execuției și să aruncați excepții).

Dacă sunteți îngrijorat de acest scenariu deoarece dezvoltați un API public, o soluție low-tech care de obicei funcționează excelent este să creați unul sau mai multe pachete *.internal și să documentați clar faptul că acestea nu ar trebui să fie utilizate în codul clientului.

1

Sunt o grămadă de întrebări împreună...

Dar în Java, nu știu cum pot face acest lucru, deoarece în virtutea utilizării unui modificator de câmp „protejat” - ofer și acces la toate clasele din pachet.

Într-adevăr, nu există nicio modalitate de a oferi acces doar la subclase, dar nu și la clase din același pachet. Aceasta a fost o decizie de design luată cu secole în urmă...

Singura modalitate pe care o găsesc de a face acest lucru este să declar un câmp protejat și să-l izolez în pachetul tău.

Acest lucru este corect din punct de vedere tehnic, deși va fi de puțin folos. Ambalarea de clasă este destinată grupării claselor înrudite, unde „înrudit” înseamnă „clase care realizează o relație specifică”, adică aparțin aceluiași caz de utilizare, aparțin aceluiași nivel arhitectural, sunt în aceleași esențe etc.

De aici concluzionez că gruparea claselor într-un singur pachet trebuie făcută pe baza „prieteniei” dintre clase. Este acesta cu adevărat factorul determinant în gruparea pachetelor?

Cred că am răspuns deja la asta paragraful anterior: Ambalajul este conceput pentru a grupa clasele conexe în funcție de anumite criterii specifice.

Pentru clasele dvs. A, B și C, de exemplu cu atribute:

Cred că B, C ar trebui să fie ambele în același pachet, A. a declarând b, cu modificatorul de ambalare i-am lăsat B, C să acceseze atât b, cât și k. Există o modalitate în Java de a face acest lucru?

Răspunsul este nu, nu există o modalitate simplă și curată de a face acest lucru. Ai putea realiza acest lucru cu niște hack-uri sau tehnici mai avansate, dar din nou, acest lucru a făcut parte din deciziile luate de dezvoltatorii de limbaj cu mult timp în urmă...

0

Răspuns scurt: nu există nicio modalitate de a face acest lucru.

Dacă sunteți îngrijorat de intruziunea clienților cu grad de injecție în pachetul de primit acces neautorizat, puteți muta codul sensibil într-un pachet separat și faceți pachetul sigilat într-un borcan la care îl livrați: http://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html

1

Se presupune implicit că toate clasele dintr-un pachet „se cunosc” între ele (pentru că au fost scrise de aceeași persoană/companie/organizație). Deci, fie nu accesează câmpurile protejate, fie dacă o fac, știu cum să o facă corect.

Se presupune că clasele din același pachet sunt mai legate între ele decât este părintele cu clasa derivată, deoarece clasa derivată ar putea fi de fapt scrisă de altcineva. Prin urmare, au decis că protecția privată era mai limitată decât protejată.

Deci, cred că nu ar trebui să vă faceți griji cu privire la modul în care clasele din același pachet pot accesa câmpurile celuilalt. În general, pur și simplu nu folosesc această caracteristică decât atunci când scriu iteratoare.

Dacă aveți două câmpuri, le puteți face clase interioare, astfel încât să aibă acces la câmpurile private (din nou, logic: dacă o clasă se află în interiorul unei alte clase, ea știe despre semantica acelei clase) și să poată oferi acel acces la clase derivate prin metode securizate.

Desigur, ai putea veni cu un protocol complex de schimb de jetoane pentru a face acest câmp accesibil doar instanțelor B/C, dar asta ar fi o suprasolicitare minunată, iar celălalt obiect ar putea folosi reflecția pentru a accesa toți membrii privați dacă nu Nu îl dezactivați prin politici de securitate, ceea ce de obicei nu este cazul, dar, din nou, politicile de securitate sunt hotărâte în cele din urmă de proprietarul JVM.

Deci, în cele din urmă, modalitatea preferată de a face ceea ce spuneți în Java este fie să le puneți în același pachet, fie să scrieți B și C ca clase interioare ale lui A, astfel încât să poată accesa direct membrii privați ai lui A și să-i expună la clasele derivate. .

Clasa publică A (clasa publică abstractă statică B (protejat Whatever getWhatever(A a) ( return a.b; ) protected void setWhatever(A a, Whatever value) ( ​​​​​a.b = value; ) ) public static abstract class C (protejat Whatever getWhatever) (A a) ( return a.c; ) protected void setWhatever (A a, Indiferent de valoare) ( ​​​a.c = valoare; ) ) private Indiferent de privat b)

încă o dată, presupui întotdeauna că clasele din același pachet nu vor face niciodată nimic rău.