Sunteți pe pagina 1din 0

17

1. COMPENDIU JAVA
Prezenta lucrare presupune c cititorul deine un nivel minimal de cuno-
tine despre programarea n limbajul Java. Exist deja suficient literatur
legat de programarea n Java [1, 5, 67, 4, 34].
n acest capitol venim n sprijinul "aducerii aminte" prin mai multe
exemple de programe Java. Vom prezenta mai nti cteva exemple simple.
Apoi facem un sumar al limbajului Java prin comparaii cu C++. Prezentm
apoi cteva aspecte Java legate de tratarea excepiilor i de interfee. Capitolul
se va ncheia cu alte cteva exemple simple de programe Java.
1.1. Primele exemple
Specificul Java ofer dou tipuri de programe:
aplicaii de sine stttoare, numite n terminologia Java standalone;
programe activabile prin intermediul navigatoarelor Web, numite
applet-uri.
1.1.1. Programul standalone Salut
Fiierul surs poart numele Salut.java i este prezentat n progra-
mul 1.1.

public class Salut{

public static void main(String a[]) {
System.out.println("Salut");
} // Salut.main

} // Salut
Programul 1.1. Salut.java

Mai nti cteva precizri, care reprezint de fapt i primele reguli Java.
Un program Java const din definirea i instanierea unei clase. Numele textului
surs este format din numele clasei urmat de sufixul .java. Unele programe
pot conine n acelai text surs mai multe clase, dar atunci numai una dintre ele
va fi vizibil n exterior, celelalte fiind numai de uz intern.

18
Un program standalone trebuie s conin metoda static main. Ea are
ca parametru un tablou avnd ca i elemente iruri de caractere. Fiecare element
al tabloului conine un argument transmis n linia de comand ce lanseaz
programul n execuie.
Tiprirea este executat de ctre metoda println a obiectului out din
clasa System.
Compilatorul Java poart numele de javac.
Lansarea compilrii programului se face cu comanda:
javac Salut.java
Rezultatul compilrii este depus n fiierul Salut.class, care
conine codul JVM echivalent.
Interpretorul standard Java poart numele java. El preia codul JVM din
Salut.class i-l execut (interpretativ).
Execuia interpretativ se lanseaz prin comanda:
java Salut
Ca efect, pe ecran se va afia, pe linie nou:
Salut
1.1.2. Applet-ul SalutAp
Exemplul din seciunea precedent, scris ca un applet, este prezentat n
programul 1.2. Textul surs conine i patru linii de comentarii, scrise ca n
C++.

import java.applet.*;
import java.awt.*;

public class SalutAp extends Applet {
public void paint(Graphics g) {
g.drawString("Salut",10,50);
} // SalutAp.paint
} // SalutAp
Programul 1.2. SalutAp.java

Mai nti se declar folosirea de metode ale pachetelor applet i awt.
Apoi se indic faptul c clasa SalutAp extinde (este o subclas pentru)
clasa Applet.

19
Scrierea textului se face prin intermediul metodei paint. Aceasta
realizeaz rescrierea metodei paint din java.awt.Component, avnd
rolul de a "picta" un obiect grafic g. Concret, este vorba de scrierea unui string
ncepnd de la pozitia (x= 10 pixeli spre dreapta, y = 50 pixeli n jos).
Compilarea sursei se face folosind aceeai comand de compilare:
javac SalutAp.java
care genereaz codul de octei echivalent sursei n fiierul SalutAp.class.
Pentru lansarea n execuie a acestui applet este nevoie de un navigator
Web: Netscape, Mozilla, Konqueror, InternetExplorer etc.
Aceste navigatoare opereaz peste o platform grafic oferit de ctre sistemul
de operare: Windows [100] (platformele Microsoft), respectiv X-window [58]
(platformele Unix). n funcie de platform, Pachetul Java ofer pentru testarea
applet-urilor, interpretorul appletviewer care este, de fapt, un navigator
Web specializat.
n textul surs HTML [59, 85] transmis navigatorului Web trebuie
inserat sursa din programul 1.3.

<APPLET code="SalutAp.class" width="500" height="100"> </APPLET>
Programul 1.3. SalutAp.html

Numele fiierului .java trebuie s coincid cu numele clasei, ns
numele fiierului HTML poate fi diferit (noi l-am luat acelai din comoditate).
Prin acest text, care este un tag HTML, se cere navigatorului s-i
ncarce codul JVM din fiierul SalutAp.class i s-l execute (interpre-
tativ).


Figura 1.1. Imaginea SalutAp prin Mozilla

20
n fig. 1.1 este prezentat rezultatul execuiei folosind navigatorul
Mozilla.
Dac se dorete utilizarea interpretorului standard Java appletviewer, se
va lansa comanda:
appletviewer SalutAp.html
Imaginea ferestrei este prezentat n fig. 1.2


Figura 1.2. Imaginea SalutAp prin appletviewer
1.1.3. Un program ce poate rula
alternativ standalone sau applet
Pare cel puin interesant s vedem un program care s poat rula, dup
preferin, ori ca aplicaie standalone ori ca applet. Unul dintre cele mai simple
programe de acest tip este programul 1.4.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class PrimCompus extends Applet {
public static void main(String a[]) {
PrimCompus oPrimCompus = new PrimCompus();
Frame oFrame = new Frame("Fereastra standalone");
WindowListener l=new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
oFrame.addWindowListener(l);
oFrame.setSize(250,350);
oFrame.add("Center", oPrimCompus);
oFrame.show();
oPrimCompus.init();
} // PrimCompus.main

21
public void init() {
} // PrimCompus.init

public void paint(Graphics g) {
g.drawString("Un sir in fereastra",50,60);
} // PrimCompus.paint

} // PrimCompus
Programul 1.4. PrimCompus.java

Clasa PrimCompus extinde clasa Applet spre a se putea comporta ca
i un applet. De asemenea, n cadrul ei se definete metoda main, care este
invocat la lansarea ca i aplicaie standalone.
S urmrim mai nti comportarea ca i applet. n momentul lansrii
dintr-un navigator, acesta (navigatorul) caut metoda init pe care o lanseaz
n execuie. n exemplul nostru metoda init este vid. n continuare (dup
cum am artat i la exemplul SalutAp), dac n cadrul clasei este definit
metoda paint, atunci se lanseaz n execuie aceasta. n cazul nostru va afia
un string n fereastr.
Pentru lansarea din navigator, este suficient ca documentul html s aib
coninutul din programul 1.5.

<html>
<title>Fereastra applet </title>
<Applet code="PrimCompus.class" width=250 height=350> </Applet>
</html>
Programul 1.5. PrimCompus.html

Spre a se deosebi de aplicaia standalone, am precizat i titlul ferestrei.
Execuia programului din Mozilla este ilustrat n fig. 1.3


Figura 1.3. Imaginea PrimCompus prin Mozilla

22
Pentru ca programul s poat fi rulat, cu (aproape) acelai efect, n cadrul
metodei main trebuie executate cteva aciuni, de altfel specifice interfeelor
grafice de tip standalone.
Mai nti am definit i construit obiectul oPrimCompus de tipul clasei.
Apoi am definit un obiect oFrame de tip Frame (tipul clasic de
fereastr din pachetul awt). Am fixat titlul acestei ferestre i dimensiunile ei (n
pixeli).
Am construit obiectul l, de tip WindowListener, definit printr-o clas
intern, anonim, de tip WindowsAdapter. Rolul acestui obiect este de a
intercepta evenimentul de apsare a butonului de distrugere a ferestrei i de a
termina apoi programul. (Ca rezultat al compilrii, din aceast clas anonim se
va crea fiierul PrimCompus$1.class)
Am adugat, n poziia central a obiectului oFrame obiectul
oPrimCompus i am cerut ferestrei s devin vizibil.
n sfrit, am lansat metoda init a obiectului oPrimCompus, dup
care comportarea va fi ca i la applet: va cuta metoda paint i va afia string-
ul n fereastr. Rezultatul execuiei va fi cel din fig. 1.4.


Figura 1.4. Imaginea PrimCompus ca aplicaie standalone
1.1.4. Acces la argumentele liniei de comand
Un program standalone const din una sau mai multe definiii de clase,
fiecare dintre acestea aflndu-se n propriul fiier *.class. Una dintre aceste
clase trebuie s conin metoda main().
Pentru a lansa programul, trebuie lansat interpretorul java cu numele
clasei care conine metoda main. Aceasta are prototipul:
public static void main ( String argv[] ) .
Interpretorul Java execut codul pn cnd metoda main execut un
apel System.exit sau pn la sfritul codului metodei (atingerea acoladei
de nchidere a metodei). Din acel moment, se ateapt terminarea tuturor

23
thread-urilor (firelor de execuie) care nc nu s-au terminat i apoi execuia se
termin.
n momentul lansrii n execuie, parametrii transmii prin linia de
comand sunt depui n vectorul de string-uri notat mai sus prin argv. De aici
utilizatorul le poate accesa. De exemplu, programul 1.6 afieaz toate aceste
argumente (tabloul de string-uri din linia de comand l-am notat cu a).

public class Echo {
public static void main(String a[]){
System.out.println("Urmeaza cele "+a.length+" argumente:");
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
} // Echo.main
} // Echo
Programul 1.6. Echo.java

Trebuie observate diferenele fa de C. n C, funcia main are dou
argumente, un ntreg i un tablou de pointeri, notate de obicei de obicei argc
argv, indicnd numrul de argumente i pointerii la string-urile transmise ca
argumente. n Java apare doar tabloul de string-uri, notat de obicei argv,
pentru c numrul de elemente este dat de argv.length, cmpul ce indic
pentru un obiect tablou numrul de elemente. Tot spre deosebire de C, dup
cum se poate vedea dac se ruleaz programul, numele comenzii nu este
considerat argument al liniei de comand.

