Noțiuni despre Java
Java este un limbaj de programare dezvoltat de fosta companie Sun Microsystems (actual Oracle) și lansat în anul 1995. Bazându-se pe acest limbaj și pe ideea de mașină virtuală, în momentul actual au apărut nenumărate tehnologii pentru aplicații web și distribuite [1].
Compilare vs. Interpretare
Înainte de a prezenta mecanismul de mașină virtuală, trebuie să facem o scurtă descriere a metodelor de execuție a programelor pentru diferite limbaje de programare.
Procesorul unui calculator (sau a unei mașini de calcul în general) poate executa un număr fix de instrucțiuni cunoscute procesorului, numit set de instrucțiuni. Un program poate fi scris folosind direct aceste instrucțiuni (mnemonicile lor), adică în limbaj de asamblare, sau într-un limbaj de nivel înalt. Există avantaje și dezavantaje pentru ambele variante.
Un program scris în limbaj de asamblare nu este deloc portabil, deci nu poate fi executat decât pe mașina pentru care a fost scris, adică depinde de setul de instrucțiuni pe care procesorul știe să îl execute, de sistemul de operare care rulează pe mașină, de perifericele prezente, etc. Alt dezavantaj este că pentru o funcționalitate relativ simplă a programului, trebuie scrisă o cantitate mult mai mare de cod decât într-un limbaj de nivel înalt (cum ar fi C sau Java), lucru care face ca mentenanța codului, ca și posibilitățile de dezvoltare să fie mult limitate. Pe de altă parte, un programator cu experiență poate face cele mai bune optimizări în limbaj de asamblare, el având control absolut asupra tuturor resurselor disponibile.
Totuși, pentru aplicații foarte complexe, este necesar un compromis între performanță și dimensiunea/ complexitatea codului. Astfel au apărut limbaje formale, de nivel înalt, care sunt mult mai intuitive, mai ușor de învățat și de înțeles, și care abstractizează o mare parte din straturile de nivel jos ale unei mașini de calcul (setul de instrucțiuni, harta memoriei, structura stivei de execuție, alocarea memoriei, etc.). Avantajele sunt uriașe, începând cu simplitatea sintactică și semantică a unui program și terminând cu faptul că apare acum un anumit grad de portabilitate. Această portabilitate apare datorită faptului că limbajul în sine este unic și un algoritm este descris în același fel pentru orice mașină, dar astfel apare și problema: din moment ce un procesor nu știe să execute decât setul lui de instrucțiuni, cum se face tranziția de la un program scris într-un limbaj de nivel înalt generic, la limbajul de asamblare? Există două soluții: interpretarea și compilarea.
Interpretarea
Interpretarea unui program se face folosind un alt program, numit interpretor. Acesta parsează codul sursă al programului pe care doriți să-l executați și îl transformă în timpul rulării în cod mașină. Avantajul acestui sistem este că există posibilitatea generării de program dinamic, la runtime, adică la momentul rulării acestuia. Un exemplu de limbaj interpretat este Javascript. Acesta acceptă construcții de forma:
eval("x=10;y=20;document.write(x*y)");
document.write("<br />" + eval("2+2"));
document.write("<br />" + eval(x+17));
Se vede faptul că funcția eval ia ca argument un șir de caractere care este construit dinamic, și apoi evaluat ca o expresie a limbajului. Acest lucru nu este posibil în cazul programelor compilate. Dezavantajul major al programelor interpretate este viteza redusă de execuție (în timpul rulării se face translația de la limbajul de nivel înalt la codul mașină).
Compilarea
Compilatorul este un program care are ca rol, traducerea unui limbaj în alt limbaj. În principiu, acesta este un program de traducere, dar nu între două limbi, ci între două limbaje formale. Diferența dintre limbă și limbaj formal este că acesta din urmă are un set de reguli stricte care fac traducerea riguroasă posibilă pentru un algoritm. Spre deosebire de interpretor, compilatorul face traducerea static, adică la ceea ce se numește compile-time, între limbajul de nivel înalt și limbajul de asamblare a unui procesor specific. Odată programul translatat în limbaj de asamblare, apoi în cod mașină cu ajutorul unui asamblor și al unui linker, acesta este rulat direct pe procesor, fără alte programe ajutătoare.
Mașina Virtuală Java (JVM)
Programele Java sunt compilate și apoi interpretate. Motivul pentru acest sistem este introducerea în flow-ul de execuție a unui strat suplimentar, numit Mașina Virtuală Java. După cum îi spune și numele, JVM este un procesor, dar nu unul real, fizic, realizat pe siliciu, ci un procesor virtual, simulat de procesorul gazdă. În esență, mașina virtuală este un alt program. Există două mari avantaje pentru utilizarea acestui concept:
- portabilitate - mașina virtuală Java are o specificație clară, și fiecare implementare de mașină virtuală este identică, indiferent pe ce procesor rulează; asta implică faptul că odată programul compilat pentru JVM, acesta va rula pe orice implementare, adică pe orice procesor gazdă și pe orice sistem de operare;
- securitate - layer-ul mașinii virtuale se comportă ca un sandbox, astfel încât execuția programului se reflectă în cea mai mare măsură în interiorul mașinii virtuale, și nu în mașina reală, oferind un grad ridicat de protecție.
În prima fază, programul inițial, care este stocat într-un fișier cu extensia .java, este compilat, folosind compilatorul Java (javac) și este generat fișierul executabil pentru JVM, care are extensia .class. Acest fișier este încărcat de către mașina virtuală (java) și este interpretat.
Particularitățile limbajului Java
Cu toate că sintaxa limbajului Java provine în cea mai mare măsură din C, există unele particularități, în special legate de modul de acces la memorie, care este fundamental diferit:
- în Java nu există pointeri, doar referințe; implicit, nu există aritmetica pointerilor;
- runtime checking - un sistem care verifică accesul la locațiile de memorie într-un vector și aruncă excepții atunci când se încearcă accesul în zone nepermise;
- garbage collection - programatorul nu trebuie să țină seama de memoria alocată, o zonă de memorie este eliberată în mod automat atunci când nu mai există referințe active către ea;
- distributed computing - Java pune la dispoziție în bibliotecile implicite clase care facilitează conectivitatea (java.net) și execuția distribuită (java.rmi);
- multithreading - Java pune la dispoziție în bibliotecile implicite clase care facilitează execuția concurentă a mai multor metode și sincronizarea acestora.
În plus față de aplicațiile de sine stătătoare (standalone), în Java există suport pentru un tip de aplicații numite applet-uri, care se execută în interiorul unui browser de web. Acest lucru facilitează dezvoltarea aplicațiilor interactive pe web.
Totuși, poate cel mai important avantaj al limbajului Java, este setul de clase puse la dispoziție de Oracle, numit generic Application Programming Interface, care conține o vastă colecție de funcții deja implementate, gata de a fi folosite pentru o gamă largă de aplicații.