Tutorial Java SCJP – # 18 Blocuri de initializare

Pentru a face prelucrari si pentru a obtine rezultate este nevoie de date. Si aceste valori de intrare sunt de obicei stocate in variabile statice, variabilele locale (definite în metode) sau variabile de instanta (variabile nonstatice definite în clase). Pentru a initializa o variabila o poti face la definitia sau mai târziu într-o metoda (constructor sau nu). In ciuda acestor doua solutii comune, exista o alta cale folosind blocuri de initializare.

Blocurile de initializarea sunt blocuri de cod definite intre { si }. Din acest punct de vedere, ele seamana cu blocuri/corpuri de metode, dar principala diferenta este ca blocurile de initializare nu au un nume. Ele sunt ca metodele, insa fara antet/header (tip returnat, nume metoda, lista de parametri).

Alte subiecte care fac parte din acest tutorial Java sunt accesibile prin intermediul Java Tutorial 6 – Cuprins.

Ca majoritatea lucrurilor in Java, blocuri de initializare sunt de asemenea definite intr-o clasa si nu la nivel global.

Un exemplu de bloc initializare este:

public class Main {
    //static initialization block
    static
    {
        System.out.println("Acesta este un bloc static de initializare !");
    }
    //initialization block
    {
        System.out.println("Acesta este un bloc de initializare !");
    }
    public static void main(String[] args) {
        System.out.println("Aceasta este metoda main() !");
    }
}

Daca se executa exemplul anterior, rezultatul afisat la consola este:

Acesta este un bloc static de initializare !
Aceasta este metoda main() !

Dupa cum se poate vedea in exemplul anterior, exista doua tipuri de blocuri de initializare cu comportamente diferite:

  • blocuri statice de initializare – blocuri de cod care sunt executate DOAR O DATA atunci când clasa este incarcata de Java Virtual Machine; acesta este motivul pentru care mesajul din blocul static de initializare este imprimat inainte de metoda main(); aceste tipuri de blocuri de initializare sunt utile pentru initializarea atributelor statice din clase sau pentru a efectua o singura data un set de prelucrari;
  • blocuri de initializare (blocuri instanta de initializare) – blocuri de cod care sunt executate de fiecare data când o instanta a clasei este creata (in cazul in care constructorul este apelat); aceste blocuri de initializare urmaresc initializari de atribute statice sau prelucrari generice ce trebuie executate de fiecare data cand se construieste un obiect indiferent de constructorul apelat.

Pe baza acestei descrieri, exemplul urmator:

class Test{
    //bloc static de initializare
    static
    {
        System.out.println("Bloc static de initializare  din Test !");
    }
    //bloc de initializare
    {
        System.out.println("Bloc de initializare din Test !");
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println("Aceasta este metoda main() !");
        Test t1 = new Test();
        Test t2 = new Test();
        System.out.println("Sfarsit metoda main() !");
    }
}

genereaza rezultatele:

Aceasta este metoda main() !
Bloc static de initializare  din Test !
Bloc de initializare din Test !
Bloc de initializare din Test !
Sfarsit metoda main() !

Dupa cum se poate vedea in exemplul anterior, este important sa se identifice in mod corect, in care clasa sunt definite blocuri de initializare, deoarece blocurile statice de initializare sunt executate doar atunci când clasa este incarcata de JVM si blocurile instanta de initializare sunt executate de fiecare data când o instanta este creata.

Motivul pentru care la consola se vede in primul rand mesajul din metoda main() este dat de faptul ca clasa Test este incarcata de JVM inainte de momentul construirii primei instante de tip Test si nu la startul aplicatiei Java. Din punct de vedere la masinii virtuale, clasa Main este incarcata inainte de clasa Test.

Spre deosebire, in primul exemplu blocul de initializare static a fost definit in clasa Main si a fost executat odata cu incarcarea calsei Main, inainte de metoda main().

In exemplul anterior, daca se comenteaza instructiunile:

        //Test t1 = new Test();
        //Test t2 = new Test();

atunci mesajele de la consola sunt:

Aceasta este metoda main() !
Sfarsit metoda main() !

Se pot defini oricat de multe blocuri de initializare (statice sau nu) dar trebuie sa se acorde atentie la ordinea lor, deoarece aceasta este si ordinea lor de executie:

class Test
{
    //bloc static de initializare
    static
    {
        System.out.println("Bloc static de initializare 1 din Test !");
    }
    //bloc de initializare
    {
        System.out.println("Bloc de initializare 1 din Test !");
    }
    //bloc de initializare
    {
        System.out.println("Bloc de initializare 2 din Test !");
    }
    static
    {
        System.out.println("Bloc static de initializare 2 din Test !");
    }
}