Accesul la variabilele de mediu
Java nu permite accesul la variabilele de mediu ale sistemului de operare
sub care se ruleaz. Aceast interdicie este impus deoarece aceste
variabile depind de sistemul concret, deci nu asigur independena de
platform. Mediul Java ofer o modalitate proprie, independent de
platform, de a defini o list de proprieti sistem. Cititorul interesat
poate s consulte [44, 10] n acest scop.
1.2. Scurt prezentare a limbajului Java
1.2.1. Java comparat cu C i C++
Dup cum se tie, Java s-a nscut din C i C++. Este deci normal ca
aceste limbaje s aib trsturi comune, precum i diferene. Deoarece nu avem
n intenie o prezentare exhaustiv a limbajului Java, preferm o prezentare a sa
relativ la aceste limbaje. Lista similaritilor i a deosebirilor este actualizat

24
cu fiecare nou distribuie Java. De exemplu, lucrrile [44, 4] prezint aceste
elemente. Noi vom prezenta deosebirile i asemnrile n ipoteza c cititorul
cunoate, la un nivel minimal, limbajele C++ i (eventual) Java.
Java nu accept mecanismul typedef, nici noiunea de preprocesor. n
consecin, construciile #define, #if #include .a. nu sunt admise.
Dispare deci noiunea de fiier header. De asemenea, Java nu suport tipul de
date enum. n locul lui lui define, n Java se pot declara constante cu ajutorul
cuvntului cheie final. Aceste constante pot fi folosite ca nlocuitori pentru
tipul enum.
Ca i C++, Java opereaz cu tipul class, dar nu suport nici tipul
struct, nici union.
Programele standalone C++ cer o funcie numit main. Pe lng
aceasta, n programele C++ pot s apar numeroase alte funcii, att
independente, ct i funcii membre ale claselor (metode). n Java, funciile sunt
numai membre ale claselor (metode), deci nu exist funcii independente,
neaparinnd claselor. De asemenea, Java nu admite funcii globale i date
globale.
n Java, toate clasele sunt, n ultim instan, descendente din clasa
Object. n schimb, n C++ este posibil crearea unor arbori de clase fr nici
o legtur ntre ei.
Toate definiiile de funcii (metode) n Java sunt coninute n interiorul
claselor crora le aparin. n C++ este permis definirea lor n afara claselor. De
asemenea, n C++ este permis definirea explicit de funcii inline, n timp
ce n Java aceast opiune este lsat pe seama interpretorului JVM.
Att C++ ct i Java permit definirea de variabile i metode clas
(static), invocabile independent de existena sau nu a unor instanieri ale
clasei respective.
Java permite utilizarea conceptului interface. Prin intermediul ei se
pot defini prototipuri de metode i eventual declararea de constante. ntr-o
interfa nu sunt permise definirea de metode, nici declararea de variabile
membru. C++ nu suport conceptul de interfa. Att Java, ct i C++ admit
clase abstracte. Vom reveni asupra acestui concept.
Java nu permite motenirea multipl. ntr-o oarecare msur, utilizarea
interfeelor suplinete n Java aceast absen. Motenirea simpl este,
conceptual la fel n Java ca i n C++, ns n partea de implementare diferenele
sunt mari.
Java nu accept instruciunea goto, dei goto este cuvnt rezervat (dar
nefolosit)! n schimb, Java permite break i continue, att n forma
existent n C++, ct i extinderile break i continue etichetate. Acestea
din urm nu sunt suportate de C++. n forma simpl ele comand prsirea,
respectiv reiterarea celui mai interior corp al unui ciclu. Cele etichetate
acioneaz n acelai mod, dar asupra ciclurilor (mai exterioare) marcate printr-o

25
etichet. Aceste extinderi pentru break i continue permit nlocuirea, n
toate cazurile de structuri de control fireti, a instruciunii goto [16].
Java nu permite suprapunerea operatorilor. De asemenea, nu permite
conversia implicit (automat) de tip.
Spre deosebire de C++, Java are obiecte de tip String, obiecte
nemodificabile. Obiectele Java de tip StringBuffer permit i modificri,
precum i conversii facile ntre cele dou tipuri de string-uri.
Tablourile n Java sunt obiecte. ntr-un tablou Java, elementele lui sunt
indexate de la 0 la length-1. length este o variabil a unui obiect tablou,
indicnd lungimea maxim a domeniului de indexare. Elementele unui tablou
sunt (evident) toate de acelai tip, care poate fi orice, inclusiv un alt tablou.
Astfel se implementeaz tablourile multidimensionale. Java permite operaia de
atribuire la nivel de tablou. Dimensiunea unui tablou se fixeaz dinamic, nu
static ca n C++. Spre deosebire de C++, n Java se controleaz, la orice
invocare, limitele indicilor, evitndu-se astfel indexarea n afara domeniului.
Java nu permite operarea cu pointeri, implicit nu exist nici aritmetica
de pointeri. Automat, a disprut i echivalena dintre pointeri, nume de tablouri
etc. Natural, absena pointerilor implic absena operatorului de selecie din
pointer "->".
Operatorul rezoluie scope "::" din C++ nu este folosit n Java. Toate
seleciile se fac cu operatorul ".".
Pentru expresiile condiionale Java s-a introdus tipul boolean, inexistent
n C++. A disprut astfel statutul de TRUE pentru o valoare nenul i FALSE
pentru o valoare nul, aa cum stau lucrurile n C.
n ceea ce privete tipurile de date primitive, ele sunt aproape identice
cu cele din C. Vom reveni cu detalii ntr-o seciune ulterioar.
Operatorii sunt, practic cei din C. Operatorii pe bii acioneaz numai
asupra ntregilor. Operatorul >> face deplasarea la dreapta cu propagarea bitului
de semn, iar un nou operator, >>>, face aceeai deplasare cu completarea de
zerouri pentru biii eliberai. Singura suprapunere, implicit, este += ce poate
indica i concatenarea de string-uri.
Ct despre spaiile de nume: n Java orice variabil (cmp) i orice
metod este declarat numai n interiorul unei clase i face parte din structura
acesteia. De asemenea, fiecare clas face parte dintr-un pachet. Pachetele Java
sunt astzi cele care permit o mare dezvoltare i extindere a platformelor Java.
O colecie de clase nrudite, cu inta spre un anumit tip de prelucrri, constituie
n fapt o bibliotec ce poate fi integrat n orice aplicaie Java. Este suficient s
amintim aici c, dac la Java 1.0 ([10]) erau opt pachete standard, la Java 1.2
erau 58 [44] i numrul pachetelor, standard sau de aplicaie este n continu
cretere.
Accesul la nume se poate face:


26
implicit - ntre clasele aceluiai pachet;
declarat public - accesibil de oriunde;
declarat protected - accesibil din clas sau clasele subordonate;
declarate private - accesibil numai n interiorul clasei.
n C++ orice nume (variabil, constant, nume de funcie etc.) trebuie
mai nti declarat sau definit i abia apoi utilizat. n Java aceast restricie nu
mai exist.
Constructorii, att n Java ct i n C++ pot fi suprapui. n Java, toate
obiectele sunt transmise prin referin, eliminndu-se astfel constructorii de
copiere din C++. n Java nu exist destructori! Interpretorul JVM are un thread
specializat, care ruleaz n continuu (cu prioritatea cea mai mic), numit
garbage collector. Acesta face oficiile de destructor atunci cnd un obiect nu
mai este referit de nicieri.

Garbage collection
Obiectele Java i ocup memoria necesar n mod dinamic, n faza de
execuie. Alocarea de memorie este fcut automat, deci lipsesc apelurile
similare lui malloc. De asemenea, nu se face eliberarea explicit a
spaiului ocupat, deci nu exist apeluri similare lui free din C i C++.
Distrugerea obiectelor se face automat, printr-un mecanism clasic de
garbage collection [76, 17]. Eliberarea spaiului ocupat de un obiect se
face, fr tirea utilizatorului, dup ce obiectul nu mai este vizibil i nici
n via.

Funciile pot fi suprapuse, att n C++ ct i n Java. Spre deosebire de
C++, n Java nu sunt admii parametri cu valori implicite, nici funcii cu un
numr variabil de parametri. La fel ca i n C++, Java permite metode native.
Spre deosebire de C++, Java nu suport template, nici funcii generice.
Cuvntul virtual nu apare n Java. Toate metodele nestatice din Java sunt
legate dinamic, aa c virtual din C++ i pierde semnificaia.
Asupra tratrii excepiilor vom reveni.
Spre deosebire de C++, Java ofer o serie de structuri specializate,
numite containere de obiecte. Relevante n acest sens sunt containerele Vector
i Hashtable.
n fine, comentariile speciale /** */ sunt procesate prin javadoc
i permit elaborarea automat de documentaii.





27
1.2.2. Modificatorii static, final, syncronized i native
Modificatorul static
Poate preceda un cmp (variabil) sau o metod a unei clase, pentru a
specifica faptul c elementul respectiv este propriu clasei respective i c
el nu depinde de una sau alta dintre obiectele rezultate din instanierile
clasei respective. Deci cmpul (variabila) are aceeai valoare indiferent
de instaniere, iar metoda funcioneaz independent de instaniere. Un
element static poate fi accesat indiferent de faptul c exist sau nu o
instaniere a clasei respective.
De exemplu, variabila out din clasa System poate fi accesat chiar dac
nu exist o instaniere a acestei clase, motiv pentru care putem invoca
metoda println a lui: System.out.println("");

Modificatorul final
Ataat unei variabile sau unei metode indic faptul c elementul
respectiv este n ultima lui form. Din aceast cauz, nici variabila, nici
metoda final nu mai pot fi suprascrise n cadrul subclaselor derivate. O
variabil final se comport ca i o constant.

Modificatorul syncronized
Poate s caracterizeze o metod (exist i instruciunea syncronized
asupra creia vom reveni). Dac dou sau mai multe thread-uri invoc o
aceeai metod sincronizat pentru un acelai obiect, atunci doar unul
dintre ele o execut, celelalte ateapt ca acesta s i termine invocarea
ei, dup care un altul i pornete exclusiv execuia .a.m.d. Deci, dac
dou thread-uri solicit pentru acelai obiect a o metod sincronizat
met, adic ambele invoc a.met, atunci ele vor fi executate unul
dup cellalt. Dac ns exist dou obiecte diferite a i b, atunci dou
thread-uri pot s execute simultan apelurile a.met() b.met().

