Bloc de inițializare

Un bloc de inițializare este un concept în programarea orientată pe obiecte , cunoscut în principal din limbajul Java , care este o secvență de comenzi executate la crearea ( încărcarea ) claselor și obiectelor . Conceput pentru a crește considerabil puterea constructorului . Există două tipuri: un bloc de inițializare static, numit în mod obișnuit bloc static pe scurt, și un bloc de inițializare dinamică (bloc de instanță).

Motivație

Când este creat un obiect, sunt executate diverse comenzi specificate în constructor. Uneori devine necesar să se extindă posibilitățile de sintaxă. De obicei, un bloc dinamic există doar pentru comoditate - poate fi înlocuit cu ușurință prin adăugarea unei funcții de încărcare și apelarea acesteia de la fiecare constructor. Cu toate acestea, blocul static crește foarte mult funcționalitatea programului și, prin urmare, este folosit mult mai frecvent.

Bloc de inițializare static

Un bloc static este în esență un constructor pentru întreaga clasă. Sintaxa sa este:

... static { // Cod bloc static } ...

Este plasat între definițiile câmpurilor și funcțiile de clasă. Comenzile vor fi executate într-unul din cele două cazuri, oricare survine primul:

  1. La crearea primului obiect al clasei în cursul programului, înainte de a rula constructorul.
  2. Prima dată când este apelată o funcție statică, înainte de execuție.

Adică, codul este executat prima dată când clasa este încărcată. În acest exemplu, dorim să creăm o clasă care să modeleze mașinile produse de o anumită companie și să le întrețină pentru a ține evidența restului existenței lor, inclusiv situația lor actuală, proprietarii, istoricul reparațiilor și așa mai departe. Fiecare obiect este o mașină , iar în clasă există un câmp static care conține o bază de date cu toate mașinile. Pe baza structurii hărții când cheia este un model de mașină și conținutul este un grup de mașini ale modelului respectiv. Următorul cod demonstrează utilizarea unui bloc de inițializare statică:

mașină de clasă publică { static Map < String , Set < Car >> catalog ; static { catalog = new HashMap < String , Set < Car >> (); catalog . put ( "model105" , nou HashSet < Car > ()); catalog . put ( "model125" , nou HashSet < Car > ()); catalog . put ( "model140" , nou HashSet < Car > ()); catalog . put ( "model201" , nou HashSet < Car > ()); } mașină publică ( model String ) { catalog . obține ( model ). adauga ( acesta ); // ... } // ... }

Linia 4 poate fi atașată cu ușurință la linia 2 fără a fi nevoie de un bloc static. Cu toate acestea, liniile 5-8 arată necesitatea acesteia - capacitatea de a executa comenzi complexe la nivel de clasă, care la nivel de obiect ar apărea în constructor.

Bloc de inițializare dinamică

Un bloc dinamic este o completare la un constructor. Sintaxa sa este:

... { // Cod de blocare a instanței } ...

Este plasat între definițiile câmpurilor și funcțiile de clasă. Comenzile vor fi executate la crearea obiectului. Blocul dinamic este un add-on pentru a face constructorul mai ușor de scris și nu aduce funcționalități suplimentare. Vă permite să salvați crearea unei funcții de lansare și să adăugați apelul acesteia de la toți constructorii. De exemplu, fragment de cod:

mașină de clasă publică { static int count = 0 ; mașină publică ( model String ) { init (); // ... } mașină publică ( model String , preț dublu ) { init (); // ... } private void init () { numără ++ ; Sistem . afară . println ( "Bună ziua tuturor, avem " + count + " mașini acum!" ); } // ... }

este echivalent cu codul:

mașină de clasă publică { static int count = 0 ; mașină publică ( model String ) { // ... } mașină publică ( model String , preț dublu ) { // ... } { numără ++ ; Sistem . afară . println ( "Bună ziua tuturor, avem " + count + " mașini acum!" ); } // ... }

Ordine de încărcare

În timpul proiectării limbajului Java, a fost stabilită o ordine de încărcare consistentă. În timpul încărcării clasei, ordinea este următoarea:

  1. Definițiile câmpurilor statice ale claselor părinte.
  2. Inițializarea câmpurilor statice și execuția blocurilor statice ale claselor părinte.
  3. Definițiile câmpurilor statice ale unei clase.
  4. Inițializarea câmpurilor statice și executarea blocurilor de clasă statică.

Apoi, când obiectul este creat, ordinea este următoarea:

  1. Definițiile câmpurilor obiect din clasele părinte.
  2. Inițializarea câmpului și execuția blocurilor dinamice din clasele părinte.
  3. Executarea constructorilor din clasele părinte.
  4. Definiții ale câmpurilor obiect din clasa sa.
  5. Inițializarea câmpului și execuția blocurilor dinamice din clasa sa.
  6. Executarea unui constructor din clasa sa.

Când există un lanț de strămoși, toate acțiunile sunt efectuate mai întâi pe cel mai îndepărtat strămoș (clasa Object) și apoi în jos în lanț în aceeași ordine până la clasa curentă.

Dacă există mai multe tipuri în aceeași secțiune de mai sus, pașii sunt efectuati în ordinea în care apar în program. De exemplu, următorul cod:

clasa publica T { static int i = 5 ; static { i = 10 ; } static { i = i * 3 ; } }

atribuie valoarea 30 variabilei i din fiecare obiect, dar codul:

clasa publica T { static { i = 10 ; } static int i = 5 ; static { i = i * 3 ; } }

atribuie o valoare de 15. Adică, mai întâi este creat un câmp, apoi toate acțiunile sunt efectuate în ordinea specificată în program - primul bloc, apoi inițializarea câmpului, apoi al doilea bloc.

Posibile probleme

Folosind o variabilă înainte de a fi definită

Contrar a ceea ce v-ați putea aștepta, următorul cod:

clasa publica T { static { i = 5 ; i = i + 1 ; } static int i = 5 ; }

nu reușește să compileze pe linia 4 deoarece variabila i din dreapta a fost folosită înainte de a fi definită, chiar dacă linia 3 se compilează și rulează fără probleme, chiar dacă i-ul din stânga pe linia 4 nu aruncă o eroare și în ciuda faptului că în timpul funcționării, când se ajunge la începutul liniei 4, variabila a fost definită și a primit o valoare. Acest lucru se datorează faptului că plasarea variabilelor (de exemplu, pe linia 3) este verificată cu lista de variabile definite în prezent în timpul execuției programului, inclusiv toate câmpurile statice, iar utilizarea unei astfel de variabile este verificată față de locația definiției.

Variabila statica locala

Contrar a ceea ce v-ați putea aștepta, următorul cod:

clasa publica T { static { int i = 10 ; } public static void main ( String [] args ) { Sistem . afară . println ( i ); } }

va eșua compilarea pe linia 6 pe motiv că variabila nu este definită, deoarece definirea unei variabile într-un bloc static nu creează o variabilă statică, ci doar o variabilă locală în acel bloc. Adică, codul nu este echivalent cu codul . static {int i = 10;}static int i = 10;

Vezi și

Link -uri