public class Main {
    //bloc static de initializare
    static
    {
        System.out.println("Bloc de initializare din Main !");
    }
    //bloc de initializare
    {
        System.out.println("Acesta este un bloc de initializare !");
    }
    public static void main(String[] args) {
        System.out.println("Aceasta este metoda main() !");
        Test t1 = new Test();
        Test t2 = new Test();
        System.out.println("Sfarsit metoda main() !");
    }
}

Mesajele afisate in consola sunt:

Bloc de initializare din Main !
Aceasta este metoda main() !
Bloc static de initializare 1 din Test !
Bloc static de initializare 2 din Test !
Bloc de initializare 1 din Test !
Bloc de initializare 2 din Test !
Bloc de initializare 1 din Test !
Bloc de initializare 2 din Test !
Sfarsit metoda main() !

deoarece:

  1. clasa Main este incarcata de JVM pentru a se executa metoda main(); blocul de initializare static din clasa Main este executat;
  2. metoda main() este executata;
  3. primul bloc static de initializare din clasa Test este executat, deoarece clasa Test este incarcata pentru a se construi instanta t1;
  4. al doilea bloc static de initializare din clasa Test este executat, deoarece clasa Test este incarcata pentru a se construi instanta t1;
  5. prima instanta de tip Test, t1, este creata si este executat primul bloc instanta de initializare;
  6. prima instanta de tip Test, t1, este creata si este executat  al doilea bloc de initializare;

Blocuri de initializare si atributele clasei

Blocuri de initializare sunt asociate cu o clasa si instantele sale. Referitor la ce tipuri de atribute ale clasei pot fi folosite in blocurile de initializare:

  • bocurile statice de initializare pot accesa DOAR atributele statice ale clasei in care sunt definite;  NU se pot folosi variabile de instanta in blocuri de initializare statice (daca incercati sa faceti acest lucru veti primi o eroare de compilare: non-static variable value cannot be referenced from a static context);
  • blocurile instanta de initializare pot accesa atribute statice si variabile de instanta (variabilele de instanta reprezinta atributele instantei construite) deoarece acestea sunt executate chiar inainte de construirea instantei;
class Test
{
    public int valoare;
    public static int valoareStatica;
    //bloc static de initializare
    static
    {
        System.out.println("Bloc static de initializare 1 din Test !");
        valoareStatica = 23;
        //valoare = 50;     //eroare de compilare
    }
    //bloc de initializare
    {
        System.out.println("Bloc de initializare 1 din Test !");
        valoare = 50;
    }
}

public class Main {
    public static void main(String[] args) {
        Test t1 = new Test();
        System.out.println("valoareStatica = "+Test.valoareStatica);
        System.out.println("t1.valoare = "+t1.valoare);
    }
}

and the output is

Bloc static de initializare 1 din Test !
Bloc de initializare 1 din Test !
valoareStatica = 23
t1.valoare = 50

Blocuri de initializare si ierarhii de clase

Blocuri statice de initializare sunt executate in secventa:

  1. blocuri statice din clasa de baza
  2. blocuri statice din clasa derivata

deoarece fiecare bloc static de initializare este executat dupa ce clasa in care este definit este incarcata.

Blocuri de initializare sunt executate dupa apelul constructorului din clasa de baza – super().

Urmatorul exemplu:

class Baza{
    static
    {
        System.out.println("Bloc static de initializare din Baza !");
    }
    {
        System.out.println("Bloc de initializare din Baza !");
    }
    public Baza() { System.out.println("Constructor din Baza !");}
}
class Child extends Baza{
    public Child()
    {
        System.out.println("Constructor din Derivata !");
    }
    static
    {
        System.out.println("Bloc static de initializare din Derivata !");
    }
    {
        System.out.println("Bloc de initializare din Derivata !");
    }
}
public class Main {
    public static void main(String[] args) {
        Child c = new Child();
    }
}

genereaza urmatorul ouput:

Bloc static de initializare din Baza !
Bloc static de initializare din Derivata !
Bloc de initializare din Baza !
Constructor din Baza !
Bloc de initializare din Derivata !
Constructor din Derivata !

Elemente importante pentru examenul de certificare SCJP:

  • blocurile statice de initializare sunt executate DOAR O DATA atunci când clasa este incarcata de JVM;
  • verificati in ce clasa este definita metoda main() si in ce clasa sunt definite blocuri de initializare, pentru a determina corect output-ul;
  • blocurile de initializare (sau blocurile instanta de initializare) sunt executate de fiecare data când o instanta a clasei este creata;
  • blocurile instanta de initializare sunt executate in ordinea in care sunt definite;
  • blocurile instanta de initializare sunt executate dupa apelul constructorului din clasa de baza  -super();
  • blocurile instanta de initializare au acces la variabile de instanta si la atributele statice ale clasei;
  • blocurile statice de initializare au acces NUMAI la atributele statice.

Alte subiecte care fac parte din acest tutorial Java sunt accesibile prin intermediul Java Tutorial 6 – Cuprins.