Modificatorul native
Indic faptul c metoda respectiv este descris ntr-un fiier extern
provenit dintr-o alt compilare. De exemplu dintr-o compilare C. Evi-
dent, acest gen de metode nu mai pstreaz independena de platform.





28
1.2.3. Cuvinte cheie
Java utilizeaz urmtoarele cuvinte cheie:

abstract boolean break byte case
catch char class const continue
default do double else extends
final finally float for goto
if implements import instanceof int
interface long native new null
package private protected public return
static short super switch synchronized
this throw throws transient try
void volatile while
1.2.4. Tipuri de date primitive
Unicode: codificarea i evitarea caracterelor
Java este unul dintre puinele limbajele de programare care ncalc un
principiu care prea statuat de facto: caracterele Java i string-urile sunt
codificate n codul Unicode pe 16 bii. Asta face ca setul de caractere s fie
potrivit i pentru alte caractere, neexistente n alfabetul englez. Setul Unicode
este efectiv un supraset al lui ASCII, deci textele ASCII au aceeai reprezentare,
dar fiecare octet ASCII este completat cu cte un octet semnificativ cu valoarea
0 (neinterpretat de mainile ce vd doar ASCII).
Cititorii care doresc s cunoasc ntregul set de caractere Unicode, pot
consulta http://unicode.org. Specificarea caracterelor ASCII tipribile
se face ca i n C. Mecanismul de evitare a caracterelor din C se pstreaz i se
mai introduce un mod suplimentar de specificare, astfel:

\uxxxx unde xxxx sunt patru cifre hexa;
\xxx unde xxx sunt trei cifre octale.
\n \r \t \f \b \ \ \\ sunt cele cunoscute din C.

Tipul char
Se reprezint pe doi octei n Unicode i respect conveniile de
conversie la ntregi din C.

String-urile
Se scriu ca i n C (ntre ghilimele). Spre deosebire de C, n Java nu
exist continuare (linie terminat cu \ n C sau C++) pentru string-urile
lungi. n schimb, operatorul + Java este extins i pentru concatenarea de

29
string-uri. Deci irurile lungi se scriu folosindu-se operatorul + de conca-
tenare. Exist tipul de date String.

Tipul Boolean
Este nou introdus n Java (nu este n C). n schimb dispare convenia C
cu 0 avnd valoarea false i diferit de 0 avnd valoarea true. Un tip
Boolean nu este un ntreg i nici nu poate fi convertit la acesta.

Tipurile ntregi
La tipurile ntregi, mprirea cu 0 activeaz excepia numit
ArithmeticException. Constantele ntregi lungi au dup irul de
cifre litera l sau L. Constantele octale ncep cu 0, iar cele hexazecimale
cu 0x sau 0X.

Tipurile flotante
Pentru tipurile flotante exist constantele predefinite:
POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN (Not a Number).
La tipurile flotante depirile nu se semnaleaz, ci rezultatul poate fi
unul dintre constantele de mai sus. Exist, de asemenea, zero negativ i
zero pozitiv. Constantele flotante se pot specifica plasnd la sfritul
scrierii numrului litera f sau F pentru simpl precizie, respectiv cu d
sau D pentru dubl precizie.
Tabelul urmtor descrie tipurile de date primitive.

Tip Coninut Valoare implicit Lungime
Boolean true sau false false 1 bit
Char caracter Unicode \u0000 16 bii
Byte ntreg cu semn 0 8 bii
Short ntreg cu semn 0 16 bii
Int ntreg cu semn 0 32 bii
Long ntreg cu semn 0 64 bii
Float standard IEEE simpl precizie 0.0 32 bii
Double standard IEEE dubl precizie 0.0 64 bii

30
1.2.5. Tipul referin obiect
Tipurile de date neprimitive sunt obiecte, n care includem i tablouri.
Ele sunt numite n Java tipuri referin, deoarece sunt manevrate prin adres:
compilatorul pune adresa unui obiect sau tablou ntr-o variabil i aa este
transmis ctre metode. Prin contrast, tipurile primitive sunt manevrate prin
valoare.
Deoarece obiectele sunt transmise prin referin, este posibil ca dou
variabile diferite s se refere la acelai obiect. De exemplu:

Button p, q;
p = new Button();
q = p;
p.setLabel(Ok);
String s = q.getLabel();

Aici, s va avea valoarea Ok.


int i = 3;
int j = i;
i = 2;

Aici, i este 2 i j este 3 (deci nu e valabil
acelai lucru la datele primitive!).


Copierea obiectelor i compararea lor
Din cauza referinei, atribuirea ntre obiecte nu face copiere. De
exemplu,

Button a = new Button(Ok);
Button b = new Button(Cancel);
a = b;

Aici, a i b puncteaz ambele la butonul Cancel, iar butonul Ok este
pierdut.
Pentru a se face o atribuire veritabil, trebuie executat o operaie de
copiere a componentelor de la surs la destinaie. Majoritatea tipurilor de date
standard au definit o metod clone(), care execut efectiv copierea, compo-
nent cu component. O astfel de atribuire funcioneaz ca n exemplul urmtor,
n care variabila c se va referi la un duplicat al obiectului b:
Vector b = new Vector;
c = b.clone();
Pentru copierea de tablouri, se folosete metoda:
System.arraycopy(sursa,inceput,destinatie,inceput,lungime)
Obiectele nu pot fi comparate nici mcar cu egalitate. Utilizatorul i
poate defini proceduri proprii de comparare. Unele clase au, n acest scop, o
metod numit equals().

31
Din raiuni de portabilitate, de independen de platform i de siguran,
nu exist pointeri! Deci, nu se pune problema referirii, dereferirii, conversiei
referinelor la tablouri n ntregi etc.
Constanta null indic inexistena unui obiect sau a unui tablou.
1.3. Tratarea excepiilor
O excepie Java este un obiect care descrie o condiie (situaie)
excepional ce are loc ntr-o secven de cod. Atunci cnd are loc o condiie
excepional Java creeaz un obiect reprezentnd eroarea i arunc excepia
metodei care a cauzat eroarea. Metoda poate s aleag ntre a prelua excepia
(i a o trata), sau a o ignora. n oricare din cazuri la un anumit moment excepia
este prins i tratat.
Excepiile pot fi generate de mediul de execuie Java, sau de pro-
gramator. Excepiile generate de Java se refer la erori fundamentale care
violeaz regulile limbajului sau ale mediului de execuie. Excepiile aruncate de
programator sunt folosite de regul pentru a raporta nesatisfacerea precon-
diiilor apelului unei metode. Pentru rezolvarea problemelor legate de excepii
sunt folosite cinci cuvinte rezervate: try, catch, throw, throws
i finally. Iat cum funcioneaz mecanismul:
secvena de instruciuni care este susceptibil de erori este pus ntr-
un bloc try; dac se genereaz o excepie, datorit execuiei
blocului de instruciuni, atunci Java creeaz un obiect excepie i l
arunc metodei (spre secvena respectiv);
dac dorim s prindem excepia, atunci folosim clauza catch,
imediat dup blocul try;
dac vrem s provocm (aruncm) o anumit excepie atunci folo-
sim throw; excepiile fundamentale sunt provocate automat de
ctre Java;
dac anumite instruciuni trebuie s fie executate nainte de a iei
(normal sau anormal) din metod, atunci punem instruciunile ntr-
un bloc finally;
n antetul de definire a unei metode, pentru a specifica c metoda
este posibil s arunce o excepie, trebuie specificat excepia
(excepiile) folosind o clauz throws
Forma general pentru manipularea excepiilor este:
try {
. . . // Bloc de instructiuni in care pot apare exceptii
}


32
catch (TipExceptie1 objExceptie1) {
. . . // Tratare exceptie TipExceptie1
}
catch (TipExceptie2 objExceptie2) {
. . . // Tratare exceptie TipExceptie2
}
. . . ...
finally {
. . // Bloc de instructiuni ce se executa
// inainte de a se incheia blocul try
}
Pentru comoditate, n multe dintre programele noastre de test evitm
folosirea lui try - catch adugnd la definirea lui main:
public static void main(String a[]) throws Exception {
Aceasta provoac tratarea automat a excepiilor de ctre JVM.
Tot pentru comoditate, spre a nu "ne bate capul" cu prea multe catch i
a inventaria toate excepiile posibile de aruncat dintr-un bloc try, plasm un
singur catch sub forma:
catch(Exception e) {
System.out.println(e.getMessage()); // eventual lipsete
e.printStackTrace();
System.exit(1); // eventual lipsete
}
Atragem ns atenia c n cadrul programelor reale trebuie tratat fiecare
excepie n parte n conformitate cu cerinele problemei de rezolvat! n caz
contrar pot aprea conflicte serioase la interfaa cu alte componente ale
aplicaiei! ntr-unul dintre capitolele urmtoare vom prezenta o aplicaie mai
mare n care vom aborda "cu sim de rspundere" tratarea excepiilor.
Aruncarea unei excepii se face prin:
new ExceptieAruncata (... );
Toate tipurile de excepii sunt subclase ale clasei
java.lang.Throwable cu dou subclase: java.lang.Exception i
java.lang.Error. Pentru fiecare eroare aprut se instaniaz un obiect al
uneia dintre cele dou subclase. Printre altele, fiecare obiect excepie conine un
string ce are ca valoare mesajul explicativ al excepiei sau erorii respective.
Excepiile generate (aruncate) prin program trebuie s fie de tip Exception.
Excepiile de tipul Error sunt generate de mediu i nu pot fi prinse de
program (de exemplu blocarea mediului Java datorit memoriei insuficiente).
O parte din ierarhia de excepii i erori este:

Throwable
Exception
IOException

33
FileNotFoundException
...
RuntimeError
ArithmeticException
IndexOutOfBoundsException
ArrayIndexOutOfBoundsException
StringIndexOutOfBoundsException
NullPointerException
...
...
Error
VirtualMachineError
...
1.3.1. Istanierea i distrugerea obiectelor. Constructori
Instanierea
Instanierea (crearea) unui obiect se face, dup cum am mai artat,
folosind new. Rutina care se execut n momentul instanierii poart numele de
constructor. Din punct de vedere formal, un constructor este o metod care:
poart acelai nume cu cel al clasei, nu se specific void la tipul ntors, i nu
conine return n interiorul corpului.
Dac nu se specific nici un constructor, atunci se generaz automat un
constructor vid, fr parametri.
E posibil s se defineasc mai muli constructori. Mai mult, unii pot s-i
foloseasc pe alii. Avem astfel de-a face cu o suprapunere (suprascriere) a
constructorilor.
n continuare exemplificm prin cteva variante de constructori pentru
clasa Cerc. La unele dintre ele vom folosi variabile locale - parametri i
cmpuri de date - cu aceleai nume, diferenierea dintre ele fcndu-se prin
cuvntul rezervat this.

public class Cerc {
public double x, y, r;
public Cerc (double x, double y, double r) // Centrul (x,y), raza r
{this.x = x; this.y = y; this.r = r;}
public Cerc (double r) // Centrul (0,0), raza r
{x = 0.0; y = 0.0;this.r = r;}
public Cerc (Cerc c) // Copiere a altui cerc
{x = c.x; y = c.y; r = c.r;}
public Cerc () // Centrul (0,0), raza 1
{x = 0.0; y = 0.0; r = 1.0;}
- - -
}

34
Singura restricie la constructorii multipli este aceea c orice doi cons-
tructori diferii trebuie s aib liste de parametri la care cel puin o pereche de
parametri corespunztori s difere. De exemplu, primul i al doilea constructor
difer prin parametrul al doilea, prezent doar la primul constructor; al doilea i
al treilea constructor au numai cte un parametru dar acetia sunt de tipuri
diferite .a.m.d.
Pentru a apela un constructor, n cadrul unui new numele clasei va avea
argumentele dorite, din care compilatorul va deduce despre care constructor este
vorba. De exemplu, urmtoarele linii au acelai efect:

Cerc c = new Cerc(); c.x = 1.0; c.r = 0.5;

Cerc c = new Cerc (1.0, 0.0, 0.5);
Cuvntul this poate s apar ntr-un constructor pentru a desemna un
alt constructor din aceeai clas. De exemplu, cei patru constructori de mai sus
se pot defini i astfel:

public class Cerc {
public double x, y, r;
public Cerc (double x, double y, double r) // Centrul (x,y), raza r
{this.x = x; this.y = y; this.r = r;}
public Cerc (double r) // Centrul (0,0), raza r
{this(0.0,0.0,r);}
public Cerc (Cerc c) // Copiere a altui cerc
{this(c.x,c.y,c.r);}
public Cerc () // Centrul (0,0), raza 1
{this(0.0,0.0,1.0);}
- - -
}

Singura restricie de folosire a lui this pe post de constructor ntr-un alt
constructor este aceea c apelul this trebuie s apar ca prim instruciune n
corpul noului constructor. Dup acest apel pot s urmeze i alte instruciuni.


Distrugerea obiectelor
Distrugerea obiectelor se face automat prin mecanismul de Garbage
Collection care este un thread (fir de execuie) de prioritate minim. El culege
zonele de memorie dup ce acestea nu mai sunt folosite i elibereaz spaiul
ocupat de ele. Aceasta este, dup prerea noastr, cea mai mare diferen de stil
de programare ntre Java i C sau C++. Urmeaz ca cititorii s se conving
singuri: va prea ciudat, cel puin la nceput, s nu gestionezi eliberarea spaiilor
de memorie!
Este ns posibil ca eliberarea de spaiu s se petreac uneori trziu.
Uneori (poate) este util forarea eliberrii mai rapide. Iat o posibil schem:


35
public static void main() {
int T = new int[100000];
- - -
calcule(T);
T = null; // Din acest moment, tabloul poate fi distrus
- - -
restul calculelor
- - -
}


Finalizator de obiecte
De multe ori, anumite obiecte sau resurse, cum ar fi spre exemplu,
descriptorii de fiiere i socket-urile, sunt pstrate indefinit. Pentru a fora
eliberarea acestora, se pot folosi metode finalizatori, dup modelul de mai jos.

protected void finalize() throws IOException
{ if (fd != null) close(); // fd este un descriptor }

Exist cteva reguli privitoare la finalizatori:
dac un obiect are o metod finalizator, atunci ea este invocat
nainte de Garbage Collection;
nu se garanteaz ordinea de intervenie a lui Garbage Collection, de
aceea nu se garanteaz momentele n care intr n lucru finaliza-
toarele;
dup finalizator, obiectul nu mai este disponibil!
de multe ori, finalizatorul se asociaz cu excepiile.
1.3.2. Definiri statice (clas):
variabile, metode, iniializatori
Variabile clas (statice)
Variabilele definite ntr-o clas au cte o copie pentru fiecare instaniere
a unui obiect. Exist ns situaii n care sunt necesare variabile proprii claselor,
ale cror valori nu depind de instaniere. Acestea vor fi numite variabile clas
sau variabile statice.


Metode clas (statice)
Analog cu variabilele clas, exist i metode clas, metode independente
de instaniere. n secvena de mai jos vom defini dou metode de comparare a
dou cercuri. Una va compara cercul curent cu un alt cerc, iar alta va compara

36
dou cercuri primite prin parametri. Evident, prima va fi dependent de
instaniere, dar a doua va fi independent de instaniere.

public class Cerc {

public double x, y, r;
- - -
public Cerc maxim (Cerc c)
{ if (c.r > r) return c; else return this;}

public static Cerc maxim (Cerc a, Cerc b)
{if (a.r > b.r) return a; else return b;}
- - -
}

Apelurile lor pot fi invocate astfel:

Cerc a = new Cerc (2.0);
Cerc b = new Cerc (3.0);
- - -
// Doua utilizari ale primei metode
Cerc c = a.maxim (b);
Cerc d = b.maxim (a);
- - -
// Utilizare a celei de-a doua metode
Cerc c = Cerc.maxim (a,b);
- - -

n funcie de context, programatorul va prefera una sau alta dintre
metodele maxim.
Precizm cteva caracteristici ale metodelor statice:
sunt declarate cu prefixul static;
sunt invocate din clase n loc de a fi invocate din instane;
n astfel de metode nu se folosete this ! (fapt normal, deoarece
this desemneaz instanierea curent).


Iniializatori statici
Att variabilele instan, ct i cele statice, pot fi iniializate, prin
mecanismele cunoscute din C i C++. De exemplu,
static int nr_cercuri = 0;
Java ofer posibilitatea de a face iniializri mai complexe. Acestea se
desemneaz prin construcia static{. . .}, unde ntre acolade poate s
apar o secven de instruciuni. Iat de exemplu cum se poate iniializa un
tablou cu valori ale funciilor trigonometrice, pentru a evita calcularea lor de
fiecare dat:


37
public class Cerc {
- - -
static private double[] sinus = new double[1000];
static private double[] cosinus = new double[1000];
- - -
static {
double x, deltax;
int i;
deltax = (Math.PI / 2) / (1000-1);
for (i=0, x=0.0; i<1000; i++, x+=deltax) {
sinus[i] = Math.sin(x);
cosinus[i] = Math.cos(x);
}
- - -
}
1.4. Interfee Java
Interfeele Java abstractizeaz complet metodele unei clase (interfaa
clasei) fa de orice implementare. Folosind cuvntul rezervat interface (n
loc de class) specificm ce poate face o clas i nu cum realizeaz clasa acel
lucru.
1.4.1. Definirea unei interfee
Forma general a definirii unei interfee Java este

interface nume {
tipRezultat1 numeMetoda1(listaParametri1);
- - -
tipRezultatn numeMetodan(listaParametrin);

tipVariabilaFinala1 numeVariabilaFinala1 = valoare1;
- - -
tipVariabilaFinalak numeVariabilaFinalak = valoarek;
}
1.4.2. Implementarea interfeelor
Odat ce o interfa a fost definit, una sau mai multe clase pot s ofere o
implementare a interfeei. Pentru a implementa o interfa, o clas trebuie s
includ cuvntul rezervat implements n antetul definiiei sale:

class NumeClasa
[ extends ClasaSuperioara ]
implements numeInterfata1 [ , numeInterfata2 . . .] {


38
dup care s defineasc toate metodele declarate de interfa. De asemenea, se
impune ca toate metodele interfeelor s fie declarate public. n consecin,
clasele care implementeaz interfaa trebuie s fie declarate public.
1.4.3. Apelul metodelor prin
variabile referine la interfee
Deoarece metodele unei interfee sunt implementate de o clas, evident
c le putem apela prin variabile referin la clasa care implementeaz interfaa.
Java trateaz interfeele ca i clase pur abstracte. Astfel,
putem s definim variabile de tip interfa (referine la interfa);
o variabil interfa poate referi o instan a unei clase ce imple-
menteaz interfaa;
dac o variabil interfa refer o instan care implementeaz inter-
faa atunci la apelul unei metode din interfa se va apela metoda
instanei (apel conform obiectului referit i nu conform referinei - ca
i la redefinirea metodelor n cazul motenirii).
1.5. Exemple de programe Java
n cele ce urmeaz prezentm cteva aplicaii standalone scrise n Java
prin care exemplificm cele prezentate mai sus.
1.5.1. Calcule aritmetice simple
1.5.1.1. Distana ntre dou puncte
Se cere determinarea distanei euclidiene dintre dou puncte ale cror
coordonate se dau n linia de comand sub forma a patru numere. Sursa este
dat prin programul 1.7.

public class Distanta {

public static void main(String a[]) throws Exception {
// Determina distanta intre punctele de coordonate (a[0],a[1]), (a[2],a[3])
double x1 = Double.parseDouble(a[0]);
double y1 = Double.parseDouble(a[1]);
double x2 = Double.parseDouble(a[2]);
double y2 = Double.parseDouble(a[3]);
System.out.println("Distanta este: "+ // Afiseaza distanta
Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)));

39
} // Distanta.main

} // Distanta
Programul 1.7. Distanta.java
1.5.1.2. Calculul unor medii ponderate
Se cere un program care calculeaz succesiuni de medii ponderate ale
unor note. Ponderile sunt date ca i argumente n linia de comand. Notele sunt
cerute pe rnd de la intrarea standard. Sursa este dat n programul 1.8

import java.io.*;

public class MediiPonderate {

public static void main(String a[]) throws Exception {
int i;
String s;
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
double[] p = new double [a.length];
double[] n = new double [a.length];
double medie, total;
for (i=0, total=0; i<a.length; i++) {
p[i] = Double.parseDouble(a[i]);
total += p[i];
} // for
for (;; ) {
for (i=0, medie=0; i<a.length;i++) {
System.out.print("Nota "+(i+1)+": ");
s = in.readLine();
if (s == null)
System.exit(0);
medie += (p[i]*Double.parseDouble(s));
} // for
medie /= total;
System.out.println("Media: "+medie);
} // for
} // MediiPonderate.main

} // MediiPonderate
Programul 1.8. MediiPonderate.java


40

Figura 1.5. Utilizarea MediiPonderate

n fig. 1.5 este prezentat un exemplu de utilizare a programului, pentru
medii ponderate cu ponderile 5, 7.5, 2.5 i 5. (Altfel spus, prima i ultima not
conteaz la fel i mpreun ct celelalte dou; nota a doua mai mult, a treia mai
puin ...):
Dac din greeal la lansarea programului de mai sus nu se dau ponderi
n linia de comand n momentul lansrii, atunci programul va intra n ciclu
infinit!
1.5.2. Generarea de elemente aleatoare
1.5.2.1. Generarea de parole
n administrarea utilizatorilor din reele este necesar o rezerv de
parole cu care s opereze administratorii. Programul care urmeaz genereaz
aleator 2000 parole de cte 8 caractere, litere mari, litere mici i cifre zecimale.
Sursa este dat n programul 1.9.

import java.io.*;
import java.util.*;

public class GenPasswd {

public static void main(String a[]) {
String car = "abcdefghijklmnopqrstuvwxyz"+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
"0123456789"; // Alfabetul
StringBuffer lin = new StringBuffer(" "); // Spatiu pentru
// o parola
Random r = new Random(); // Obiect numar aleator
for (int n=0; n<2000; n++) {
for(int i=0; i<8; i++)
lin.setCharAt(i,
car.charAt(

41
Math.abs(r.nextInt())%car.length())); // Genereaza un caracter
System.out.println(lin); // Tipareste o parola
} // for: cele 2000 parole generate
} // GenPasswd.main

} // GenPasswd
Programul 1.9. GenPasswd.java
1.5.2.2. Generarea de expresii booleene
Pentru o culegere de probleme a fost necesar scrierea unor expresii
booleene. Acestea trebuie simplificate i s se construiasc circuitele combina-
ionale echivalente. Autorii au decis generarea aleatoare a unui anumit numr de
variabile, a unui numr oarecare de termeni conjunctivi i o manier aleatoare
de negare a variabilelor. Programul 1.10 face acest lucru.

import java.io.*;
import java.util.*;

public class GenExpr {
public static void main(String a[]) {
String var="abcde"; // Variabilele
String neg=" -"; // Negare sau nu
String s;
int v, n, t, i, j, k;
Random r = new Random(); // Obiectul numar aleator
for (i=0; i<20; i++) {
v = 3 + Math.abs(r.nextInt())%3; // Numar de variabile
t = 4 + Math.abs(r.nextInt())%8; // Numar de termeni conjunctivi
for (s = "f(",k=0; k<v; k++) {
s += var.substring(k,k+1);
s += (k<v-1)?",":") = ";
} // for: Partea stanga a definirii functiei
for(j=0; j<t; j++) {
for (k=0; k<v; k++) {
n = Math.abs(r.nextInt())%2; // Alege negare sau nu
s +=neg.substring(n,n+1)+var.substring(k,k+1);
// Lipeste variabila negata sau nu
} // for: generat un termen conjunctiv
if (j < t-1)
s += " V "; // Pune operatorul SAU
} // for: Expresia booleeana
System.out.println(s); // Tipareste expresia generata
} // for: cele 20 expresii
} // GenExpr.main
} // GenExpr
Programul 1.10. GenExpr.java

42
Iat, n fig. 1.6, cum arat rezultatul execuiei acestui program.


Figura 1.6. Generarea unor expresii booleene
1.5.3. Ordonare linii
Programul 1.11 prezint un exemplu simplu de operare cu string-uri. Se
citete de la intrarea standard o succesiune de linii. Programul reine aceste linii
i apoi le afieaz n ordine alfabetic a coninutului lor. Terminarea transmiterii
liniilor de la intrarea standard trebuie marcat prin CTRL/Z (cazul Windows),
respectiv CTRL/D (cazul Unix), pentru a marca sfritul fiierului de intrare
standard.

import java.io.*;
import java.util.*;

public class Linii {

public static void main(String a[]) {
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
String s, d; // String-uri de serviciu
Vector ts = new Vector(); // Tabloul de stringuri
int n;
for(n=0; ; ) { // Citeste linie cu linie si adauga la ts
s=null;
try {
s = in.readLine();
} // try
catch (IOException e) {
e.printStackTrace();
} // catch
if (s==null)
break; // S-a tastat sfarsitul intrarii
ts.add(s);
n++;
} // for
for(int i=0; i<n-1; i++){ // Ordoneaza tabloul

43
for(int j=i+1; j<n; j++) {
d=(String)ts.elementAt(j);
s=(String)ts.elementAt(i);
if (s.compareTo(d) > 0) {
ts.set(i, d);
ts.set(j, s);
} // if
} // for j
} // for i
System.out.println("\nLiniile ordonate lexicografic:\n");
for (int i=0; i<n;i++){
s=(String)ts.elementAt(i);
System.out.println(s); // Afiseaza liniile
} // for
} // Linii.main

} // Linii
Programul 1.11. Linii.java

Iat, n fig. 1.7 o mostr de execuie a acestui program:


Figura 1.7. Ordonarea liniilor
1.6. Thread-uri Java
n prezent, tendinele n programarea concurent utilizeaz n loc de
proces conceptul de thread [3, 6, 14]. Pachetul java.lang ofer clasa
Thread. Aceasta, mpreun cu unele metode motenite de la clasa Object,
permit crearea, execuia, controlul i sincronizarea thread-urilor. n particular,

44
sincronizarea se bazeaz pe conceptul de monitor. Este cunoscut faptul c
operarea multithreading d mult btaie de cap programatorilor C i C++.
Programatorii trebuie s-i implementeze mecanisme proprii de blocare a unor
seciuni critice i de partajare a unor resurse critice. Primitivele furnizate de
Java reduc esenial acest efort.
1.6.1. Elemente de limbaj Java n contextul thread-urilor
Utilizarea thread-urilor Java este deja bine cunoscut n literatur [14,
32]. Avnd n vedere faptul c ne vom referi frecvent la o serie de metode
specifice lucrului cu thread-uri, considerm oportun o trecere n revist a
acestora. Pentru detalii se poate consulta [14].
1.6.1.1. Obiecte versus thread-uri
Avnd n vedere importana conceptului de thread, prezentm pe scurt
metodele din clasa Object care se refer la thread-uri. Reinem din clas doar
ceea ce, ntr-un fel sau altul, poate fi util n context multithreading. Prototipurile
metodelor se gsesc n documentaiile standard [91].

Metodele wait()
Pun obiectul n ateptare pn la apariia unui eveniment. Ultimele dou
forme indic o durat maxim de ateptare, fie numai n
milisecunde, fie n milisecunde plus nanosecunde.

Metodele notify() i notifyAll()
Sunt duale metodelor wait(), ele anun alte obiecte apariia unui
eveniment.

Metoda getClass()
ntoarce clasa din care s-a instaniat obiectul apelant al metodei.

Metoda equals()
Ofer, prin suprascriere n subclase, posibilitatea de a se defini ce
nseamn egalitatea a dou obiecte din clasa respectiv. Implementarea
acestei metode trebuie s respecte, pentru orice referiri nenule x, y,
z, urmtoarele condiii:
reflexivitate, adic x.equals(x) trebuie s ntoarc true;

45
simetrie, adic x.equals(y) este true dac i numai dac
y.equals(x) este true;
tranzitivitate, adic x.equals(y) este true i y.equals(z) este
true implic x.equals(z) este true;
consisten, adic datele utilizate n metoda equals s nu modifice
relaia ntre dou obiecte; deci, pentru dou obiecte x i y, apelurile
multiple x.equals(y) trebuie s ntoarc mereu fie true, fie
false;
referina null: x.equals(null) s fie mereu false.

Metoda clone()
Creeaz o copie a obiectului. nelesul exact al copiei depinde de clas.
n general urmtoarele condiii sunt adevrate:
x.clone() != x este true;
x.clone90.getClass() == x.getClass() este true;
x.clone().equals(x) este true.

Sunt extrem de rare cazurile n care apar mici abateri de la aceste reguli.
Este vorba de situaiile n care suprascrierea lui clone realizeaz o
copiere superficial.

Metoda finalize()
Poate fi suprascris n subclase i ea conine aciunile pe care compo-
nenta garbage collection din JVM le va executa imediat nainte de a
distruge un obiect. Trebuie remarcat faptul c programul utilizator nu
poate stabili cu exactitate momentul i ordinea de execuie a metodelor
finalize legate de obiecte expirate.

Metoda toString()
ntoarce reprezentarea textual a obiectului. Este util uneori n activi-
tatea de depanare. Se recomand suprascrierea ei dac se intenioneaz a
fi utilizat.
1.6.1.2. Clasa Thread
n acelai stil ca i n seciunea precedent, prezentm principalele
metode ale clasei Thread.
Dac se specific n constructor un obiect tinta , atunci corpul thread-
ului (corpul metodei run) este ataat acestui obiect. Dac nu se specific,

46
atunci corpul este ataat thread-ului nou creat. Prin constructor, sau mai trziu
folosind metoda setName(), se poate atribui thread-ului un nume. Dac nu se
specific alt valoare, atunci numele implicit va fi Thread-+n, unde n este
un ntreg. Metoda getName() ntoarce numele curent al thread-ului.

Metoda start()
Lanseaz n execuie noul thread. Din acest moment, execuia progra-
mului este controlat de (cel puin) dou thread-uri: pe de o parte
funcioneaz thread-ul curent - cel care execut start(), iar pe de alt
parte se lanseaz n execuie noul thread, ale crui instruciuni sunt
precizate n metoda run().

Metoda run
Conine corpul efectiv al thread-ului. ntreaga activitate curent a noului
thread trebuie descris prin suprascrierea acestei metode.

Metodele sleep()
Pun thread-ul curent n ateptare un anumit interval de timp.

Metodele join()
Ateapt ca obiectul thread care le apeleaz s moar. Ultimele dou
forme limiteaz timpul maxim de ateptare.

Metoda yield()
Cedeaz controlul de la obiectul thread la planificatorul JVM, pentru a
permite unui alt thread (green) s ruleze.

Metoda interrupt()
Trimite o ntrerupere obiectului thread care o invoc.

Metodele interrupted() i isInterrupted()
Testeaz dac thread-ul apelant a fost ntrerupt sau nu. Metoda
interrupted() modific statutul de ntrerupt, aa c la un dublu apel
al ei starea thread-ului revine la vechea ei form. Metoda
isInterrupted nu modific aceast stare.

Metoda isAlive()
Rspunde dac obiectul thread apelant este n via sau nu.

47
Metoda activeCount()
ntoarce numrul de thread-uri active din grupul curent. Metoda
currentThread() ntoarce numrul thread-ului curent. Metoda
enumerate() ntoarce n tabloul t thread-urile membre ale grupului
curent i ale celor din subgrupuri. Metoda getThreadGroup()
ntoarce grupul curent de thread-uri. Metoda dumpStack() afieaz la
ieirea standard stiva curent de thread-uri.

Metodele stop(), suspend() i resume()
Au fost definite n primele versiuni Java. Ulterior s-a dovedit c folosirea
lor poate conduce, n cazul unei proiectri neatente a programului, la
impas i din aceast cauz ncepnd cu versiunea 1.2 au fost declarate
deprecated, motiv pentru care nici noi nu le vom acorda prea mare
atenie. Metoda stop() provoac oprirea execuiei unui thread. Metoda
suspend() suspend temporar execuia thread-ului, reluarea i conti-
nuarea execuiei fcndu-se cu metoda resume().
1.6.2. Operaii asupra thread-urilor Java;
creare, terminare
1.6.2.1. Crearea unui thread
Crearea unui thread folosind Java API se poate face n dou moduri:

implementnd o clas derivat din clasa predefinit Thread, clas
care face parte din pachetul java.lang i ca urmare este importat
automat n orice program Java;
definind o clas care implementeaz interfaa Runnable.

Primul dintre ele const n a declara o clas ca subclas a clasei
Thread. n interiorul acesteia se redefinete metoda run(), metod care
conine corpul de instruciuni ale thread-ului. Dup aceea, se poate defini i
instania noua subclas. Schematic, crearea se face conform modelului de mai
jos.

class ThreadPropriu extend Thread {
// - - - datele subclasei - - -
ThreadPropriu ( /* parametrii constructorului */ ) {
// - - - descrierea constructorului
}
public void run() {
// - - - defineste corpul thread-ului ThreadPropriu - - -
}

48
}

A doua metod const n implementarea clasei Runnable. Aceast
interfa conine o unic metod, i anume metoda run:

interface Runnable {
public void run ();
}

Astfel, o clas care implementeaz interfaa Runnable, evit descen-
dena din clasa standard Thread. Instanele acestei clase sunt create ca obiecte
active, n thread-uri diferite de thread-ul curent. Schematic, acest mod de creare
a unui thread apare aproape ca mai sus, cu excepia primei linii:

class ThreadPropriu - - - implements Runnable {
// - - - datele subclasei - - -
ThreadPropriu ( /* parametrii constructorului */ ) {
// - - - descrierea constructorului
}
public void run() {
// - - - defineste corpul thread-ului ThreadPropriu - - -
}
}

Dup definirea clasei ThreadPropriu, indiferent de modalitate,
urmeaz crearea thread-ului i lansarea lui n execuie:

ThreadPropriu thr = new ThreadPropriu(- - -);
thr.start();

Mai nti se creeaz obiectul thread, dup care se lanseaz metoda
start() pentru efectuarea iniializrilor.
Execuia curent a unui thread const n execuia metodei run(),
similar din acest punct de vedere cu funcia main() a unui program
standalone. Spre deosebire de main(), metoda run() nu primete argumente
din linia de comand. Eventualii parametri pot fi transmii thread-ului prin
constructor, variabile statice sau prin alte alte metode stabilite de programator.
1.6.2.2. Terminarea unui thread
JVM execut un thread, precum i pe cele pe care acesta le creeaz, pn
cnd apare una dintre urmtoarele situaii:

Este apelat metoda exit() a clasei Runtime, iar managerul de
securitate a permis ndeplinirea cu succes a acestui apel.
Toate thread-urile care nu sunt daemon s-au terminat, fie prin
ntoarcerea din apelul metodei run(), fie printr-un apel al metodei

49
stop() din partea altui thread, fie prin trimiterea unei ntreruperi
(interrupt()) din partea altui thread.
S-a invocat metoda stop() a obiectului thread (metod depit).
La terminarea unui thread, resursele specifice acestuia sunt eliberate.
Obiectul thread nu va fi ters din memorie de ctre garbage collector dect la
dereferenierea manual a instanei (atribuirea valorii null pentru referin)
sau la terminarea programului.
1.6.2.3. Ateptarea terminrii unui thread
Dac se dorete ateptarea terminrii unui thread, se poate folosi metoda
join() a obiectului thread dup care se ateapt. Thread-ul a crui terminare
se ateapt nu este afectat de acest apel. Funcia join() are acelai efect ca i
combinaia de metode sleep() i isAlive().
Apelul this.join() nseamn wait forever pentru c thread-ul
curent nu se va termina niciodat datorit acestui apel de ateptare.
Funcia join() apelat pentru un thread, care nu i-a nceput execuia
sau s-a terminat, returneaz fr s atepte.
1.6.3. Sincronizarea thread-urilor Java
1.6.3.1. Conceptul de monitor Java; synchronized
Mecanismele de sincronizare ale thread-urilor Java au la baz conceptul
de monitor (vezi [14]). Obiectele monitor aplic principiul excluderii mutuale
pentru grupul de proceduri sincronizate. Excluderea mutual la datele partajate
se obine prin accesul serializat al thread-urilor: "un thread odat".
Limbajul Java a implementat noiunea de monitor ca un element asociat
fiecrui obiect Java. Utilizarea direct a monitoarelor este permis prin
intermediul cuvntului rezervat synchronized aplicat funciilor membre sau
unor seciuni de cod din interiorul metodelor.
Ca urmare, pentru a proteja o seciune critic, se poate declara sincro-
nizat a) o metod complet, sau b) un bloc (o secven de instruciuni) dintr-o
metod. n prima situaie, mecanismul de sincronizare este asociat obiectului
curent (mai corect spus, monitorului acestuia) iar n al doilea caz, se poate alege
obiectul de sincronizare, de exemplu, un obiect declarat static n clasa curent
sau din nou, obiectul curent. Ca regul, nu se alege ca obiect de sincronizare un
obiect a crui valoare se modific n interiorul blocului. Deci, pentru un obiect,
statutul de monitor se poate obine fie pe ntreaga durat a execuiei unei meto-
de, fie pe durata execuiei unei anumite secvene de instruciuni.

50
Schematic, aplicarea declaraiilor synchronized se face dup una din
urmtoarele dou scheme:

public - - - synchronized - - - numeMetoda ( ){ - - - }
sau
synchronized (obiect) { bloc (secven de instruciuni) }

n prima situaie, un apel obiect.numemetoda() face ca obiect
s primeasc statutul de monitor. Deci orice apel obiect.altaMetoda(),
unde altaMetoda este i ea sincronizat, va rmne n starea de ateptare a
exclusivitii pn cnd apelul obiect.numemetoda() i ncheie activi-
tatea.
n a doua situaie, se confer obiectului obiect statutul de monitor
pn la terminarea secvenei de instruciuni specificat ntre acoladele instruc-
iunii synchronized. Trebuie remarcat faptul c obiectul argument al ins-
truciunii synchronized nu este obligatoriu s coincid cu obiectul curent.
n legtur cu metodele/seciunile de program sincronizate trebuie fcute
urmtoarele precizri:
Cnd este apelat o procedur sincronizat (care conine atributul
synchronized) pentru un obiect, se verific monitorul asociat obiectului.
Dac exist alte metode sincronizate care se execut, prima metod se va bloca,
pn la terminarea lor. Deci se pot executa n paralel: o singura metod sincro-
nizat cu mai multe metode nesincronizate


Metode sincronizate statice
n cazurile precedente de sincronizare, am precizat c acest mecanism
este posibil prin obinerea monitorului asociat obiectului curent de
sincronizare. Metodele statice nu sunt particulare unei anumite instane a
clasei curente, motiv pentru care la sincronizarea acestora se folosete un
obiect denumit class lock. i n acest caz, sistemul este destul de
inteligent ca s suporte blocri imbricate, deci dac o metod static
sincronizat este apelat din interiorul altei metode statice sincronizate,
nu mai este cerut obiectul class lock asociat.
1.6.3.2. Mecanismul wait/notify
Un thread care are exclusivitatea asupra unui obiect cu statut de monitor
poate ceda temporar exclusivitatea. Aceast cedare temporar se face apelnd
metoda wait(). Ca efect, este cedat exclusivitatea asupra obiectului, iar
thread-ul curent i oprete temporar execuia instruciunilor lui, adic trece n
starea Waiting.

51
Reluarea exclusivitii cedate de ctre un thread care a executat un wait
are loc atunci cnd thread-ul respectiv se trezete ca urmare a receptrii unui
anun trimis de ctre un alt thread activ care execut una dintre metodele
notify() sau notifyAll(). n urma acestui eveniment, thread-ul i
recapt exclusivitatea cedat anterior i i continu execuia instruciunilor de
unde i-a oprit-o anterior (dup apelul wait()).
Anunul efectuat prin notify() se adreseaz tuturor thread-urilor care
sunt n starea Waiting, dar numai unul dintre ele i va relua activitatea, celelalte
vor rmne n continuare n starea Waiting. n schimb, anunul efectuat prin
notifyAll() este recepionat de ctre toate thread-urile aflate n starea
Waiting. n consecin toate thread-urile ies din aceast stare i i continu
activitatea.
Este posibil ca un thread s solicite intrarea n starea Waiting doar pentru
un interval limitat de timp. n acest caz el va specifica n apelul wait durata
maxim pe care o admite.
De asemenea, un thread poate iei din starea Waiting dac un alt thread
apeleaz metoda interrupt() a thread-ului aflat n starea Waiting. n acest
caz execuia lui se reia cu secvena catch ce intercepteaz ntreruperea.
n sumar, prezentm scenariul de comunicare ntre thread-uri, folosind
funciile wait i notify:

1. Un thread are nevoie n timpul execuiei de o condiie despre care
presupune c va fi realizat n alt thread.
2. Primul thread ateapt realizarea condiiei cu ajutorul metodei
wait(), oferind astfel fiecrui thread suport pentru acest meca-
nism de comunicare.
3. Thread-ul care realizeaz condiia n timpul execuiei, anun acest
lucru unui thread care ateapt, prin apelul funciei notify().

Metodele wait() i notify() trebuie apelate din interiorul unei
metode sau bloc sincronizat, pentru a preveni eventuale rezultate incorecte,
generate de lipsa sincronizrii. nainte de a intra n ateptare folosind wait(),
thread-ul curent elibereaz obiectul de sincronizare blocat i-l obine din nou
cnd thread-ul este anunat c a fost realizat condiia ateptat.
Metodele wait() i notify() sunt metode native, scrise n C i nu
este posibil reimplementarea lor folosind numai limbajul Java.
Mai facem cteva precizri n legtur cu comportarea mecanismului
wait/notify:
Dac notify() este apelat dintr-un thread, dar nu este nici un
thread care s atepte, atunci metoda notify() returneaz fr nici
o eroare.

52
Funcia wait() elibereaz obiectul de sincronizare la intrarea n
ateptare i l reobine la recepionarea unei notificri. Sistemul
asigur atomicitatea acestor operaii critice.
Dac exist mai multe thread-uri care ateapt o anumit condiie, nu
se poate tii care thread primete notificarea dup apelul funciei
notify(). Acest lucru depinde de JVM i de mecansimul de
planificare a thread-urilor.
Dac se dorete apelul funciilor wait() i notify() din metode
statice, atunci se declar n interiorul clasei un obiect de sincronizare
static, iar funciile wait() i notify() se vor apela pentru acest
obiect static.
Diferena esenial dintre funciile wait i sleep const n faptul c
metoda sleep nu este obligatoriu s fie apelat dintr-un bloc sincronizat i nu
implic blocarea sau deblocarea unui obiect de sincronizare.
1.6.3.3. O schem exemplu de sincronizri
n cele ce urmeaz, pentru a exemplifica utilizarea synchronized,
wait(), notify(), notifyAll(), prezentm schematic prile eseniale
ale unei clase Bd care poate fi accesat n regim de cititor/scriitor [14].

class Bd {
static int cititori = 0;
- - - - - - - - - - - -
public void citeste ( - - - ){
- - -
synchronized (this) {
cititori++;
}
- - - // citirea propriuzisa
synchronized (this) {
cititori--;
notify();
}
}
public synchronized void scrie( - - - ) {
while (cititori > 0) {
- - - - - - - -
try { wait(); }
catch (InterruptedException e) { - - - }
}
- - - // scrierea propriu-zisa
notifyAll();
}


53
Partea esenial pentru sincronizare const din definirea variabilei
cititori i a metodelor citeste i scrie.
Variabila clas cititori reine de fiecare dat ci cititori sunt activi
la un moment dat. Dup cum se poate observa, instana curent a clasei Bd este
blocat (pus n regim de monitor) pe parcursul aciunilor asupra variabilei
cititori. Aceste aciuni sunt efectuate numai n interiorul metodelor scrie
i citeste.
Metoda citeste incrementeaz (n regim monitor) numrul de cititori.
Apoi, posibil concurent cu ali cititori, i efectueaz activitatea, care aici const
doar n afiarea strii curente. La terminarea acestei activiti, n regim monitor
decrementeaz i anun thread-urile atepttoare. Acestea din urm sunt, cu
siguran, numai scriitori.
Metoda scrie este declarat synchronized (regim monitor), deoa-
rece ntreaga ei activitate se desfoar fr ca celelalte procese s acioneze
asupra Bd.
1.6.4. Un exemplu de multithreading:
alinierea cuvintelor ntr-un fiier text
Enunul problemei este simplu:
Se cere rearanjarea paragrafelor dintr-un text aa nct toate liniile, cu
excepia ultimei din paragraf, s aib exact aceeai lungime, iar cuvintele
s fie dispuse (ct mai) echidistant n linie.
Abordm problema multithreading, n sensul urmtor. Se definete un
recipient de cuvinte, care s funcioneze dup disciplina FIFO i s se
sincronizeze ca i buffer-ul de la problema productorului i a consumatorului
[14]. Programul este descris cu ajutorul a patru clase:
RecipientCuvinte, care nmagazineaz un numr limitat de
cuvinte i le livreaz la cerere;
ProductorCuvinte, este un thread care citete textul de
reformatat de la intrarea standard i l depune n
RecipientCuvinte;
ConsumatorCuvinte, este un thread care extrage pe rnd cuvinte din
RecipientCuvinte, le pune n linii i distaneaz uniform
cuvintele ntre ele;
AliniereCuvinte, care este programul principal.

Vom prezenta pe scurt fiecare dintre clase.

54
1.6.4.1. Clasa RecipientCuvinte
Clasa RecipientCuvinte folosete un Vector pentru a memora
maximum RECIPIENT cuvinte. Constructorul primete i reine valoarea
RECIPIENT. (Se tie c tipul Vector nu impune limitri asupra numrului de
obiecte din el. Noi am introdus aceast limitare numai pentru a rmne n
condiiile problemei clasice a productorului i a consumatorului.)
Metoda get, asigur, n regim de monitor, livrarea urmtorului cuvnt
din recipient. Dac nu are cuvnt de livrat, atunci thread-ul solicitant este pus n
ateptare pn cnd productorul livreaz (cel puin) un cuvnt.
Metoda put, asigur, n regim de monitor, preluarea de la productor a
urmtorului cuvnt i depunerea lui n recipient. Dac nu mai este spaiu (am
limitat spaiul doar cu scop didactic), atunci thread-ul productor este pus n
ateptare pn cnd consumatorul extrage (cel puin) un cuvnt.
Textul surs al clasei este prezentat n programul 1.12.

import java.util.*;

class RecipientCuvinte {
private Vector b = new Vector();
private String continut;
private int RECIPIENT;

public RecipientCuvinte(int recipient) {
RECIPIENT = recipient;
} // RecipientCuvinte.RecipientCuvinte

public synchronized String get() { // Extrage urmatorul cuvant din recipient,
// daca are ce extrage
while (b.size()==0) {
try { wait();
} // try
catch (Exception e) {
e.printStackTrace();
} // catch
} // while
continut = (String)b.elementAt(0); // Extrage cuvantul
b.remove(0); // Sterge-l
notify();
return continut;
} // RecipientCuvinte.get

public synchronized void put(String continut) { // Depune inca un
// cuvant in recipient, daca are loc
while (b.size()>=RECIPIENT) {
try { wait();
} // try
catch (Exception e) {

55
e.printStackTrace();
} // catch
} // while
b.add(continut);
notify();
} // RecipientCuvinte.put

} // RecipientCuvinte
Programul 1.12. RecipientCuvinte.java
1.6.4.2. Clasa ProductorCuvinte
ProducatorCuvinte este un thread care citete linii dintr-un fiier,
le desparte n cuvinte i depune cuvintele n recipient. Constructorul thread-ului
primete i reine referina la recipient i la fiierul de unde i citete liniile.
Metoda run, corpul thread-ului, citete fiierul linie dup linie. La
ntlnirea unei linii goale sau a unei linii care ncepe cu caracterul '\t' (TAB),
consider c paragraful precedent s-a terminat i introduce, numai pentru uzul
lui ConsumatorCuvinte, caracterul '\t' ca i marcaj de terminare a
paragrafului.
La ntlnirea sfritului de fiier, de asemenea numai pentru uzul lui
ConsumatorCuvinte, introduce '\n' ca i marcaj de sfrit de fiier.
n mod normal, fiecare linie este mprit n cuvinte cu ajutorul unui
obiect StringTokenizer, iar apoi fiecare dintre cuvinte este depus n
recipient cu ajutorul metodei put a acestuia. Este posibil (i probabil) ca din
cnd n cnd thread-ul s atepte extragerea de ctre ConsumatorCuvinte a
unui cuvnt din recipient nainte de a depune cuvntul curent.
Sursa clasei este prezentat n proogramul 1.13.

import java.util.*;
import java.io.*;

class ProducatorCuvinte extends Thread {
private RecipientCuvinte r;
private BufferedReader in;

ProducatorCuvinte(RecipientCuvinte r, BufferedReader in) {
this.r = r;
this.in = in;
} // ProducatorCuvinte.ProducatorCuvinte

public void run() {
String s = "";
StringTokenizer st;
r.put("\t");

56
for (;;) {
try {
s = in.readLine();
} // try
catch (Exception e) {
e.printStackTrace();
} // catch
if (s == null)
break; // Sfarsit fisier intrare
if (s.equals("")) {
r.put("\t"); // Depune marcaj de paragraf
continue;
} // if
if (s.charAt(0) == '\t')
r.put("\t"); // Depune marcaj de paragraf
st = new StringTokenizer(s.trim());
for ( ; st.hasMoreTokens(); )
r.put(st.nextToken()); // Depune cuvant
} // for
r.put("\n"); // Depune sfarsit de fisier
} // ProducatorCuvinte.run

} // ProducatorCuvinte
Programul 1.13. ProductorCuvinte.java
1.6.4.3. Clasa ConsumatorCuvinte
ConsumatorCuvinte este un thread care extrage succesiv cuvinte
din recipient, le aranjeaz (frumos) n linii i le depune pe fiierul de ieire.
Constructorul thread-ului primete i reine referina la recipient, referina la
fiierul de ieire i lungimea curent a liniei de ieire.
Metoda run, corpul thread-ului, citete din recipient cuvnt dup
cuvnt, folosind metoda get i reine ntr-un string cuvintele citite, unul dup
altul, separate printr-un spaiu. La ntlnirea unui caracter '\t' (TAB), care
semnific sfrit de paragraf, scrie la ieire ultima linie a paragrafului.
La ntlnirea caracterului '\n' (marcaj de sfrit de fiier), scrie ultima
linie (a ultimului paragraf) i thread-ul se termin.
n celelalte cazuri, verific dac urmtorul cuvnt mai ncape n linia
curent (nu a depit nc LUNGIME). n caz afirmativ depune cuvntul n linia
de ieire. Dac cuvntul curent nu mai ncape, atunci transmite linia curent
(fr cuvntul curent) metodei distantare care aliniaz cuvintele din linie.
Alinierea se face plasnd primul cuvnt aliniat la stnga n linie, ultimul cuvnt
aliniat la dreapta, iar celelalte cuvinte sunt deplasate aa nct spaiile dintre ele
s fie plasate ct mai uniform.

57
Extragerile din recipient se fac prin invocarea metodei get a recipien-
tului. Este posibil (i probabil) ca din cnd n cnd thread-ul s atepte extra-
gerea din recipient nainte de a depune.
Sursa clasei este prezentat n programul 1.14.

import java.io.*;
import java.util.*;

class ConsumatorCuvinte extends Thread {
private RecipientCuvinte r;
private PrintStream out;
private int LUNGIME;

ConsumatorCuvinte(RecipientCuvinte r, PrintStream out,
int lungime) {
this.r = r;
this.out = out;
LUNGIME = lungime;
} // ConsumatorCuvinte.ConsumatorCuvinte

private String distantare(String s) {
int i, nrSeparatori, nrSeparatoriMaiLungi=0,
pas=0, start, x;
String separator;
StringTokenizer st;
for (i=0, nrSeparatori=0; i<s.length(); i++)
if (s.charAt(i) == ' ')
nrSeparatori++;
if (nrSeparatori == 0)
return s;
nrSeparatoriMaiLungi =
(LUNGIME - s.length()) % nrSeparatori;
if (nrSeparatoriMaiLungi != 0)
pas = nrSeparatori / nrSeparatoriMaiLungi;
start = pas / 2;
x = (pas+1)*(nrSeparatoriMaiLungi-1)+1;
if (x <= nrSeparatori) {
pas++;
start = (nrSeparatori - x) /2;
} // if
for (i=0, separator=" ";
i<(LUNGIME-s.length())/nrSeparatori;
i++, separator+= " ");
st = new StringTokenizer(s);
for (i=0; st.hasMoreTokens(); i++)
if (i==0)
s = st.nextToken();
else if (nrSeparatoriMaiLungi == 0)
s += separator+st.nextToken();
else if ((((i-1)%pas)!=start))
s += separator+st.nextToken();
else {

58
s += " "+separator+st.nextToken();
nrSeparatoriMaiLungi--;
} // if
return s;
} // ConsumatorCuvinte.distantare

public void run() {
String linie = "", cuvant;
for (; ; ) {
cuvant = r.get();
if (cuvant.equals("\n"))
break; // Sfarsitul intrarii de cuvinte
if (cuvant.equals("\t")) {
if (linie.equals(""))
continue;
out.println(linie);
out.println(); // ncheie vechiul paragraf
linie = "";
continue;
} // if
if (linie.length()+1+cuvant.length() >= LUNGIME) {
out.println(distantare(linie));
// Scrie o linie din paragraf
linie = "";
} // if
if (linie.equals(""))
linie = cuvant;
else
linie += " "+cuvant;
} // for
out.println(linie);
} // ConsumatorCuvinte.run

} // ConsumatorCuvinte
Programul 1.14. ConsumatorCuvinte.java
1.6.4.4. Clasa AliniereCuvinte
Clasa principal a programului este AliniereCuvinte. Mai nti se
definesc constantele lungime a unei linii de ieire i capacitate a recipientului.
Apoi se definesc i construiesc cte un obiect recipient, un thread productor i
unul consumator. Intrarea pentru productor este intrarea standard, iar ieirea
pentru consumator este ieirea standard. Programul se ncheie cu lansarea n
lucru a celor dou thread-uri.
Sursa clasei este prezentat n programul 1.15.




59
import java.io.*;

class AliniereCuvinte {
final public int LUNGIME = 60, RECIPIENT = 100;
RecipientCuvinte r;
ProducatorCuvinte p;
ConsumatorCuvinte c;

public static void main(String[] a) {
AliniereCuvinte ac = new AliniereCuvinte();
ac.r = new RecipientCuvinte(ac.RECIPIENT);
ac.p = new ProducatorCuvinte(ac.r,
new BufferedReader(
new InputStreamReader(System.in)));
ac.c = new ConsumatorCuvinte(ac.r, System.out, ac.LUNGIME);
ac.p.start();
ac.c.start();

} // AliniereCuvinte.main

} // AliniereCuvinte
Programul 1.15. AliniereCuvinte.java
1.7. Procese externe lansate din Java
Facilitile independente de platform oferite de limbajul Java sunt
completate de posibilitatea utilizrii de cod extern, specific platformei. Este
vorba fie de includerea n codul Java a unor funcii native, fie de existena unei
interfee simple la aplicaii i utilitare specifice platformei gazd. n acest
paragraf, vom prezenta cea de-a doua facilitate dependent de platform.
Astfel, limbajul Java permite lansarea n execuie din interiorul unui
program, a unei aplicaii executabile externe JVM. De exemplu, se poate lansa
un fiier de tip .bat sau .exe sub Windows, sau un fiier shell, sub Unix.
Interfaa de execuie a unor comenzi externe din programe Java, este realizat
cu ajutorul metodei statice exec, din clasa Runtime [91]. Exist patru
variante de apel ale acestei metode, prezentate n continuare:

public Process exec (String command);
public Process exec (String [] cmdArray);
public Process exec (String command, String [] envp);
public Process exec (String [] cmdArray, String [] envp);

Metoda exec primete ca parametru un ir (sau mai multe iruri) de
caractere, reprezentnd comanda (comenzile) extern de executat. Dac este
prezent al doilea parametru, acest ir de caractere conine setrile variabilelor de
mediu, sub forma nume=valoare.

60
Metoda exec lanseaz un thread separat pentru execuia comenzii
(comenzilor) respective i returneaz un obiect de tip Process, asociat
procesului creat, astfel, n sistem. Dac aplicaia lansat din programul Java are
nevoie de date de intrare, acestea sunt transmise aplicaiei externe cu ajutorul
obiectului OutputStream, ataat obiectului Process:
OutputStream getOutputStream();
Similar, eventualele date de ieire ale aplicaiei, se pot obine folosind
obiectul InputStream, al aceluiai obiect Process:
InputStream getInputStream();
Se recomand ca nainte de a obine rezultatele aplicaiei, s se atepte
terminarea procesului creat folosind metoda waitFor(), din clasa Process.
De asemenea, codul de retur al aplicaiei se poate obine cu ajutorul metodei
exitValue(). Dac ntregul ntors are valoarea 0, atunci aplicaia s-a
terminat cu succes, altfel a aprut o eroare.
n programul 1.16 prezentm un exemplu de program Java, care afieaz
coninutul directorului curent folosind o comand extern, mai precis un fiier
de comenzi shell.

import java.io.*;

public class ExecJava {

static String com="fisier.bat";
static int SMAX=1000;

public static void main(String argv[]) {
try {
Process p;
p=Runtime.getRuntime().exec(com);
p.waitFor();

// obtine codul de retur al aplicatiei externe
int exval=p.exitValue();
System.out.println(exval);

// obtine datele de iesire
InputStream in=p.getInputStream();
byte blin[]=new byte[SMAX];
int noct=in.read(blin,0,SMAX);
String s=new String(blin,0,noct);
System.out.println(s);
}
catch(IOException e1) {
System.out.println(e1);
}
catch(InterruptedException e2){

61
System.out.println(e2);}
}// ExecJava.main

}// ExecJava
Programul 1.16. ExecJava.java

Fiierul fisier.bat, dac este sub Windows poate conine numai
comenzi DOS externe! Comenzile interne, cum ar fi dir, copy etc. nu pot fi
rulate, deoarece acestea presupun ncrcarea fiierului DOS command.com.
Pentru execuia unui fiier shell sub Unix dintr-un program Java este
obligatorie includerea, ca prim comentariu n fiier, a specificrii interpretorului
de comenzi folosit. De exemplu, pentru un fiier executat de ctre shell-ul
Bourne (sh) [65, 75, 99], prima linie din fiier va fi:
# !/bin/sh
Folosind facilitatea de apel a unor comenzi externe din programe Java,
se pot compila i executa noi programe Java, din interiorul altor programe.
Compilarea i/sau execuia acestor noi programe se realizeaz dinamic, n
momentul apelurilor de metode exec.
Iat, spre exemplu, partea esenial dintr-un program Java care lanseaz
din interiorul lui o compilare Java, dup care lanseaz crearea unei arhive jar
din fiierul class obinut:

String[] javac = {"javac", "FisierProgram.java"};
Process p=Runtime.getRuntime().exec(javac);
p.waitFor();
String[] jar = {"jar", "cf", "FisierProgram.jar",
"FisierProgram.class"};
p=Runtime.getRuntime().exec(jar);
p.waitFor();

S-ar putea să vă placă și