Você está na página 1de 138

1.

Introducere în limbajul de programare Java

1.1. Ce este Java?

• o insulă din Indonezia (126 650 km²,

65 mil. locuitori)

• un jargon american pentru cafea

• o platformă şi un limbaj de programare orientat pe obiecte


Utilizarea Internetului
ca mediu pentru difuzarea de informaţii, dar şi de programe, conduce la ideea
de numitor comun, de platformă comună pentru care să fie dezvoltate aplicaţiile.
Costurile implementării de aplicaţii pot să scadă spectaculos dacă nu sunt
necesare adaptări de soluţii pentru fiecare tip sau versiune hardware sau de sistem
de operare existent în lume.

1.2. Limbajul de programare Java

Java este un limbaj de programare de nivel înalt, dezvoltat de JavaSoft,


companie în cadrul firmei Sun Microsystems. Dintre caracteristicile principale ale
limbajului amintim:
• simplitate – Java este uşor de învăţat, caracteristicile complicate
(supraîncărcarea operatorilor, moştenirea multiplă, şabloane) întâlnite în
alte limbaje de programare sunt eliminate.

1
• robusteţe, elimină sursele frecvente de erori ce apar în programare prin
eliminarea pointerilor, administrarea automată a memoriei şi eliminarea
fisurilor de memorie printr-o procedură de colectare a 'gunoiului' care
rulează în fundal. Un program Java care a trecut de compilare are
proprietatea că la execuţia sa nu "crapă sistemul".
• complet orientat pe obiecte - elimină complet stilul de programare
procedural; se bazează pe încapsulare, moştenire, polimorfism
• uşurinţă în ceea ce priveşte programarea în reţea
• securitate, este cel mai sigur limbaj de programare disponibil în acest
moment, asigurând mecanisme stricte de securitate a programelor
concretizate prin: verificarea dinamică a codului pentru detectarea
secvenţelor periculoase, impunerea unor reguli stricte pentru rularea
programelor lansate pe calculatoare aflate la distanta, etc
• este neutru din punct de vedere arhitectural
• portabilitate, cu alte cuvinte Java este un limbaj independent de
platforma de lucru, aceeaşi aplicaţie rulând, fără nici o modificare, pe
sisteme diferite cum ar fi Windows, UNIX sau Macintosh, lucru care aduce
economii substanţiale firmelor care dezvoltă aplicaţii pentru Internet.
Sloganul de bază este: „Write once, run anywhere”
• compilat şi interpretat
• asigură o performanţă ridicată a codului de octeţi
• conţine o librărie de clase şi interfeţe pentru domenii specifice cum ar fi
programarea interfeţelor utilizator (JFC, AWT, Swing), programare
distribuită (comunicare TCP/IP, CORBA, RMI etc.)
• permite programarea cu fire de execuţie (multithreaded)
• dinamicitate
• este modelat după C şi C++, trecerea de la C / C++ la Java făcându-se
foarte uşor.
• face diferenţa între literele mici şi mari (este case sensitive)
• permite dezvoltarea aplicaţiilor pentru Internet – crearea unor
documente Web îmbunătăţite cu animaţie şi multimedia.
• Java Development Kit (JDK) este disponibil gratis

2
1.3. Java : un limbaj compilat şi interpretat

În funcţie de modul de execuţie al programelor, limbajele de programare se


împart în două categorii :
• interpretate: instrucţiunile sunt citite linie cu linie de un program numit
interpretor şi traduse în instrucţiuni maşină; avantaj: simplitate;
dezavantaj: viteza de execuţie redusă;
• compilate: codul sursă al programelor este transformat de compilator
într-un cod ce poate fi executat direct de procesor; avantaj: execuţie
rapidă; dezavantaj: lipsa portabilităţii, codul compilat într-un format de
nivel scăzut nu poate fi rulat decât pe platforma pe care a fost compilat.
Programele Java sunt atât interpretate cât şi compilate
Codul de octeţi este diferit de codul maşină. Codul maşină este reprezentat de
o succesiune de 0 şi 1; codurile de octeţi sunt seturi de instrucţiuni care seamănă cu
codul scris în limbaj de asamblare. Codul maşină este executat direct de către
procesor şi poate fi folosit numai pe platforma pe care a fost creat; codul de octeţi
este interpretat de mediul Java şi de aceea poate fi rulat pe orice platformă care
foloseşte mediul de execuţie Java.
Fazele prin care trece un program Java sunt:
Cod sursa Java -> (compilare) -> Cod de octeti ->
(interpretare)

1.4. Istoria limbajului Java

• 1991: în cadrul companiei Sun Microsystems începe dezvoltarea unui


proiect pentru aparatură electronică inteligentă conectată în reţea.

• 1992: începe dezvoltarea limbajului de programare Oak (James Gosling);

• 1993: devine disponibil primul browser WWW (World Wide Web) Mosaic;
dezvoltarea unui web-browser (Webrunner), capabil să încarce şi să execute
programe mici scrise în Oak;

• 1994: Oak este redenumit Java iar Webrunner, HotJava

• 1995: Netscape (fondat de cei care au dezvoltat Mosaic-ul) decide să


integreze Java în Netscape Navigator 2.0

3
• ianuarie 1996 : apare JDK 1.0 (soft gratuit);

• februarie

• 1997: apare JDK 1.1;

• martie 1997: apar HotJava 1.0 şi JavaOS 1.0;

• 1998 Java Foundation Classes JVC released, incluzând Swing 1.0

• după 1999 apar versiuni noi ale JDK

• în prezent s-a ajuns la JDK1.4.

1.5. Mediul Java

În acest curs se utilizează distribuţia JDK 1.3 (Java Development Kit), produsă
de firma Sun.
Există două posibilităţi de a lucra în Java: în linie de comandă – paşii fiind
indicaţi mai jos, sau folosind un editor Java cum ar fi JCreator, Eclipse, etc.
Realizarea unui program Java constă în următorii paşi:
• Editarea programului într-un editor de texte;
• Salvarea programului sub numele NumeClasa.java unde NumeClasa este
numele clasei care conţine metoda main(). Într-un program Java trebuie să
existe o singură clasă care să conţină o metodă main(). Cu alte cuvinte, numele
clasei trebuie să coincidă cu numele fişierului. Extensia fişierului este .java
• Compilarea programului se face cu ajutorul comenzii
javac NumeClasa.java

• Executarea programului se face cu ajutorul comenzii


java NumeClasa

1.6. Crearea unei aplicaţii simple

1. Scrierea codului sursă:

4
class Salut {
public static void main(String args[]) {
System.out.println("Salut !!!");
}
}
Toate aplicaţiile Java conţin o clasă principală în care trebuie să se găsească
metoda main(). Clasele aplicaţiei se pot găsi fie într-un singur fişier, fie în mai
multe.

2. Salvarea fişierelor sursă


Se va face în fişiere cu extensia .java. Fişierul care conţine codul sursă al
clasei principale trebuie să aibă acelaşi nume cu clasa principală a aplicaţiei (clasa
care conţine metoda main). Prin urmare, fişierul nostru o să-l salvăm sub numele:
Salut.java

3. Compilarea aplicaţiei
Se foloseşte compilatorul Java, javac. Apelul compilatorului se face pentru
fişierul ce conţine clasa principală a aplicaţiei. Compilatorul creează câte un fişier
separat pentru fiecare clasă a programului; acestea au extensia .class şi sunt
plasate în acelaşi director cu fişierele sursă. Rezultatul comenzii
javac Salut.java
este fişierul Salut.class

4. Rularea aplicaţiei
Se face cu interpretorul java, apelat pentru unitatea de compilare
corespunzătoare clasei principale, fiind însă omisă extensia .class asociată
acesteia.
java Salut

Rularea unei aplicaţii care nu foloseşte interfaţă grafică, se va face într-o fereastră
sistem.

1.7. Crearea unui applet

Crearea structurii de fişiere şi compilarea applet-urilor sunt identice ca în cazul


aplicaţiilor. Diferă în schimb structura programului şi modul de rulare al acestuia.

1. Scrierea codului sursă:

5
import javax.swing.*;
import java.awt.*;

public class Salut extends JApplet {


public void paint(Graphics g){
g.drawString("Salut",50,50);
}
}
2. Salvarea fişierelor sursă
Salvarea se va face în fişierul Salut.java

3. Compilarea applet-ului
javac Salut.java
În urma compilării rezultă fişierul Salut.class

4. Rularea applet-ului
Applet-urile nu rulează independent. Ele pot fi rulate doar prin intermediul unui
browser: Internet Explorer, Netscape sau printr-un program special cum ar fi
appletviewer-ul din setul JDK.
Crearea unui fişier HTML pentru miniaplicaţie (exemplu.html)
<html>
<head>
<title>Primul Applet Java</title>
</head>
<body>
<applet code=Salut.class width=400 height=400>
</applet>
</body>
</html>

5. Vizualizarea applet-tlui
appletviewer exemplu.html

6
2. Programarea Orientată pe Obiecte şi Java

2.1. Obiecte şi clase

Programarea Orientată pe Obiecte (OOP) este una dintre cele mai mari idei de
programare apărută în anii 1990. Ideea centrală a OOP este: organizarea
programelor astfel încât ele să reprezinte un ecou al modului în care lucrurile sunt
puse împreună în lumea reală.
Exemplu:
Pentru cine nu s-a jucat niciodată cu Lego, acesta constă în diferite bucăţi de
plastic, de diferite culori şi dimensiuni. Ele sunt dotate cu crescături şi adâncituri prin
intermediul cărora piesele pot fi conectate între ele. Cu diferite componente Lego se
poate forma aproape orice: maşini, oameni, castele, case, etc. în funcţie de
imaginaţia fiecăruia. Fiecare piesă de Lego este un mic obiect care împreună cu
altele ajută la crearea altor obiecte mai mari. Exact aşa stau lucrurile şi în
programarea orientată pe obiecte: obiecte mici puse împreună formează obiecte
mari.
Programarea orientată pe obiecte este gândită după modelul lumii reale –
obiectele sunt adesea formate din mai multe tipuri de obiecte mici.
Când scriem programe într-un limbaj orientat pe obiecte, nu definim obiecte ci
clase de obiecte, unde o clasă reprezintă un şablon pentru mai multe obiecte cu
caracteristici similare. Clasele întrupează toate caracteristicile unei mulţimi
particulare de obiecte. De exemplu, ne putem gândi la clasa Copac care descrie
caracteristicile tuturor copacilor (au rădăcini, trunchi şi frunze, cresc, produc clorofilă,
îşi schimbă frunzele, etc). Clasa Copac reprezintă un model abstract pentru
conceptul de copac – pentru a planta un copac, a-l atinge, a-i rupe o frunză sau a-l
tăia avem nevoie de un copac concret, altfel spus de o instanţă a copacului.
Bineînţeles că, odată ce avem clasa copac, putem crea oricâte instanţe diferite ale

7
copacului respectiv – ”copaci concreţi”. Aceştia pot avea caracteristici diferite (unii
sunt înalţi, alţii pitici, unii îşi pierd frunzele toamna, alţii nu, etc)

O altă noţiune specifică OOP este cea de obiect. Obiect sau instanţă a clasei
reprezintă acelaşi lucru. Clasa este reprezentarea generală a unui obiect iar
instanţa /obiectul este reprezentarea concretă a clasei.

2.2. Atribute şi comportamente

Fiecare clasă scrisă în Java are două caracteristici de bază: atribute şi


comportament.

2.2.1. Atribute

Atributele diferenţiază obiectele între ele şi determină aparenţa, starea sau alte
calităţi ale obiectului în cauză. Dacă ne gândim să creăm o clasă Maşină, ea ar
trebui să includă următoarele atribute: culoare, stil, marcă.
Atributele sunt definite în clase ca variabile. Tipul şi numele variabilelor
sunt definite în clase şi fiecare obiect are valori proprii pentru fiecare atribut.

8
Deoarece fiecare instanţă a clasei poate avea valori diferite pentru variabilele sale,
aceste variabile se mai numesc şi variabile instanţă.
Exemplu: O instanţă a clasei maşină, MaşinaMea ar putea avea următoarele
valori pentru atribute:
culoare = alb
stil = elegant
marcă = Mercedes
Există, de asemenea, şi un alt tip de variabile numite variabile clasă.
Diferenţa dintre cele două tipuri de variabile este aceea că valorile variabilelor
instanţă sunt păstrate în instanţe şi se schimbă pentru fiecare instanţă iar valorile
variabilelor clasă sunt păstrate în clasă şi nu se schimbă pentru fiecare instanţă.
Asupra diferenţei dintre cele două tipuri de variabile o să revin într-un capitol
următor.

2.2.2. Comportament

Comportamentul unei clase determină cum operează o instanţă a unei clase.


De exemplu, cum reacţionează un obiect atunci când un alt obiect sau o altă clasă îi
cere să facă ceva. Să revenim la clasa Maşină. Comportamentul unei maşini constă
în: porneşte, opreşte, frânează, schimbă viteza, schimbă
direcţia, etc.
Pentru a defini comportamentul unei clase se definesc metode, echivalentul
funcţiilor sau procedurilor din alte limbaje de programare. Spre diferenţă de alte
limbaje de programare, în Java nu se pot defini funcţii în afara claselor. Prin urmare,
metodele sunt funcţii definite în interiorul claselor care operează în instanţele
claselor respective.
Metoda unui obiect poate fi apelată de către un alt obiect sau o altă clasă.
Ca şi în cazul atributelor, există două tipuri de metode: metode instanţă şi
metode clasă. Metodele instanţă operează doar în cadrul instanţei unei clase. În
schimb, metodele clasă operează în interiorul clasei.

9
2.3. Principiile OOP

Obiectul este o variabilă care are o structura şi o stare. Fiecare obiect dispune
de operaţii prin intermediul cărora i se poate manipula starea.
Obiectul trebuie privit ca o unitate atomică pe care utilizatorul nu ar trebui să o
disece. De exemplu, când lucrăm cu numere întregi, nu ne punem problema
reprezentării lor. Utilizatorul nu are acces direct la părţile constituente ale unui obiect
sau la implementarea sa; acestea vor putea fi accesate doar prin intermediul
metodelor care au fost furnizate împreună cu obiectul. Gruparea datelor şi a
operaţiilor care pot fi efectuate asupra acestor date, având grijă ca detaliile de
implementare să fie ascunse, poarta numele de încapsulare.
Unul din principalele scopuri ale OOP este refolosirea codului. Limbajele de
programare orientate pe obiecte furnizează mai multe mecanisme în acest scop.
1. Folosirea codului generic – dacă implementarea este identică, şi diferă
doar tipul de bază al obiectului, nu este necesară rescrierea completă a
codului – se scrie un cod generic care funcţionează pentru orice tip. De
exemplu, se poate scrie o metodă care să ordoneze un şir de numere întregi,
caractere, şiruri de caractere.
2. Moştenirea este un mecanism care permite extinderea funcţionalităţii unei
clase. Se pot crea noi tipuri de date care să extindă (sau să restricţioneze)
proprietăţile tipului de date original.
3. Polimorfismul Un tip referinţă polimorfic poate să refere obiecte de mai
multe tipuri. Atunci când se apelează o metodă a tipului polimorfic, se va
selecta automat metoda care corespunde tipului referit în acel moment.

10
3. Elementele de bază ale limbajului de
programare Java

3.1. Structura lexicală a limbajului

3.1.1. Setul de caractere

Limbajului Java foloseşte setul de caractere Unicode. Este un standard


internaţional care înglobează setul de caractere ASCII (permite reprezentarea a 256
de caractere). Foloseşte pentru reprezentarea caracterelor 2 octeţi, ceea ce
înseamnă că se pot reprezenta 65536 de semne. Primele 256 caractere Unicode
corespund celor din ASCII. Referirea la un caracter se face prin \uxxxx, unde xxxx
reprezintă codul caracterului.
Exemple:
\u0030 - \u0039 : cifre ISO-Latin 0 - 9
\u0660 - \u0669 : cifre arabic-indic 0 - 9
\u4e00 - \u9fff : litere din alfabetul Han (Chinez, Japonez,
Coreean)

3.1.2. Cuvinte cheie

Cuvintele rezervate în Java sunt cele din C++, cu câteva excepţii.

3.1.3. Identificatori

Sunt secvenţe nelimitate de litere şi cifre Unicode, începând cu o literă.


Identificatorii nu au voie să fie identici cu cuvintele rezervate.

11
3.1.4. Constante

Constantele pot fi de următoarele tipuri


1. constante întregi
Sunt acceptate 3 baze de numeraţie : baza 10, baza 16 (încep cu
caracterele 0x) şi baza 8 (încep cu cifra 0) şi pot fi de două tipuri:
• normale, (se reprezintă pe 4 octeţi - 32 biţi)
• lungi (8 octeţi - 64 biţi): se termină cu caracterul L (sau l).
2. constante reale
Pentru ca o constantă să fie considerată reală ea trebuie să aibă cel puţin
o zecimală după virgulă, să fie în notaţie exponenţială sau să aibă sufixul F sau f
pentru valorile normale (reprezentate pe 32 biţi), respectiv D sau d pentru valorile
lungi (reprezentate pe 64 biţi).

3. constante logice
true : valoarea booleană de adevăr
false : valoarea booleană de fals
Observaţie: spre deosebire de C++, constantele întregi 1 şi 0 nu mai au rolul
de adevărat şi fals.
4. constante caracter
O constantă de tip caracter este utilizată pentru a exprima caracterele
codului Unicode. Reprezentarea se face fie folosind o literă, fie o secvenţă
escape scrisă între apostrofuri. Secvenţele escape permit reprezentarea
caracterelor care nu au reprezentare grafică şi reprezentarea unor caractere
speciale precum backslash, apostrof, etc. Secvenţe escape predefinite în Java:

Cod Secvenţa Escape Caracter


\u0008 '\b' Backspace(BS)
\u0009 '\t' Tab orizontal (HT)
\u000a '\n' Linie nouă - linefeed (LF)
\u000c '\f' Pagină nouă - formfeed (FF)
\u000d '\r' Început de rând (CR)
\u0022 '\"' Ghilimele
\u0027 '\'' Apostrof
\u005c '\\' Backslash
\u0008 '\b' Backspace(BS)

12
5. constante şiruri de caractere
Un şir de caractere este format din zero sau mai multe caractere cuprinse
între ghilimele. Caracterele care formează şirul de caractere pot fi caractere
grafice sau secvenţe escape. Dacă şirul este prea lung el poate fi scris ca o
concatenare de subşiruri de dimensiune mai mică. Concatenarea şirurilor se face
cu operatorul + ("Ana " + " are " + " mere "). Şirul vid este "". După
cum vom vedea, orice şir este de fapt, o instanţă a clasei String, definită în
pachetul java.lang.

3.1.5. Separatori

Un separator este un caracter care indică sfârşitul unei unităţi lexicale şi


începutul alteia. În Java separatorii sunt următorii: ( ) { } [ ] ; , . Instrucţiunile unui
program se separă cu ”;”.

3.1.6. Operatori

1. operator de atribuire: = (semnul egal)


Exemplu: a=9 (lui a i se atribuie valoarea 9)
Operatorii de atribuire pot fi înlănţuiţi. De exemplu: a=b=c=10
2. operatori aritmetici binari: +, -, *, /, %
Exemplu: s=a+b
În Java există forme prescurtate care cuprind operatorul de atribuire şi un
operator aritmetic binar. Operatorii prescurtaţi sunt:+=, -=, *=, /=, %=
Exemplu: n += 2 este echivalentă cu n=n+2
3. operatori aritmetici unari: +, -, ++ (operator de incrementare), -- (operator de
decrementare). Operatorii de incrementare şi decrementare pot fi prefixaţi (++x
sau --x) sau postfixaţi (x++ sau x--). Diferenţa dintre operatorii prefixaţi şi cei
postfixaţi este semnificativă doar atunci când expresia de incrementare /
decrementare apare în cadrul unei expresii. Exemplele următoare vor evidenţia
aceste lucruri.
Exemple:

13
a) -x reprezintă opusul lui x
b) int x=5,y=7;
x++; // x primeste valoarea 6
y--; // y primeste valoarea 6
c) int x=5,y=7;
++x; // x primeste valoarea 6
--y; // y primeste valoarea 6
d) int x=5,y;
y=x++; // y primeste valoarea 5, x primeste
valoarea 6
e) int x=5,y;
y=x--; // y primeste valoarea 5, x primeste
valoarea 4
f) int x=5,y;
y=++x; // x primeste valoarea 6, y primeste
valoarea 6
g) int x=5,y;
y=--x; // x primeste valoarea 4, y primeste
valoarea 4

Observaţii: În exemplele b şi c nu se observă nici o diferenţă între


operatorii postfixaţi şi cei prefixaţi deoarece ei nu sunt folosiţi în cadrul altor
expresii. În exemplele d şi f, respectiv, e şi g se observă că x primeşte aceeaşi
valoare dar y are valori diferite. În exemplele d şi e sunt folosiţi operatorii
postfixaţi de incrementare şi decrementare care se comportă astfel: valoarea
variabilei asupra căreia acţionează operatorul postfixat (în cazul nostru x)
participă la evaluarea expresiei din care face parte (y primeşte valoarea lui x)
după care se aplică operatorul (valoarea lui x creşte / scade cu o unitate). În
exemplele f şi g sunt folosiţi operatorii prefixaţi de incrementare şi decrementare
care se comportă astfel: valoarea variabilei asupra căreia acţionează operatorul
postfixat (în cazul nostru x) îşi schimbă valoarea (valoarea lui x creşte / scade cu
o unitate), noua valoare participând la evaluarea expresiei din care face parte (y
primeşte noua valoare a lui x).
4. operatori logici: &&(and), ||(or), !(not)
Observaţie: evaluarea expresiilor logice se face prin scurtcircuitare
(evaluarea se opreşte în momentul în care valoarea de adevăr a expresiei este
sigur determinată)
5. operatori relaţionali: <, <=, >, >=, ==, !=
6. operatori pe biţi: & (and), |(or), ^(xor), ~(not)
7. operatori de translaţie: <<, >>, >>> (shift-are la dreapta fără semn)

14
8. operatorul condiţional: ”? : ” . Are forma:
expresie_logica ? expresie1 : expresie2

Valoarea expresiei este dată de expresie1 dacă expresie_logică


este true sau de expresie2 dacă expresie_logică este false.
Exemplu: Metoda de calculul minimului a două numere este:
public int min (int a, int b){
return a<b?a:b;
}

9. operatorul , (virgula) este folosit pentru evaluarea secvenţială a operaţiilor


Exemplu: int x=0, y=1, z=2; (x=1,y=a=10,c=1)
10. operatorul + pentru concatenarea şirurilor:
String s="abcd"
int x=100;
System.out.println(s + " - " + x); //afiseaza abcd-100

11. operatorul de conversie de tip (cast) este: (tip_de_data)


int i = 200;
long l = (long)i; //conversie prin extensie
long l2 = (long)200;
int i2 = (int)l2; // conversie prin contractie

Exemplu 1: Fie programul

public class Operator{


public static void main(String args[]){
int a=2, b=3,c;
c=a+b;
System.out.println(a+" "+b+" "+c);
a++; --b;
System.out.println(a+" "+b+" "+c);
c=++a+b++;
System.out.println(a+" "+b+" "+c);
a/=2;b*=2;
System.out.println(a+" "+b+" "+c);
c=a-- + --b;
System.out.println(a+" "+b+" "+c);
c=b=(a+=1);
System.out.println(a+" "+b+" "+c);
}
}

15
Rezultatul afişat este:
2 3 5
3 2 5
4 3 6
2 6 6
1 5 7
2 2 2

Exemplu 2: Fie programul


public class OpLogic{
public static void main(String args[]){
byte a=0;
System.out.println("Primul if");
if ((a!=0) && ((1/a)<1))
System.out.println("Ambele conditii sunt adevarate");
else
System.out.println("O conditie este falsa");
System.out.println("Al doilea if");
if ((1/a<1) && (a!=0))
System.out.println("Ambele conditii sunt adevarate");
else
System.out.println("O conditie este falsa");
}
}

Rezultatul afişat este:


Primul if
O conditie este falsa
Al doilea if
Exception in thread ”main” java.lang.ArithmeticException:
/ by zero at OpLogic.main(OpLogic.java:11)

Explicaţia se găseşte în modul în care sunt evaluate expresiile logice (prin


scurtcircuitare). În primul if se evaluează expresia a!=0 care are valoarea false.
Indiferent de rezultatul celei de-a doua expresii, rezultatul final va fi false. Prin
urmare, evaluarea întregii expresii se opreşte după evaluarea lui a!=0, ceea ce
urmează după nu mai contează. În al doilea if, evaluarea începe tot cu prima
expresie, şi anume 1/a<1. Dar, ea nu poate fi evaluată deoarece 1/a nu are sens
(a fiind 0) şi, este generată o excepţie. Din nou, nu se ajunge la evaluarea celei de a
doua expresii.

16
3.1.7. Comentarii

În Java există trei feluri de comentarii:


• Comentarii pe o singură linie: încep cu //.
• Comentarii pe mai multe linii, închise între /* şi */.
• Comentarii pe mai multe linii care formează documentaţia, închise între /** şi
**/. Textul dintre cele douã secvenţe este automat mutat în documentaţia
aplicaţiei de către generatorul automat de documentaţie javadoc.
Observaţii:
1. nu pot fi scrise comentarii în interiorul altor comentarii.
2. nu pot fi introduse comentarii în interiorul constantelor caracter sau şir de
caractere.
3. secvenţele /* şi */ pot să apară pe aceeaşi linie cu secvenţa // dar îşi pierd
semnificaţia; la fel se întâmplã cu secvenţa // în comentarii care încep cu /*
sau /**.

3.2. Tipuri de date

În Java tipurile de date se împart în două categorii:


• tipuri primitive de date
• tipuri referinţă.
Java porneşte de la premiza că "orice este un obiect". Prin urmare, tipurile de
date ar trebui să fie de fapt definite de clase şi toate variabilele ar trebui să
memoreze de fapt instanţe (obiecte) ale acestor clase. În principiu acest lucru este
adevărat, însă, pentru uşurinţa programării, mai există şi aşa numitele tipuri
primitive de date, care sunt cele uzuale:
1. tipuri întregi
Tip de date Dimensiune în octeţi Domeniu
byte 1 -128 .. 127
short 2 -32768 .. 32767
-2147483648 ..
int 4
2147483647

17
long 8 -263 .. 263-1

2. tipuri reale
Tip de date Dimensiune în octeţi Domeniu
float 4 -1046 .. 1038
double 8 -10324 .. 10308

3. tipul caracter: char memorat pe 2 octeţi


4. tipul boolean: are două valori – true şi false
În alte limbaje formatul şi dimensiunea tipurilor primitive de date folosite într-un
program pot depinde de platforma pe care rulează programul. În Java acest lucru nu
mai este valabil, Java fiind independent de platformă.
Vectorii, clasele şi interfeţele sunt tipuri referinţă. Valoarea unei variabile de
acest tip este, spre diferenţă de tipurile primitive, o referinţă (adresă de memorie)
către valoarea sau mulţimea de valori reprezentată de variabila respectivă.
Există trei tipuri de date C care nu sunt suportate de limbajul Java: pointer,
struct şi union. Pointerii au fost eliminaţi din cauza că erau o sursă constantă de
erori, locul lor fiind luat de tipul referinţă, iar struct şi union nu îşi mai au rostul atât
timp cât tipurile compuse de date sunt formate în Java prin intermediul claselor.

3.3. Variabile

Variabilele pot avea ca tip fie un tip primitiv de dată, fie o referinţă la un obiect.
Declararea variabilelor se face prin:
tip_de_date nume_variabila

Iniţializarea variabilelor se face prin:


nume_variabila = valoare

Declararea şi iniţializarea variabilelor pot fi făcute în acelaşi moment:


tip_de_date nume_variabila = valoare

Declararea constantelor se face prin:


final tip_de_date nume_variabila

18
Exemple:
int a; a=5;
final double PI = 3.14;
int valoare = 100;
long numarElemente = 12345678L;
String floare = "frezie";

În funcţie de locul în care sunt declarate, variabilele se împart în următoarele


categorii:

1. Variabile membru, declarate în interiorul unei clase, vizibile pentru toate


metodele clasei respective şi pentru alte clase în funcţie de modificatorul lor
de acces
2. Variabile locale, declarate într-o metodă sau într-un bloc de cod, vizibile
doar în metoda / blocul respectiv
3. Parametrii metodelor, vizibili doar în metoda respectivă
4. Parametrii de la tratarea excepţiilor
Imaginea următoare ilustrează tipurile de variabile şi parametrii împreună cu
domeniul lor de vizibilitate.

public class Nume_Clasa


{
...
declararea variabilelor membru
...
public void Metoda (parametrii metodei)

{

declararea variabilelor locale

catch (parametrii de la tratarea
excepţiilor)
{

}


}

}

19
Observaţie: Variabilele declarate într-un for, rămân locale corpului ciclului. De
exemplu:
for(int i=0; i<100; i++) { }
int i; //posibil în Java, eroare în C++

3.4. Instrucţiuni

3.4.1. Instrucţiunea vidă

Este formată din ”;”.

3.4.2. Instrucţiuni de decizie

1. Instrucţiunea if–else are forma:


if (expresie_logică)
instrucţiuni1
else
instrucţiuni2
instrucţiuni

Dacă expresie_logică are valoarea true atunci se execută instrucţiuni1, altfel


se execută instrucţiuni2. Expresie_logică este obligatoriu să fie cuprinsă între
paranteze. Dacă pe una din ramuri sunt mai multe instrucţiuni ele trebuie să fie
cuprinse între acolade {…}. Ramura
else
instrucţiuni2
poate să lipsească.

Exemplu 3: Să se calculeze maximul a două numere.


1. public class Maxim
2. { public static void main(String args[])
3. {int a=12, b=5,m;
4. if (a>b)
5. m=a;
6. else
7. m=b;
8. System.out.println("Maximul dintre "+a+" si "+b+" este: "+m);
9. }

20
10. }

Exemplu 4: Să se rezolve ecuaţia de gradul I ax+b=0 cunoscând coeficienţii a şi b.


1. public class ecGrI
2. { public static void main(String args[])
3. {int a=12, b=5;
4. System.out.print("Ecuatia: "+a+"x+"+b+"=0");
5. if (a==0)
6. if (b==0)
7. System.out.println(" are o infinitate de solutii");
8. else
9. System.out.println(" nu are solutii");
10. else { double x =-(double)b/a;
11. System.out.println(" are solutia "+x);
11. }
12. }
13. }

În exemplu 4 au fost folosite if-uri imbricate. Pe linia 10 a fost folosit


operatorul de conversie pentru ca rezultatul împărţirii să se fie număr real. Dacă
acest operator nu ar fi fost folosit, împărţirea ar fi fost efectuată între doi operanzi
întregi şi, prin urmare, rezultatul ar fi fost număr întreg.

2. Instrucţiunea switch are forma:


switch (expresie_selectare){
case val_1: instrucţiune_1; break;
case val_2: instrucţiune_2; break;
. . .
case val_i: instrucţiune_i; break;
. . .
case val_n: instrucţiune_n; break;
default: instrucţiune;
}
Instrucţiunea switch selectează dintre mai multe secvenţe de cod una care
va fi executată. Se evaluează expresie_selectare; rezultatul obţinut se compară
pe rând cu val_1, val_2, ..., val_n. Dacă se întâlneşte o valoare val_i pentru
care se obţine egalitate (expresie_selectare = val_i ) se execută
instrucţiunile instrucţiune_i. Altfel, (dacă nu are loc nici o egalitate) se execută
instrucţiunile de pe ramura default.
Instrucţiune break întâlnită pe fiecare ramură are rolul de a întrerupe execuţia
instrucţiunii switch după ce au fost executate instrucţiunile aferente ramurii alese.

21
Dacă instrucţiunea break lipseşte atunci se execută şi instrucţiunile de pe
următoarele ramuri până la întâlnirea primului break.

Exemplu 5: Se citeşte de la tastatură un caracter reprezentând un operator: ’+’, ’–’,


’*’ sau ’/’. În funcţie de operatorul citit să se facă suma, diferenţa, înmulţirea sau
împărţirea celor două numere a şi b.
1. public class Operatii{
2. public static void main(String args[]){
3. double a=12, b=5, r=0;
4. char oper=' ';
5. try{
6. System.out.println("Introduceti operatorul");
7. oper=(char)System.in.read();
8. }
9. catch(Exception e){}
10. switch (oper) {
11. case '+':
12. r=a+b; break;
13. case '-':
14. r=a-b; break;
15. case '*':
16. r=a*b; break;
17. case '/':
18. r=a/b; break;
19. default:
20. System.out.println("Operator invalid");
21. System.exit(1);
22. }
23. System.out.println(a+" "+oper+" "+b+" = "+r);
24. }
25. }

În linia 7 se citeşte un caracter de la tastatură memorat în oper şi, în funcţie de


el se execută instrucţiunile de pe liniile 12, 14, 16, 18 sau 20-21. Instrucţiunile de pe
liniile 20-21 se execută doar în cazul în care nu a fost introdus un operator corect.

Exemplu 6: Să se spună dacă un număr dat mai mic decât 10 este par sau impar.
1. public class ParImpar{
2. public static void main(String args[]){
3. int x=2;
4. switch (x) {
5. case 0:
6. case 2:
7. case 4:
8. case 6:

22
9. case 8:
10. System.out.println(x+" este numar par");break;
11. default:
12. System.out.println(x+" este numar impar");
13. }
14. }
15. }

În exemplul precedent ne interesează ca aceeaşi instrucţiune, cea din linia 9


să fie executată pentru mai multe potriviri. În acest caz, sunt folosite mai multe linii
de case fără nici un rezultat, instrucţiunea switch executând prima instrucţiune
întâlnită după găsirea potrivirii. Prin urmare, instrucţiunea break nu apare pe nici
una din liniile 5, 6, 7,8.

3.4.3. Instrucţiuni repetitive

1. Instrucţiunea for repetă un bloc de instrucţiuni cât timp o condiţie este


adevărată. În general, se cunoaşte de la început de câte ori urmează să se
execute blocul de instrucţiuni. Are forma generală:
for (iniţializare; test; incrementare)
instrucţiuni
unde:
• iniţializare este o expresie care iniţializează variabila de control

a instrucţiunii for
• test este o expresie booleană evaluată înaintea fiecărei reluări a

buclei; cât timp valoarea ei este true blocul de instrucţiuni se execută. Când
valoarea ei este false, se părăseşte instrucţiunea for.
• incrementare este o expresie care modifică variabila de control a

instrucţiunii for.
Oricare dintre cele trei părţi constituente ale instrucţiunii for poate să
lipsească.
for ( ; ; )

În acest caz se obţine o buclă infinită. Pentru a evita acest lucru este necesar
ca în cadrul blocului de instrucţiuni să existe o condiţie de oprire.

23
De asemenea, blocul de instrucţiuni poate să lipsească, el fiind înlocuit de
instrucţiunea vidă. Exemplul 8 de mai jos ilustrează această situaţie.

Exemplu 7: Să se calculeze n! unde n este iniţializat în program.


2. public class Factorial{
3. public static void main(String args[]){
4. long f=1;
5. int n=15;
6. for(int i=2; i<=n; i++)
7. f*=i; //f=f*i;
8. System.out.println(n+"!="+f);
9. }
10. }

Exemplu 8: Să se calculeze n! unde n este iniţializat în program.


1. public class Factorial{
2. public static void main(String args[]){
3. long f=1;
4. int n=15;
5. for(int i=2; i<=n; f*=i, i++)
6. ;
7. System.out.println(n+"!="+f);
8. }
9. }

După cum se poate remarca, pe linia 6 este folosită instrucţiunea vidă


deoarece codul f*=i a fost mutat în cadrul părţii de incrementare.
O altă observaţie ar fi că, oricare dintre părţile constituente ale instrucţiunii for
poate fi formată din mai multe instrucţiuni. Acest lucru este ilustrat în programul
următor.

Exemplu 9:
1. public class Factorial{
2. public static void main(String args[]){
3. long f, LimSup;
4. int n=10,i;
5. LimSup=(long)Math.pow(2,63);
6. for(i=2,f=1; i<=n && f<=LimSup/i; f*=i,i++)
7. ;
8. if (i==n+1)
9. System.out.println(n+"!="+f);
10. else
11. System.out.println(n+"!=este prea mare pentru puterile mele");
12. }

24
13. }

În linia 5 este calculat numărul maxim reprezentabil, de tip long. În for,


iniţializăm două variabile i=2,f=1. Test-ul este format din două condiţii unite prin
&&. Incrementarea este, de asemenea, formată din două instrucţiuni f*=i,i++.

11. Instrucţiunea while are forma:


while (condiţie)
instrucţiuni
Instrucţiunea while este folosită pentru a repeta execuţia unui grup de
instrucţiuni atâta timp cât condiţie are valoare true.

Exemplu 10: Să se calculeze suma cifrelor unui număr.


1. public class SumCifNr{
2. public static void main(String args[]){
3. long x=12345,xInit=x;
4. int s=0;
5. while(x>0){
6. s+=x%10;
7. x/=10;
8. }
9. System.out.println("Suma cifrelor numarului "+xInit+"
este: "+s);
10. }
11. }

Instrucţiunea while se mai numeşte şi instrucţiune cu test iniţial. Dacă la prima


evaluarea a condiţiei aceasta are valoarea false instrucţiunile din corpul
while-ului nu se execută niciodată. În exemplul precedent, dacă iniţializăm x cu 0,
condiţia x>0 este falsă şi se continuă cu instrucţiunea din linia 9.

12. Instrucţiunea do-while are forma:


do{
instrucţiuni
}while (condiţie);

Ca şi while, instrucţiunea do-while este folosită pentru a repeta execuţia


unui grup de instrucţiuni atâta timp cât condiţie are valoare true. Diferenţa dintre

25
cele două instrucţiuni este că, dacă la while se executau instrucţiunile doar dacă
condiţie era adevărată, în cazul lui do-while blocul de instrucţiuni se execută
cel puţin o dată după care se verifică valoarea condiţiei.
Instrucţiunea do-while se mai numeşte şi instrucţiune cu test final.

Exemplu 11: Să se calculeze cel mai mare divizor comun a două numere a şi b.
1. public class Cmmdc{
2. public static void main(String args[]){
3. long a=54,b=68,r;
4. System.out.print("Cmmdc-ul numerelor "+a+" si "+b+"
este: ");
5. do{
6. r=a%b;
7. a=b;
8. b=r;
9. }while(r>0);
10. System.out.println(a);
11. }
12. }

13. Instrucţiunea break


break
Este folosită pentru părăsirea forţată a corpurilor instrucţiunilor repetitive (for,
while, do-while).

Exemplu 12: Să se caute un număr cuprins în intervalul [a,b].


1. public class ExBreak{
2. public static void main(String args[]){
3. int a=10, b=20, x;
4. while(true){
5. x=(int)(Math.random()*b);
6. if ( (a<=x) && (x<=b) )
7. break;
8. }
9. System.out.println(x);
10. }
11. }

În linia 5 se generează aleator un număr întreg mai mic decât b. Dacă numărul
este cuprins în intervalul [a,b] se părăseşte instrucţiunea while.
Dacă instrucţiunea break este plasată în cadrul mai multor instrucţiuni
repetitive imbricate, ea are ca efect părăsirea doar a instrucţiuni care o conţine.

26
Exemplu:
1. for(...){
2. ...
3. for(...){
4. ...
5. break;
6. ...
7. }
8. ...
9. }

Efectul instrucţiunii break este părăsirea for-ului din linia 3, execuţia


continuându-se cu instrucţiunile de pe linia 8.

14. Instrucţiunea continue


Are ca efect întreruperea execuţiei iteraţiei curente şi trecerea la iteraţia
următoare.

Exemplu 13: Următorul cod afişează toate caracterele citite cu excepţia cifrelor de la
0 la 9.
1. public class ExContinue{
2. public static void main(String args[]){
3. for(int i=0; i<=10; i++){
4. char c=' ';
5. try{
6. c=(char)System.in.read();
7. }
8. catch(Exception e){}
9. if ( ('0'<=c) && (c<='9') )
10. continue;
11. System.out.print(c+" ");
12. }
13. }
14. }

În cazul în care se citeşte o cifră, se execută instrucţiunea continue de pe


linia 10, nu se mai execută linia 11 şi se sare direct la linia 3.
Observaţie: Instrucţiunile break şi continue pot să apară doar în cadrul unor
instrucţiuni repetitive. Excepţie face instrucţiunea break care poate să apară şi în
cadrul instrucţiunii switch.

27
3.5. Tablouri (vectori)

3.5.1. Tablouri (vectori) unidimensionale

Declararea unui vector se face prin


TipElement[] numeVector; sau TipElement numeVector[];

unde TipElement reprezintă tipul elementelor vectorului, iar parantezele []


aşezate fie înaintea fie după numele vectorului arată că este vorba despre un vector.

Exemple:
int[] v;
String adrese[];

Instanţierea unui vector se realizează cu operatorul new şi are ca efect


alocarea memoriei necesare pentru memorarea elementelor vectorului, mai precis
specificarea numărului maxim de elemente pe care îl va avea vectorul. Instanţierea
unui vector se face astfel:
numeVector = new TipElement[dimensiune];

Exemple:
v = new int[10]; //se alocă spaţiu pentru 10 întregi
adrese = new String[100]; //se alocă spaţiu pentru 100 de String-uri

Declararea şi instanţierea unui vector pot fi făcute simultan astfel:


TipElement[] numeVector = new TipElement[dimensiune];

Exemple:
int [] v = new int[10];

După declararea unui vector, acesta poate fi iniţializat, adică elementele sale
pot primi valori. În acest caz instanţierea lipseşte, alocarea memoriei făcându-se
automat în funcţie de numărul de elemente cu care se iniţializează vectorul.

Exemple:

28
String culori[] = {"Rosu", "Galben", "Verde"};
int []v = {2, 4, 6, 8, 10, 12};

Observaţii:
Primul indice al unui vector este 0, deci poziţiile unui vector cu n elemente vor
fi cuprinse între 0 şi n-1.
Nu sunt permise construcţii de genul:
TipElement numeVector[dimensiune]

alocarea memoriei făcându-se doar prin intermediul operatorului new sau prin
iniţializare.
Exemple:
int v[10]; //incorect
int v[] = new int[10]; //corect

Accesul la elementul unui vector se face prin:


numeVector[indice]

Exemplu 1:
int v[]=new int[10];
for(i=0; i<10; i++)
v[i]=i;

Exemplu 2:
int v[]={1,2,3,4,5};
for(i=0; i<5; i++)
System.out.println(v[i]+” “);

3.5.2. Tablouri (vectori) cu mai multe dimensiuni

În Java tablourile cu mai multe dimensiuni sunt de fapt vectori de vectori. Prin
urmare, declararea, instanţierea şi iniţializarea se fac la fel ca în cazul vectorilor
unidimensionali.
TipElement numeVector[][]… = new TipElement[dim1][dim2]…
sau
TipElement[][]… numeVector = new[dim1][dim2]… TipElement
sau parantezele pot fi de o parte şi de alta a lui numeVector.

29
Exemplu:
int m[][]; //declararea unei matrice
m = new int[5][10]; //cu 5 linii, 10 coloane
Observaţie:
m[0], m[1], ..., m[4] sunt vectori de întregi cu 10 elemente

3.5.3. Dimensiunea unui vector

Cu ajutorul cuvântului cheie length se poate afla dimensiunea unui vector.


Exemple:
Fie vectorul
int []a = new int[5];
atunci a.length are valoarea 5.
Fie matricea
int m = new int[5][10];
atunci:
m.length are valoarea 5 şi reprezintă numărul de linii al matricei
m[0].length are valoarea 10 şi reprezintă numărul de elemente al
primei linii a matricei,
m[1].length are valoarea 10 şi reprezintă numărul de elemente al
celei de-a doua linii a matricei, etc.

Exemplu 14: Să se calculeze minimul elementelor unui vector.


1. public class MinVect{
2. public static void main(String args[]){
3. int a[]={2,1,4,7,3};
4. int min=a[0];
5. for(int i=0; i<a.length; i++)
6. if (min>a[i])
7. min=a[i];
8. System.out.println("Minimul este "+min);
9. }
10. }

Exemplu 15: Să se ordoneze elementele de pe diagonala principală a unei matrice.


1. public class OrdDiagPrinc{
2. public static void main(String args[]){
3. int a[][]={{2,1,4,7},{3,5,1,8},{2,5,1,9},{3,2,5,8}};
4. boolean ordonat;
5. for(int i=0; i<a.length; i++){

30
6. for(int j=0; j<a[i].length; j++)
7. System.out.print(a[i][j]+" ");
8. System.out.println("");
9. }
10. do{
11. ordonat=true;
12. for(int i=0; i<a.length-1; i++)
13. if (a[i][i]>a[i+1][i+1]){
14. int aux=a[i][i];
15. a[i][i]=a[i+1][i+1];
16. a[i+1][i+1]=aux;
17. ordonat=false;
18. }
19. }while(!ordonat);
20. System.out.println("Matricea cu diagonala
ordonata:");
21. for(int i=0; i<a.length; i++){
22. for(int j=0; j<a[i].length; j++)
23. System.out.print(a[i][j]+" ");
24. System.out.println("");
25. }
26. }
27. }

3.5.4. Tablouri cu dimensiuni variabile

Java permite folosirea tablourilor cu dimensiuni variabile adică, a vectorilor de


vectori cu dimensiuni variabile.

Exemplu 16: Să se genereze şi să se afişeze triunghiul lui Pascal.


1. public class TrPascal{
2. public static void main(String args[]){
3. int []a[]=new int[10][];
4. a[0]=new int[1];
5. a[1]=new int[2];
6. a[0][0]=a[1][0]=a[1][1]=1;
7. for(int i=2; i<a.length; i++){
8. a[i]=new int[i+1];
9. a[i][0]=a[i][i]=1;
10. for(int j=1; j<a[i].length-1; j++)
11. a[i][j]=a[i-1][j-1]+a[i-1][j];
12. }
13. for(int i=0; i<a.length; i++){
14. for(int j=0; j<a[i].length; j++)
15. System.out.print(a[i][j]+" ");
16. System.out.println("");
17. }

31
18. }
19. }

În linia 8 se observă că, pentru fiecare linie a matricei se alocă memorie pentru
un număr variabil de elemente: pe linia 0 va fi memorat un element, pe linia 1 vor fi
memorate două elemente, etc.

3.6. Şiruri de caractere

În Java, un şir de caractere poate fi reprezentat printr-un vector format din


elemente de tip char, un obiect de tip String sau un obiect de tip StringBuffer.
Exemple echivalente de declarare a unui şir:
String str = "abc";
char data[] = {'a', 'b', 'c'};
String str = new String(data);
String str = new String("abc");
Concatenarea şirurilor de caractere se face prin intermediul operatorului +.
String str1 = "abc" + "xyz";
String str2 = "123";
String str3 = str1 + str2;

În Java, operatorul de concatenare + este extrem de flexibil în sensul că


permite concatenarea şirurilor cu obiecte de orice tip care au o reprezentare de tip
şir de caractere.
Exemplu:
System.out.print("Vectorul v are" + v.length + "
elemente");

32
4. Clase şi obiecte în Java

4.1. Referinţe

După cum am arătat în capitolul 2, o clasă este un şablon pentru mai multe
obiecte cu caracteristici asemănătoare. Un obiect este o colecţie de variabile
(atribute) şi metode asociate descrise în clasă.
Clasa poate fi asemănată cu un tip de date iar obiectul cu o variabilă. Dacă se
declară o variabilă folosind numele unei clase ca şi tip, această variabilă conţine o
referinţă către un obiect al clasei respective. Cu alte cuvinte, variabila nu va conţine
obiectul actual ci o referinţă către un obiect / o instanţă a clasei. Deoarece folosind
numele unei clase ca şi tip se declară o referinţă către un obiect, aceste tipuri poartă
numele de tipuri referinţă.
Se disting două caracteristici principale ale obiectelor în Java:
 obiectele sunt întotdeauna alocate dinamic. Durata de viaţă a unui
obiect este determinată de logica programului. Ea începe atunci când
obiectul este creat şi se termină în momentul în care obiectul nu mai
este folosit, el fiind distrus de un mecanism de curăţenie oferit de
limbajul Java – garbage collector (colectorul de gunoaie).
 obiectele nu sunt conţinute de către variabile. O variabilă păstrează o
referinţă către un obiect. o referinţă este similară cu ceea ce se
numeşte pointer în alte limbaje de programare cum ar fi C++. Dacă
există două variabile de acelaşi tip referinţă şi o variabilă este atribuită
celeilalte, ambele vor referi acelaşi obiect. Dacă informaţia din obiect se
modifică, schimbarea este vizibilă în ambele variabile.
O variabilă referinţă poate conţine şi o referinţă către nimic. Valoarea unei
asemenea variabile referinţă este null.
În Java nu se permite tipurilor referinţă să fie convertite către tipuri primitive
sau invers.

33
În capitolul 2 am văzut cum se poate lucra cu tablouri (şiruri) fără să ne punem
problema cu ce tip de date lucrăm – primitiv sau referinţă. În Java, şirurile nu sunt
tipuri primitive ci referinţă. Ele se comportă ca nişte obiecte.

4.2. Obiecte

4.2.1. Noţiuni generale

În Java obiectele sunt create prin instanţierea unei clase, cu alte cuvinte prin
crearea unei instanţe a unei clase.
Declararea obiectului se face prin:
NumeClasa numeObiect;
Exemplu:
String s;
Complex c;

În urma declarării, variabila este iniţializată cu null.


Crearea obiectului echivalentă cu instanţierea clasei se realizează prin
intermediul operatorului new şi presupune alocarea spaţiului de memorie necesar
păstrării obiectului. Adresa (referinţa) către obiectul respectiv o să fie memorată în
variabila numeObiect.
numeObiect = new NumeClasa();
Exemplu:
s=new String() ;
Complex c=new Complex(2,3);

Declararea şi crearea obiectului pot fi făcute pe aceeaşi linie.


Exemplu:
String s=new String() ;
Complex c=new Complex(2,3);

În momentul în care se realizează crearea obiectului are loc şi iniţializarea lui.


Atenţie
Spaţiul de memorie nu este alocat în momentul declarării obiectului.
Exemplu:

34
Complex c;
c.re = 10; //EROARE!
Alocarea memoriei se face doar la apelul instrucţiunii new !
Referirea valorii unei variabile se face prin
obiect.variabila

Exemplu:
Complex c = new Complex();
c.re = 2;
c.im = 3;
System.out.println("Re=" +c.re+ " Im="+c.im);

Observaţie: Accesul la variabilele unui obiect se face în conformitate cu drepturile de


acces pe care le oferă variabilele respective celorlalte clase.
Apelul unei metode se face prin
obiect.metoda([parametri])
Exemplu:
Complex c = new Complex();
c.setRe(2);
c.setIm(3);

În Java programatorul nu mai are responsabilitatea distrugerii obiectelor sale


întrucât, în momentul rulării unui program, simultan cu interpretorul Java rulează şi
un proces care se ocupă de distrugerea obiectelor care nu mai sunt folosite. Acest
proces pus la dispoziţie de platforma Java de lucru se numeşte garbage collector
(colector de gunoaie). Un obiect este eliminat din memorie de procesul de colectare
atunci când nu mai exista nici o referinţă la acesta. Referinţele (care sun de fapt
variabile) sunt distruse:
• natural, atunci când variabila respectivă nu mai este folosită (de exemplu,
la terminarea unei metode)
• explicit, dacă atribuim variabilei respective valoare null.

4.2.2. Operatorul de atribuire =

În cazul în care operatorul = este folosit împreună cu date de tip primitiv, are
loc o atribuire de valori.
Exemplu:

35
int x = 12, y = 10;
x = y;

Valoarea lui x se schimbă, primind valoarea lui y.


În cazul în care operatorul = este folosit împreună cu date de tip referinţă, are
loc tot o atribuire de valori. Atâta doar că valorile sunt în acest caz adrese.
Exemplu:
1. class Nimic{
2. int x;
3. }

4. class Test{
5. public static void main(String args[]){
6. Nimic a1=new Nimic(),a2;
7. a1.x=10;
8. a2=a1;
9. System.out.println(a1.x+" "+a2.x);
10. a1.x=5;
11. System.out.println(a1.x+" "+a2.x);
12. }
13. }

În linia 7 se modifică valoarea atributului x a obiectului a1. În linia 8 conţinutul


variabilei a1 se copiază în a2. Se afişează 10 10. Se schimbă valoarea atributului lui
a1 şi, ne-am aştepta să se afişeze 5 10 dar se afişează 5 5. Nu este greşit! În linia 8
se copiază valoarea lui a1 adică referinţa către obiect în a2. Din acest moment
există un singur obiect către care referă atât a1 cât şi a2. Orice modificare are loc
asupra obiectului, ea este văzută şi de a1 şi de a2.
Exemplu:
public class Test{
public static void main(String args[]){
int[] a1={1,2,3,4,5};
int[] a2;
a2=a1;
for(int i=0; i<a1.length; i++)
a2[i]++;
for(int i=0; i<a1.length; i++)
System.out.print(a1[i]+" ");
System.out.println("");
for(int i=0; i<a2.length; i++)
System.out.print(a2[i]+" ");
}
}

36
Rezultatul este:
23456
23456

4.2.3. Operatorul de egalitate ==

În cazul în care operatorul == este folosit împreună cu date de tip primitiv, are
loc o testare a egalităţii valorilor celor două variabile.
Exemplu:
int x = 12, y = 10, z = 12;
x == y are valoarea false; x şi y au valori diferite
x == z are valoarea true; x şi z au valori egale
În cazul în care operatorul = este folosit împreună cu date de tip referinţă, se
verifică dacă cele două variabile referă acelaşi obiect.

Exemplu:
1. class Nimic{
2. int x;
3. Nimic(int x){
4. this.x=x;
5. }
6. }

7. class Test{
8. public static void main(String args[]){
9. Nimic a1=new Nimic(1),a2=new Nimic(1);
10. if(a1==a2)
11. System.out.println("Sunt egale");
12. else
13. System.out.println("Nu sunt egale");
14. a2=a1;
15. if(a1==a2)
16. System.out.println("Sunt egale");
17. else
18. System.out.println("Nu sunt egale");
19. }
20. }

În linia 9 se creează două obiecte cu aceeaşi valoare. Totuşi testul din linia 10
are ca rezultat valoarea false. După linia 14 cele două variabile referă acelaşi
obiect şi, prin urmare, testul din linia 15 are ca rezultat valoarea true.

37
4.3. Clase

4.3.1. Definirea claselor

[public][abstract][final] class NumeClasa


[extends NumeSuperclasa]
[implements Interfata1 [, Interfata2 ... ]]
{
//corpul clasei
}
Antetul clasei:
[public][abstract][final] class NumeClasa
este format din modificatorii clasei, cuvântul rezervat class şi numele clasei
NumeClasa.
Prezenţa parantezelor [] indică faptul că ceea ce este cuprins între ele este
opţional.
Modificatorii clasei sunt:
• public: dacă o clasă este declarată public, ea este accesibilă oricărei

alte clase. Dacă modificatorul public nu apare, clasa poate fi accesată


doar de către clasele din pachetul căruia aparţine clasa (dacă nu se
specifică un anume pachet, toate clasele din directorul curent sunt
considerate a fi în acelaşi pachet). Spaţiul de căutare este definit de
variabila sistem CLASSPATH.
• abstract: o clasă declarată abstractă este o clasă şablon adică ea este
folosită doar pentru a crea un model comun pentru o serie de subclase. O
clasă trebuie declarată abstractă daca ea este incomplet implementată
adică nu toate metodele ei sunt definite. O astfel de clasă nu poate fi
instanţiată, dar poate fi extinsă de alte clase care să implementeze
metodele nedefinite. Doar clasele abstracte pot să conţină metode
abstracte (metode declarate dar nu implementate).
• final o clasă poate fi declarată finală dacă a fost complet definită şi nu se
doreşte să fie extinsă (să aibă subclase); cu alte cuvinte ea nu poate apare
în clauza extends a altei clase.

38
Observaţie: O clasă declarată atât abstractă cât şi finală generează eroare.
Dacă clasa este abstractă înseamnă că ea conţine metode neimplementate şi, prin
urmare trebuie extinsă de o altă clasă care să le implementeze. Dar, dacă ar fi şi
finală, nu ar putea fi extinsă.
După numele clasei se pot specifica, dacă este cazul, clasele moştenite şi
interfeţele implementate. O clasă poate moşteni o singură clasă, prin urmare dacă
apare clauza extends ea este urmată doar de numele unei clase. Însă, o clasă
poate implementa mai multe interfeţe, ale căror nume apar după clauza
implements şi trebuie separate prin virgulă. Asupra moştenirii şi interfeţelor se
găsesc mai multe detalii în subcapitolele „Moştenire” respectiv „Interfeţe”.
Corpul unei clase urmează după antetul clasei şi este cuprins între acolade.
Conţine:
• declararea variabilelor instanţă şi clasă care împreună formează
variabilele membru;
• definirea metodelor instanţă şi clasă care împreună formează metodele
membru.
Observaţie: variabilele unei clase pot avea acelaşi nume cu metodele clasei.

4.3.2. Variabile membru

Variabilele se declară de obicei înaintea metodelor, deşi acest lucru nu este


impus de compilator.
class NumeClasa {
//declararea variabilelor
//declararea metodelor
}
Variabilele unei clase sunt doar cele care sunt declarate în corpul clasei şi nu
în corpul unei metode. Variabilele declarate în cadrul unei metode sunt locale
metodei respective.
Declararea unei variabile presupune specificarea următoarelor lucruri:
• numele variabilei;
• tipul de date;
• nivelul de acces la acea variabilă de către alte clase;

39
• dacă este constantă sau nu;
• tipul variabilei: instanţă sau clasă
Tiparul declarării unei variabile este:
[modificatori] TipDeDate numeVariabila [ = valoareInitiala ] ;
unde un modificator poate fi :
• un specificator de acces: public, protected, private;
• unul din cuvintele rezervate: static, final, transient, volatile.
Exemple:
double x;
protected static int n;
public String s = "abcd";
private Point p = new Point(10, 10);
final long MAX = 100000L;

Detalii despre modificatorii de acces se găsesc în subcapitolul „Modificatori de


acces pentru membrii unei clase”.
Cuvintele rezervate: static, final, transient, volatile au următoarele
roluri:
• static este folosit pentru declararea variabilelor clasă.
Exemplu:
int x ; //variabilă instanţă
static int nrDeObiecteCreate; //variabilă clasă

• final este folosit pentru declararea constantelor. O constantă este o


variabilă a cărei valoare nu mai poate fi schimbată. Valoarea unei variabile
finale nu trebuie specificată neapărat la declararea ei, ci poate fi specificată
şi ulterior, după care ea nu va mai putea fi modificată.
Exemplu: se declară şi se iniţializează o variabilă finală (linia 1). Valoarea ei nu mai
poate fi modificată (linia 3).
1. final double PI = 3.14 ;
2. ...
3. PI = 3.141 // eroare la compilare

Exemplu: se declară o variabilă finală (linia 2). În linia 4 se iniţializează iar în linia 5
se doreşte modificarea valorii ei.
1. class Test {
2. final int MAX;
3. Test() {

40
4. MAX = 100; // legal
5. MAX = 200; // ilegal -> eroare la compilare
6. }
7. }

• transient este folosit la serializarea obiectelor, pentru a specifica ce


variabile membru ale unui obiect nu participa la serializare.
• volatile este folosit pentru a semnala compilatorului să nu execute
anumite optimizări asupra membrilor unei clase. Este o facilitate avansată
a limbajului Java.

4.3.3. Metode

4.3.3.1 Definirea metodelor


Metodele sunt folosite pentru descrierea comportamentului unui obiect. O
metodă se declară astfel:
[modificatori] TipReturnat numeMetoda ([argumente])
[throws TipExceptie]
{
//corpul metodei
}

4.3.3.2 Modificatorii metodelor


Un modificator poate fi :
• un specificator de acces: public, protected, private;
• unul din cuvintele rezervate: static, abstract, final, native,
synchronized.

Detalii despre modificatorii de acces se găsesc în subcapitolul „Modificatori de


acces”.
Cuvintele rezervate: static, abstract, final, native, synchronized
au următoarele roluri:
• static este folosit pentru declararea metodelor clasă.
Exemplu:
void metoda1() ; //metoda de instanta
static void metoda2(); //metoda de clasa

41
• abstract este folosit pentru declararea metodelor abstracte. O metodă
abstractă este o metodă care nu are implementare şi trebuie să aparţină
unei clase abstracte.
• final este folosit pentru a specifica faptul că acea metodă nu mai poate fi
supradefinită în subclasele clasei în care ea este definită ca fiind finală.
Acest lucru este util dacă respectiva metodă are o implementare care nu
trebuie schimbată în subclasele ei.
• native este folosit pentru refolosirea unor funcţii scrise în alt limbaj de
programare decât Java (C de exemplu).
• synchronized este folosit în cazul în care se lucrează cu mai multe fire de
execuţie iar metoda respectivă se ocupă cu partajarea unei resurse
comune. Are ca efect construirea unui semafor care nu permite executarea
metodei la un moment dat decât unui singur fir de execuţie.

4.3.3.3 Tipul returnat de o metodă


Metodele pot să returneze sau nu o valoare (un obiect) la terminarea lor. Tipul
valorii returnate poate fi atât un tip primitiv de date (int, double, etc.) cât şi o referinţă
la un obiect al unei clase. În cazul în care o metoda nu returnează nimic atunci
TipReturnat este void.
Exemplu: void afisareRezultat()

Returnarea valorii de către o metodă se realizează prin intermediul instrucţiunii


return.

Dacă o metodă returnează o valoare de un tip de bază atunci tipul ei trebuie să


coincidă cu TipReturnat, în caz contrar se primeşte eroare la compilare.

Exemplu: Metodă care calculează maximul a două numere


public int max(int a, int b){
return a>b?a:b;
}

Dacă valoarea returnată este o referinţă la un obiect al unei clase, atunci clasa
obiectului returnat trebuie să coincidă sau să fie o subclasă a clasei specificate la
declararea metodei.

42
4.3.3.4 Parametrii unei metode
După cum am văzut, numele clasei este urmat de lista parametrilor
(argumentelor), listă care este opţională (o metodă poate să nu aibă parametrii).
Parametrii sunt specificaţi prin numele şi tipul lor, fiind despărţiţi unul de altul prin
virgulă.
NumeMetoda([tip1 argument1], [tip2
argument2] ... )

Tipul de date al unui argument poate fi orice tip valid al limbajului, atât tip
primitiv de date cât şi referinţă la un obiect.
Exemplu:
void adaugarePersoana(String nume, int varsta, float
salariu){
...
}

unde String este tip referinţă, int şi float sunt tipuri primitive.
În Java o metodă nu poate primi un număr variabil de argumente, ceea ce
înseamnă că apelul unei metode trebuie să se facă cu specificarea exactă a
numărului şi tipurilor argumentelor.
Nu este permisă gruparea parametrilor după tipul lor.
Exemplu:
public int max(int a,b){...} //este greşit
public int max(int a, int b){ ...} //este corect

Numele argumentelor primite trebuie să difere între ele şi nu trebuie să


coincidă cu numele nici uneia din variabilele locale ale metodei. Pot însă, să coincidă
cu numele variabilelor membre ale clasei caz în care diferenţierea se va face prin
intermediul variabile this. Vezi subcapitolul „Obiectul this”
Exemplu:
class Complex{
int re,im;
public schimba(int re, int im){
this.re = re;
this.im = im;
}
}

Atenţie: În Java argumentele sunt trimise doar prin valoare !!!

43
Asta însemnă că metoda recepţionează doar valorile variabilelor primite ca
parametri. Când argumentul are tip primitiv de date metoda nu-i poate schimba
valoarea decât local (în cadrul metodei); la revenirea din metodă variabila are
aceeaşi valoare ca la apelul iniţial al metodei (modificările făcute în cadrul metodei
sunt pierdute). Când argumentul este de tip referinţă metoda nu poate schimba
referinţa obiectului însă poate schimba variabilele membru ale respectivului obiect.
Prin urmare, dacă dorim ca o metodă să schimbe starea (valoarea) unui argument
primit, atunci el trebuie să fie neapărat de tip referinţă (trebuie să fie un obiect!).

4.3.4. Constructorii unei clase

Constructorii unei clase sunt metode speciale care au acelaşi nume cu cel al
clasei, nu returnează nici o valoare şi sunt folosiţi pentru iniţializarea obiectelor
acelei clase în momentul instanţierii lor. Constructorii controlează modul în care un
obiect este creat şi iniţializat.
Class COMPLEX {
COMPLEX() {
//constructor
}
}

O clasă poate avea unul sau mai mulţi constructori care trebuie însă să difere
prin lista de parametri primiţi. Astfel sunt permise diferite tipuri de iniţializări ale
obiectului la crearea sa, în funcţie de numărul parametrilor cu care este apelat
constructorul.
Exemplu: Clasa COMPLEX are trei constructori: unul fără parametrii definit în liniile
3-5, altul cu doi parametrii definit în liniile 6-8, altul cu un parametru definit în liniile 9-
11.
1. class COMPLEX {
2. double re, im;

3. COMPLEX () {
4. re=im=0;
5. }
6. COMPLEX (double r, double i ) {
7. re=r; im=i;
8. }
9. COMPLEX (double r) {
10. re=r; im=0;

44
11. }
12. }

Constructorii sunt apelaţi automat la instanţierea unui obiect. În cazul în care


dorim să apelăm explicit constructorul unei clase folosim metoda this(argumente),
care apelează constructorul corespunzător (ca argumente) al clasei respective.
Această metodă este folosită atunci când sunt implementaţi mai mulţi constructori
pentru o clasă pentru a nu repeta secvenţele de cod scrise la constructorii cu mai
puţine argumente.

Exemplu: În clasa COMPLEX a fost definit constructorul cu doi parametrii. Ceilalţi doi
constructori fac apel la constructorul cu doi parametrii în liniile 4 şi 10.
1. class COMPLEX {
2. double re, im;

3. COMPLEX () {
4. this(0,0);
5. }
6. COMPLEX (double r, double i ) {
7. re=r; im=i;
8. }
9. COMPLEX (double r) {
10. this(r,0);
11. }
12. }

Dacă într-o clasă nu este defineşte nici un constructor, sistemul îi creează


automat un constructor implicit care nu primeşte nici un argument. El iniţializează
variabilele membru de tipuri primitive cu 0 şi pe cele de tipuri referinţă cu null. Deci
prezenţa constructorilor în corpul unei clase nu este obligatorie. Dacă într-o clasă a
fost definit cel puţin un constructor cu parametrii, atunci constructorul implicit (fără
parametrii) nu va mai fi creat automat.

Exemplu: În clasa COMPLEX nu a fost definit nici un constructor. În linia 5 se


apelează constructorul implicit creat automat pentru clasa Complex.
1. class COMPLEX {
2. double re, im;
3. }
4. ...
5. COMPLEX c= new COMPLEX ();

45
Exemplu: În clasa COMPLEX au fost definiţi doi constructori: cu un parametru şi cu
doi parametrii. În linia 11 se apelează constructorul fără parametrii. Această linie
generează o eroare deoarece nu există constructor fără parametrii – el nu a fost
creat implicit.
1. class COMPLEX {
2. double re, im;
3. COMPLEX (double r, double i ) {
4. re=r; im=i;
5. }
6. COMPLEX (double r) {
7. this(r,0);
8. }
9. }
10. ...
11. COMPLEX c= new Complex(); //eroare

Constructorii unei clase pot avea următorii specificatori de acces:


private: nici o altă clasă nu poate instanţia obiecte ale acestei clase. O astfel
de clasă poate conţine metode publice care să-şi creeze propriile obiecte şi să le
returneze altor clase;
public: orice clasă poate crea instanţe ale clasei respective;
protected: doar subclasele pot crea obiecte de tipul clasei respective.
Dacă specificatorul lipseşte, doar clasele din acelaşi pachet pot crea instanţe
ale clasei respective.

4.3.5. Obiectul this

Obiectul this este o referinţă către obiectul curent.


Este folosit în trei situaţii:
• în cadrul unei metode care are parametrii cu nume identic cu numele
atributelor clasei. În această situaţie, trebuie făcută o diferenţă între cele
două. Cu this se califică atributele clasei.
Exemplu: Metoda schimba primeşte doi parametrii cu acelaşi nume cu atributele
clasei: re şi im.
1. class Complex{
2. int re,im;
3. public schimba(int re, int im){

46
4. this.re = re;
5. this.im = im;
6. }
7. }

• în cadrul constructorilor pentru a apela ceilalţi constructori ai clasei.


Exemplu: În liniile 4 şi 11 se apelează constructorul cu doi parametrii definit în liniile
6-9.
1. public class Rational{
2. private long m,n;
3. public Rational(){
4. this(0,1);
5. }
6. public Rational(long m,long n){
7. this.m=m;
8. this.n=n;
9. }
10. public Rational(long m){
11. this(m,1);
12. }
13. }

• pentru a testa că obiectul primit ca parametru nu este chiar obiectul curent.

Exemplu: Clasa ContBancar conţine metoda transfer în care se transferă suma


de bani din contul primit în contul curent – liniile 10, 11. În linia 15 se creează un
obiect ContBancar. În linia 16 se apelează metoda transfer a obiectului c cu
parametru c. Asta înseamnă că, suma din contul c va fi transferată tot în contul c.
Citind cu atenţie codul din liniile 10, 11 observăm că se adună suma primită
(c.suma) la suma actuală (this.suma) – în cazul nostru, contul îşi dublează suma,
după care suma contului primit (c.suma) se face zero.
1. public class ContBancar{
2. private long suma;
3. public ContBancar(){
4. this(0);
5. }
6. public ContBancar(long suma){
7. this.suma=suma;
8. }
9. public void transfer(ContBancar c){
10. this.suma+=c.suma;
11. c.suma=0;
12. }
13. }

47
14. ...
15. ContBancar c=new ContBancar(100);
16. c.transfer(c);

Din punct de vedere logic, nu este corect. Ar trebui ca înaintea începerii


transferului de bani să se verifice dacă nu cumva este vorba despre acelaşi cont,
caz în care nu ar trebui să se întâmple nimic. Metoda transfer ar arăta astfel:

1. public void transfer(ContBancar c){


2. if (this == c)
3. return;
4. this.suma+=c.suma;
5. c.suma=0;
6. }
7. }

În linia 2, this reprezintă obiectul curent iar c obiectul primit ca parametru.

4.3.6. Supraîncărcarea şi supradefinirea metodelor

• supraîncărcarea (overloading): în cadrul unei clase pot exista metode cu


acelaşi nume cu condiţia ca ele să difere prin lista parametrilor – diferenţa
constă în numărul parametrilor sau în tipul lor. Astfel la apelul metodei cu
acel nume se poate face distincţia între ele şi se stabileşte în mod unic
care dintre ele se execută.
Exemplu: În clasa Maxim sunt definite două metode max cu doi respectiv cu trei
parametrii.
1. public class Maxim {
2. public static int max(int a, int b){
3. return a>b?a:b;
4. }

5. public static int max(int a, int b, int c){


6. int m=a>b?a:b;
7. m=m>c?m:c;
8. return m;
9. }

10. public static void main(String args[]){


11. int a=12, b=5,c=90,m;
12. m=max(a,b);
13. System.out.println("Max. dintre "+a+" si
"+b+" este: "+m);

48
14. m=max(a,b,c);
15. System.out.println("Max. dintre "+a+",
"+b+" si "+c+" este: "+m);
16. }
17. }

.
• supradefinirea (overriding): o subclasă a unei clase poate rescrie o metodă
a clasei părinte, prin implementarea unei metode cu acelaşi antet ca al
superclasei.

4.3.7. Modificatori de acces pentru membrii unei clase

Sunt cuvinte rezervate ce controlează accesul celorlalte clase la membrii unei


clase. Modificatoriii de acces pentru variabilele şi metodele unei clase sunt: public,
protected, private şi cel implicit. Nivelul lor de acces este dat în tabelul de mai
jos:
Modificator Clasă Subclasă Pachet Altundeva
private x
protected x x x
public x x x x
implicit x x

După cum se vede în tabelul de mai sus, modificatorii au următoarele


semnificaţii.
private – un membru declarat private este accesibil doar în clasa în care
este declarat;
protected – un membru declarat protected este accesibil oricărei clase
care aparţine aceluiaşi pachet ca şi clasa în care este declarat membrul; de
asemenea, este accesibil şi oricărei subclase a clasei respective;
public – un membru declarat public este accesibil oricărei clase indiferent
de locul unde se află ea.
Dacă modificatorul unui membru lipseşte, se consideră implicit un modificator
„friendly” care dă acces oricărei clase din pachetul respectiv.
Exemple:
private int re,im;
protected String secret;
public float[] elemente;

49
long x;
private void metodaInterna();
public void setRe(int re);

Observaţie: În cazul în care declarăm un membru "protected" atunci accesul la


acel membru din subclasele clasei în care a fost declarată variabila depinde şi de
pachetul în care se găseşte subclasa: dacă sunt în acelaşi pachet accesul este
permis, dacă nu sunt în acelaşi pachet accesul nu este permis decât pentru obiecte
de tipul subclasei.

4.3.8. Membrii instanţă şi membrii clasă

O clasă Java poate conţine două tipuri de variabile şi metode :


• instanţă: declarate fără modificatorul static, specifice fiecărei
instanţe
• clasă: declarate cu modificatorul static, specifice clasei
Dacă o variabilă este declarată statică atunci există doar o copie a variabilei
asociată cu clasa respectivă şi nu mai multe copii ale ei asociate cu fiecare instanţă
a clasei.
O variabilă clasă există şi poate fi folosită chiar dacă clasa nu a fost instanţiată
spre diferenţă de variabilele instanţă care există doar după ce a fost creată o
instanţă a clasei.
Pentru variabilele statice sistemul alocă o singură zonă de memorie la care au
acces toate instanţele clasei respective, ceea ce înseamnă că dacă un obiect
modifică valoarea unei variabile statice, modificarea va fi văzută de către toate
celelalte obiecte. Variabilelor statice nu li se alocă dinamic memorie; memoria pentru
ele este rezervată înainte ca oricare obiect al clasei să fie creat. În cazul variabilelor
instanţă, la fiecare creare a unei instanţe a clasei sistemul alocă o zonă de memorie
separată pentru memorarea valorii ei.

Exemplu: Clasa Punct conţine două variabile instanţă declarate pe linia 2 şi o


variabilă clasă declarată şi iniţializată pe linia 3. Constructorul clasei Punct
iniţializează variabilele instanţă şi incrementează variabila clasă. Cu alte cuvinte,
variabila nr_puncte va contoriza câte ”puncte” (instanţe ale clasei Punct) se

50
creează. În clasa TestPunct se creează trei obiecte de tipul Punct şi se afişează
valoarea variabilei clasă nr_puncte. Trebuie remarcat că variabila nr_puncte
este accesată prin intermediul numelui clasei.
1. class Punct{
2. int x, y;
3. static int nr_puncte=0;

4. Punct(int xx, int yy){


5. x=xx; y=yy;
6. nrpuncte++;
7. }
8. }

9. class TestPunct{
10. public static void main(String args[]){
11. Punct p1=newPunct(10, 10);
12. Punct p2=newPunct(20, 20);
13. Punct p3=newPunct(30, 30);
14. System.out.println(Punct.nr_puncte);
15. }
16. }

Întrucât metodele clasă nu depind de starea obiectelor clasei respective, apelul


lor se poate face prin:
NumeClasa.metodaStatica();
sau
NumeClasa obiect = new NumeClasa();
obiect.metodaStatica();
În cazul metodelor instanţă apelul nu se poate face decât prin intermediul unui
obiect:
NumeClass.metodaInstanta(), //ilegal
NumeClasa obiect = new NumeClasa();
obiect. metodaDeInstanta(); //legal

Exemplu: În clasa Cerc sunt definite: o metodă instanţă în liniile 6-11 care
returnează cercul cu raza cea mai mare şi o metodă clasă în liniile 12-18 care
returnează cercul cu raza cea mai mare dintre cele două cercuri primite ca
parametru. În liniile 21, 22 sunt create două cercuri a şi b cu raze diferite. În linia 23
este apelată metoda maimare a obiectului a. În linia 24 este apelată metoda
maimare a clasei Cerc.
1. class Cerc{
2. double x,y,r;

51
3. Cerc(double x, double y, double r) {
4. this.x=x; this.y=y; this.r=r;
5. }

6. Cerc maimare(Cerc c) {
7. if(c.r>r)
8. return c;
9. else
10. return this;
11. }

12. static Cerc maimare(Cerc a, Cerc b) {


13. if (a.r>b.r)
14. return a;
15. else
16. return b;
17. }
18. }
19.
20. ...
21. Cerc a=new Cerc(10, 10, 50);
22. Cerc b=new Cerc(20, 20, 100);
23. Cerc c = a.maimare(b);
24. Cerc d = Cerc.maimare(a,b);

Metodele clasă nu pot accesa câmpuri sau metode instanţă.


Metodele instanţă pot accesa atât membrii clasă cât şi instanţă.

Membrii clasă (statici) sunt folosiţi pentru a pune la dispoziţie valori şi metode
independente de starea obiectelor dintr-o anumită clasă.
Spre deosebire de C++, în Java nu putem avea funcţii globale definite ca
atare, întrucât "orice este un obiect". Din acest motiv şi metodele care au o
funcţionalitate globală trebuie implementate în cadrul unei clase. Acest lucru se va
face prin intermediul metodelor clasă (globale), deoarece acestea nu depind de
starea particulară a obiectelor din clasa respectivă. De exemplu, să considerăm
funcţia globală sqrt care extrage radicalul dintr-un număr şi care se găseşte în clasa
Math. Dacă nu ar fi fost funcţie clasă, apelul ei ar fi trebuit făcut astfel:
Math m = new Math();
double rad121 = m.sqrt(121);
ceea ce ar fi fost extrem de neplăcut pentru programatori. Fiind însă funcţie
statică ea poate fi apelată prin: Math.sqrt(121).

52
4.3.9. Argumente în linia de comandă

În sfârşit suntem în măsură să descifrăm antetul metodei main.


public static void main(String args[])
Metoda main primeşte un şir de String-uri ca parametru. Prin intermediul lui
o aplicaţie Java poate primi oricâte argumente din linia de comandă în momentul
lansării ei. Aceste argumente sunt utile pentru a permite utilizatorului să specifice
diverse opţiuni legate de funcţionarea aplicaţiei sau să furnizeze anumite date iniţiale
programului.
Argumentele din linia de comandă sunt introduse la lansarea unei aplicaţii,
fiind specificate după numele aplicaţiei şi sunt separate prin spaţiu.
Formatul general pentru lansarea unei aplicaţii care primeşte argumente din
linia de comandă este:
java NumeAplicatie [arg1 arg2 . . . argn]
Evident, o aplicaţie poate să nu primească nici un argument sau poate să
ignore argumentele primite din linia de comandă.
În momentul lansării unei aplicaţii interpretorul parcurge linia de comandă cu
care a fost lansată aplicaţia şi, în cazul în care există argumente, îi transmite
aplicaţiei sub forma şirului de String-uri.
Numărul argumentelor primite de un program este dat de dimensiunea
vectorului args –args.length:
numarArgumente = args.length ;

Exemplu: Afişarea argumentelor primite din linia de comandă


public class ArgLinCom {
public static void main (String[] args) {
for (int i = 0; i < args.length; i++)
System.out.println(args[i]);
}
}

Un apel de genul:
java ArgLinCom Nu mai vine primavara odata
va produce următorul rezultat:
Nu
mai
vine
primavara
odata

53
Dacă o anumită parte din şirul de intrare este cuprinsă între ghilimelele se
interpretează ca un singur argument, spaţiile fiind ignorate.
Una apel de genul:
java ArgLinCom "Nu mai vine" primavara odata
va produce următorul rezultat:
Nu mai vine
primavara
odata
Dacă se doreşte ca din linia de comandă să fie transmise argumente
numerice, acestea sunt primite de metoda main sub forma unui vector de String-
uri. Ulterior ele trebuie convertite din String-uri în numere. Acest lucru se
realizează cu metode de tipul parseXXX aflate în clasa XXX corespunzătoare tipului
în care vrem să facem conversia: Integer, Float, Double, etc.
Exemplu:
1. public class Maxim {
2. public static int max(int a, int b){
3. return a>b?a:b;
4. }

5. public static int max(int a, int b, int c){

6. int m=a>b?a:b;
7. m=m>c?m:c;
8. return m;
9. }

10. public static void main(String args[]){


11. if (args.length!=3){
12. System.out.println("Nu ati introdus trei
numere");
13. return;
14. }
15. int a=Integer.parseInt(args[0]),
16. b=Integer.parseInt(args[1]),
17. c=Integer.parseInt(args[2]),
18. m;
19. m=max(a,b);
20. System.out.println("Maximul dintre "+a+" si
"+b+" este: "+m);
21. m=max(a,b,c);
22. System.out.println("Maximul dintre "+a+",
"+b+" si "+c+" este: "+m);
23. }
24. }

54
În linia 11 se verifică dacă au fost transmişi atâţia parametrii câţi sunt necesari.
În liniile 15-17 se convertesc argumentele în întregi.

4.4. Moştenirea

4.4.1. Principiul moştenirii

După încapsularea datelor, este al doilea principiu de bază al programării


orientate pe obiecte. Moştenirea este folositoare deoarece reduce rescrierea codului.
Adică, o clasă poate fi moştenită de către o altă clasă (toate caracteristicile primei
clase se regăsesc şi în a doua clasă). Noua clasă îşi poate modifica o parte din
comportament, poate adăuga ceva nou sau poate ignora ceea ce este neinteresant.
Această idee provine din lumea înconjurătoare. De exemplu, primul model de
maşină a fost mult timp gândit şi dificil de construit. Evident că nu a atins
perfecţiunea şi, omul a dorit repede ceva mai performant şi mai frumos. Prin urmare,
s-a trecut la crearea celui de-al doilea model. Ar fi o naivitate să credem că lucrul la
acest al doilea model a fost luat de la zero. De fapt, s-a pornit de la primul model şi
s-a încercat o îmbunătăţire a lui în diferite direcţii – s-a redus ceea ce nu era bun, s-
au adăugat elemente noi şi au fost făcute modificări. Astfel s-a născut şi al doilea
model. Pornind de la el, în acelaşi stil, s-au creat noi modele. Şi maşinile elegante pe
care le vedem azi rulând cu viteză pe şosele se trag tot din acea primă maşină. Baza
este aceeaşi, „puţin” îmbunătăţită.
În Java pentru a crea o clasă nouă trebuie specificate: clasa moştenită şi
diferenţele faţă de clasa moştenită. Clasa moştenită se specifică în clauza extends.
modificator NumeClasa extends ClasaDeBaza

Clasa moşteneşte toate metodele accesibile şi variabilele superclasei sale.

55
Exemplu: Următoare ierarhie de clase:
se exprimă în Java astfel: A
class A{
...
}
B
class B extends A{
...
}
class C extends B{
... C D
}
class D extends B{
...
}

Dacă clauza extends lipseşte, implicit clasa moşteneşte clasa Object.


Observaţie: În Java moştenirea multiplă nu este permisă. Adică o clasă poate
să moştenească o singură clasă nu mai multe.
Prin urmare, orice clasă are o superclasă şi poate avea una sau mai multe
subclase.
În exemplul nostru avem:
• clasa A este subclasă a clasei Object şi are o subclasă: clasa B.
• clasa B este subclasă a clasei A şi are o subclasă: clasa C.
• clasele C şi D sunt subclase ale clasei B şi nu au subclase.
Nu este permisă o asemenea moştenire (moştenire multiplă):

A B

Avantajele creării unei ierarhii de clase


- funcţionalitatea comună a mai multor clase se pune în superclase. Acest
aranjament permite ca funcţionalitatea să fie refolosită în mod repetat
deoarece fiecare subclasă primeşte informaţia comună din superclasă.

56
- schimbarea sau inserarea unei clase în partea de sus a ierarhiei
determină automat schimbări în comportamentul claselor de jos
Ce se întâmplă când o clasă conţine o metodă care are acelaşi antet cu
metoda unei superclase? Este executată prima metodă întâlnită – căutarea făcându-
se pornind de la baza ierarhiei în sus. Datorită acestui fapt, se pot scrie metode care
să ascundă metodele din superclase.
Dacă o metodă din superclasă nu este rescrisă ea va fi luată ca atare de
subclasă. Nu acelaşi lucru se întâmplă şi cu constructorii. Fiecare clasă derivată
trebuie să îşi definească proprii constructori. Dacă nu se scrie nici un constructor în
subclasă, atunci se generează constructorul implicit.

Exemplu: Se definesc două clase Rational şi RationalIred care moşteneşte


clasa Rational. În linia 15 se construieşte un obiect al clasei Rational prin
apelarea constructorului cu doi parametrii. Acest constructor există deci, totul este în
regulă. În linia 16 se doreşte construirea unui obiect al clasei RationalIred tot
prin apelarea constructorului cu doi parametrii. Dar, în acest caz este generată o
eroare deoarece clasa RationalIred nu are definit constructorul cu doi parametrii.
8. public class Rational{
9. private long m,n;
10. public Rational(){
11. m=0; n=1;
12. }
13. public Rational(long m,long n){
14. this.m=m;
15. this.n=n;
16. }
17. }

18. public class RationalIred extends Rational {


19. ...
20. }

21. ...

22. Rational r = new Rational(2,5);


23. RationalIred r1 = new RationalIred(2,5);

Pentru ca linia 16 să nu mai genereze eroare, clasa RationalIred trenbuie


să arate astfel:

1. public class RationalIred extends Rational {

57
2. public RationalIred(){
3. m=0; n=1;
4. }

5. public RationalIred(long m,long n){


6. this.m=m;
7. this.n=n;
8. }
9. }

În cadrul unei metode a subclasei care supradefineşte o metodă din


superclasă se poate apela metoda supradefinită (a superclasei), folosind super.

Exemplu: Reluăm exemplul precedent. Subclasa RationalIred conţine ca şi


superclasa Rational doi constructori: unul fără parametrii şi unul cu doi parametrii.
Constructorii subclasei au aceeaşi funcţionalitate cu cei ai superclasei. În linia 16 se
apelează constructorul fără parametrii ai superclasei Rational. În linia 19 se
apelează constructorul cu doi parametrii ai superclasei Rational. Pe lângă cei doi
constructori care au aceeaşi funcţionalitate în ambele clase, a mai fost definită o
metodă produs care este suprascrisă în subclasă. Metoda produs din subclasă
trebuie să facă ceva în plus faţă de metoda superclasei. Prin urmare, „se copiază ”
comportamentul metodei din liniile 10-12 şi se adaugă ceva în plus. „Copierea” se
realizează în linia 22, iar adăugarea în linia 23. Această „copiere” constă în apelarea
metodei din superclasă.
1. public class Rational{
2. public long m,n;
3. public Rational(){
4. m=0; n=1;
5. }
6. public Rational(long m,long n){
7. this.m=m;
8. this.n=n;
9. }
10. public void produs(){
11. System.out.println("Inmultesc doua numere
rationale");
12. }
13. }

14. public class RationalIred extends Rational {


15. public RationalIred(){
16. super();
17. }

58
18. public RationalIred(long m,long n){
19. super(m,n);
20. }
21. public RationalIred produs(RationalIred r){
22. super.produs(r);
23. System.out.println("si ireductibile");
24. }
25. }

Observaţii:
Când se doreşte apelarea constructorului superclasei se foloseşte doar
super(...).
Când se doreşte apelarea unei metode a superclasei se foloseşte
super.NumeMetoda(...).

4.4.2. Interfeţe

Interfeţele duc conceptul de clasă abstractă cu un pas înainte prin eliminarea


oricărei implementări a metodelor, punând în practică unul din conceptele OOP de
separare a modelului unui obiect (interfaţa) de implementarea sa.
O interfaţă Java defineşte un set de metode dar nu specifică nici o
implementare pentru ele. O clasă care implementează o interfaţă trebuie obligatoriu
să definească toate metodele interfeţei. Prin urmare, o interfaţă este o colecţie de
metode fără implementare şi declaraţii de constante.
Definirea unei interfeţe se face prin intermediul cuvântului cheie interface:
[public] interface NumeInterfata
extends SuperInterfata1 [,extends
SuperInterfata2...]]
{
//corpul interfetei:constane si metode abstracte
}
O interfaţă poate fi declarată doar public. O clasă poate extinde oricâte
interfeţe. Acestea se numesc superinterfeţe şi sunt separate prin virgulă.
Corpul unei interfeţe conţine:
• constante: acestea pot fi sau nu declarate cu modificatorii public,
static şi final care sunt impliciţi; nici un alt modificator nu poate apărea
în declaraţia unei variabile a unei interfeţe. Constantele dintr-o interfaţă
trebuie obligatoriu iniţializate.

59
Exemplu:
1. interface NumeInterfata {
2. int x = 100; //corect
3. public static final int y = 100; //corect
4. private z=100; //incorect
5. int a; //incorect
6. }

• metode fără implementare: acestea pot fi sau nu declarate cu


modificatorul public care este implicit; nici un alt modificator nu poate
apărea în declaraţia unei metode a unei interfeţe.
Exemplu:
7. interface NumeInterfata {
8. void metoda1(); //corect
9. public void metoda2(); //corect
10. private void metoda3(); //incorect
11. }

Atenţie:
Variabilele şi metodele unei interfeţe sunt implicit publice chiar dacă nu sunt
declarate cu modificatorul public.
Variabilele unei interfeţe sunt implicit constante chiar dacă nu sunt declarate
cu modificatorii static şi final.
Implementarea unei interfeţe se face prin intermediul cuvântului cheie
implements:
class NumeClasa implements NumeInterfata
sau
class NumeClasa implements Interfata1, Interfata2...
O clasă poate implementa oricâte interfeţe. O clasă care implementează o
interfaţă trebuie obligatoriu să definească toate metodele interfeţei.

Exemplu: Se defineşte o interfaţă FigGeom care este implementată de clasa


Cerc şi clasa Dreptunghi. Clasa Patrat moşteneşte clasa Dreptunghi, iar
clasa Pataratel moşteneşte clasa Patrat.
1. interface FigGeom{
2. void desen();
3. void arie();
4. }

5. class Cerc implements FigGeom{

60
6. int r;
7. Cerc(int r){
8. this.r=r;
9. System.out.println("Constructor cerc "+r);
10. }
11. public void desen(){
12. System.out.println("Deseneaza cercul "+r);
13. }
14. public void arie(){
15. double s=Math.PI*r*r;
16. System.out.println("Cercul "+r+" are aria "+s);
17. }
18. }

19. class Dreptunghi implements FigGeom{


20. int L,l;
21. Dreptunghi(){}
22. Dreptunghi(int L,int l){
23. this.L=L;
24. this.l=l;
25. System.out.println("Constructor dreptunghi "+L+"
"+l);
26. }
27. public void desen(){
28. System.out.println("Deseneaza dreptunghiul "+L+"
"+l);
29. }
30. public void arie(){
31. double s=L*l;
32. System.out.println("Dreptunghiul "+L+" "+l+" are
aria "+s);
33. }
34. }

35. public class TestFigGeom{


36. public static void main(String args[]){
37. FigGeom c=new Cerc(10),
38. d=new Dreptunghi(20,25),
39. c.desen();
40. c.arie();
41. d.desen();
42. d.arie();
43. }
44. }

Rezultatul execuţiei este:


Constructor cerc 10
Constructor dreptunghi 20 25
Deseneaza cercul 10
Cercul 10 are aria 314.1592653589793
Deseneaza dreptunghiul 20 25

61
Dreptunghiul 20 25 are aria 500.0

Diferenţa dintre o interfaţă şi o clasă abstractă


La prima vedere o interfaţă nu este altceva decât o clasă abstractă în care
toate metodele sunt abstracte (nu au nici o implementare). Deosebirea dintre ele
constă în faptul că unele clase sunt forţate să extindă o anumită clasă (de exemplu
orice applet trebuie să fie subclasă a clasei Applet) şi nu ar mai putea să extindă o
clasă abstractă deoarece în Java nu există decât moştenire simplă. Fără folosirea
interfeţelor nu am putea forţa clasa respectiva să respecte un anumit protocol.
La nivel conceptual diferenţa constă în:
• extinderea unei clase abstracte forţează o relaţie între clase;
• implementarea unei interfeţe specifică doar necesitatea implementării
unor anumite metode.

4.5. Probleme

Exemplu 1: Exemplificarea moştenirii.


class Masina {
private String s = new String("Masina");

public void append(String a){


s += a;
}

public void porneste(){


append(" porneste()");
}

public void merge(){


append(" merge()");
}
public void opreste(){
append(" opreste()");
}
public void print(){
System.out.println(s);
}
}

class BMW extends Masina {


//schimbarea unei metode
public void opreste() {
append(" BMW opreste sigur()");

62
super.opreste(); // apelul metodei clasei de baza
}

// adaugarea unei metode noi


public void franeazaBine(){
append(" franeazaBine()");
}
}

// testarea noii clase


public class TestMasina{
public static void main(String[] args) {
BMW bmw = new BMW();
/* System.out.println(bmw.s); //Eroare s nu apartine lui
bmw */
bmw.porneste();
bmw.merge();
bmw.franeazaBine();
bmw.opreste();
bmw.print();
}
}
Rezultatul execuţiei este:
Masina porneste() merge() franeazaBine() BMW opreste sigur()
opreste()

Exemplu 2: Exemplificarea moştenirii şi a polimorfismului.


abstract class FigGeom{
abstract void desen();
abstract void arie();
}

class Cerc extends FigGeom{


int r;
Cerc(int r){
this.r=r;
System.out.println("Constructor cerc "+r);
}
void desen(){
System.out.println("Deseneaza cercul "+r);
}
void arie(){
double s=Math.PI*r*r;
System.out.println("Cercul "+r+" are aria "+s);
}
}

class Dreptunghi extends FigGeom{


int L,l;

63
Dreptunghi(){}
Dreptunghi(int L,int l){
this.L=L;
this.l=l;
System.out.println("Constructor dreptunghi "+L+"
"+l);
}
void desen(){
System.out.println("Deseneaza dreptunghiul "+L+"
"+l);
}
void arie(){
double s=L*l;
System.out.println("Dreptunghiul "+L+" "+l+" are
aria "+s);
}
}

class Patrat extends Dreptunghi{


int l;
Patrat(int l){
// super(l,l);
this.l=l;
System.out.println("Constructor patrat "+l);
}
void desen(int k){
System.out.println("Deseneaza patratul "+l+" indice
"+k);
}
void arie(){
double s=l*l;
System.out.println("Patrat "+l+" are aria "+s);
}
}

class Patratel extends Patrat{


int l;
Patratel(int l){
super(l);
this.l=l;
System.out.println("Constructor patratel "+l);
}
void desen(int k){
System.out.println("Deseneaza patratelul "+l+"
indice "+k);
}
void arie(){
double s=l*l;
System.out.println("Patratelul "+l+" are aria "+s);
}
}

64
public class TestFigGeom{
public static void main(String args[]){
FigGeom c=new Cerc(10),
d=new Dreptunghi(20,25),
p=new Patrat(30),
pm=new Patratel(40);
c.desen();
c.arie();
d.desen();
d.arie();
// p.desen(100); da eroare p fiind o figura
geometrica
p.desen(); //se apeleaza desen din dreptunghi
p.arie();
pm.desen(); //se apeleaza desen din dreptunghi
pm.arie();
Patrat p1=new Patrat(300);
p1.desen(100); //este ok
p1.arie();

}
}

Rezultatul afişat este:


Constructor cerc 10
Constructor dreptunghi 20 25
Constructor patrat 30
Constructor patrat 40
Constructor patratel 40
Deseneaza cercul 10
Cercul 10 are aria 314.1592653589793
Deseneaza dreptunghiul 20 25
Dreptunghiul 20 25 are aria 500.0
Deseneaza dreptunghiul 0 0
Patrat 30 are aria 900.0
Deseneaza dreptunghiul 0 0
Patratelul 40 are aria 1600.0
Constructor patrat 300
Deseneaza patratul 300 indice 100
Patrat 300 are aria 90000.0

65
Exemplu 3: Ilustrează ordinea iniţializărilor
class Floare {
Floare(int nr) {
System.out.println("Floare(" + nr + ")");
}
void actiune(String fel) {
System.out.println("actiune(" + fel + ")");
}
}

class Vaza {
static Floare f1 = new Floare(1); //var STATICA
Vaza() {
System.out.println("Vaza()");
f2.actiune("Floare in vaza");
}
void pozitie(String loc) {
System.out.println("pozitie(" + loc + ")");
}
static Floare f2 = new Floare(2); //var STATICA
}

class Gradina {
Floare f3 = new Floare(3);
static Floare f4 = new Floare(4); //var STATICA
Gradina() {
System.out.println("Gradina()");
f4.actiune("Floare doarme");
}
void aspect(String tip) {
System.out.println("aspect(" + tip + ")");
}
static Floare f5 = new Floare(5); //var STATICA
}

public class StaticInit {


public static void main(String[] args) {
System.out.println(
"Creaza o Gradina() noua in main");
new Gradina();
System.out.println(
"Creaza o Gradina() noua in main");
new Gradina();
v2.pozitie("pe masa");
g3.aspect("frumos");
}
static Vaza v2 = new Vaza(); //var STATICA
static Gradina g3 = new Gradina(); //var STATICA
}
Rezultatul execuţiei este:

66
Floare(1)
Floare(2)
Vaza()
actiune(Floare in vaza)
Floare(4)
Floare(5)
Floare(3)
Gradina()
actiune(Floare doarme)
Creaza o Gradina() noua in main
Floare(3)
Gradina()
actiune(Floare doarme)
Creaza o Gradina() noua in main
Floare(3)
Gradina()
actiune(Floare doarme)
pozitie(pe masa)
aspect(frumos)

Exemplu 4: Exemplificarea moştenirii. Clasa Rational implementează lucrul cu


numere raţionale. Clasa RationalIred moşteneşte clasa Rational şi
implementează lucrul cu numere raţionale ireductibile.
public class Rational{
private long m,n;

public Rational(){
this(1,0);
}

public Rational(long m,long n){


setm(m);
setn(n);
}

public Rational(long m){


this(m,1);
}

public void setm(long m){

67
this.m=m;
}

public long getm(){


return m;
}

public void setn(long n){


this.n=n;
}

public long getn(){


return n;
}

public Rational produs(Rational r){


return new Rational(m*r.m,n*r.n);
}

public String toString(){


return m+"/"+n;
}

public class RationalIred extends Rational {

public RationalIred(){
super();
}

public RationalIred(long m,long n){


super(m,n);
}

public RationalIred(long m){


super(m);
}

private void simplifica(){


long x=getm(), y=getn();
while(x!=y){
if(x>y) x-=y;
else y-=x;
}
setm(getm()/x);
setn(getn()/x);
}

public RationalIred produs(RationalIred r){


RationalIred p=new RationalIred();

68
p.setm(getm()*r.getm());
p.setn(getn()*r.getn());
p.simplifica();
return p;
}

public class TestRational{


public static void main(String[] args) {
RationalIred r1,r2,p;
r1=new RationalIred(Integer.parseInt(args[0]),
Integer.parseInt(args[1]));
r2=new RationalIred(Integer.parseInt(args[2]),
Integer.parseInt(args[3]));
System.out.println(r1);
System.out.println(r2);
p=r1.produs(r2);
System.out.println(p);
}
}

69
5. Pachete

Un pachet este o colecţie de clase şi interfeţe înrudite. Sunt folosite pentru


găsirea şi utilizarea mai uşoarã a claselor, pentru a evita conflictele de nume şi
pentru a controla accesul la anumite clase.
În Java toate clasele şi interfeţele sunt grupate în diferite pachete după
funcţionalitatea lor. Cu ajutorul lor se pot construi aplicaţiile. Cele mai importante
pachete pe care le pune Java la dispoziţie sunt:
 pachetul java.lang cuprinde clasele de bazã ale limbajului;
 pachetul java.io cuprinde clasele pentru intrãri/ieşiri, lucru cu fişiere;
 pachetul java.math cuprinde clasele în care sunt definite operaţiile
matematice;
 pachetul java.util cuprinde clasele utile : Vector, Stack, Random,
Date etc;
 pachetul java.text oferă suport pentru formatarea textelor;
 pachetul java.sql oferă suport pentru interogări SQL;
 pachetul java.beans cuprinde clasele necesare scrierii de
componente reutilizabile;
 pachetul java.net cuprinde clasele care asigură accesul la reţea;
 pachetul java.awt cuprinde clasele pentru graficã (Abstract
Windowing Toolkit);
 pachetul javax.swing cuprinde clasele pentru graficã; extinde
funcţionalitatea claselor din pachetul java.awt.
 pachetul java.rmi cuprinde clasele care asigură execuţie la distanţă
(Remote Message Interface);
 pachetul java.securitz cuprinde clasele care asigură mecanisme de
securitate: criptare, autentificare;
Pentru a folosi o componentă a unui pachet trebuie făcut cunoscut clasei
curente fie pachetul în care se găseşte componenta, fie doar componenta. Acest
lucru se realizează prin importarea pachetului sau, doar a clasei.

70
5.1. Importul unui pachet, al unei clase sau a unei interfeţe

Importul se realizează prin instrucţiunea import.


Importul pachetelor se face prin specificarea numelui pachetului urmat de
simbolul '*'. '*' are semnificaţia că toate clasele şi interfeţele pachetului sunt
importate.
import NumePachet.*;
Exemple:
import java.io.*;
import javax.swing.*;

O dată realizat într-un fişier importul pachetului, orice clasă din pachet poate fi
accesată prin numele ei.
Exemplu: Clasa Date aparţine pachetului java.util.
import java.util.*;
public class ExData{
public static void main(String[] args) {
Date d=new Date(2003,4,13);
System.out.println(d);
}
}

Atenţie: În cazul în care sunt importate două pachete care conţin o clasă cu
acelaşi nume atunci referirea la ea trebuie făcută folosind numele complet al clasei
respective (nume pachet urmat de nume clasă).
Implicit, mediul Java importă trei pachete:
• pachetul java.lang
• pachetul curent
• pachetul implicit (fără nume)

Importul claselor (interfeţelor) se realizează prin specificarea numelui clasei


(interfeţei) pe care dorim să o folosim dintr-un pachet:
import NumePachet.NumeClasa;
Exemple:
import java.util.Date;
O dată realizat într-un fişier importul clasei (interfeţei), aceasta poate fi
accesată prin numele ei.

71
Exemplu:
import java.util.Date;
public class ExData{
public static void main(String[] args) {
Date d=new Date(2003,4,13);
System.out.println(d);
}
}
În cazul în care nu avem nevoie decât de câteva clase dintr-un pachet este
mai eficient să importăm clasele decât întregul pachet.

5.2. Crearea unui pachet

Se creează un director cu numele NumePachet în care vor fi salvate toate


fişierele sursă ce conţin clasele şi interfeţele pe care dorim să le grupăm într-un
pachet. Numele directorului dă numele pachetului.
În prima linie a fiecărui fişier din directorul NumePachet se specifică faptul că
toate clasele din fişierul respectiv vor aparţine clasei. Aceasta se realizează prin:
package NumePachet;
Prin urmare codul unei clase care se adaugă la un pachet arată astfel:
package NumePachet;
public class NumeClasa{
...
}
Instrucţiunea package acţionează asupra întregului fişier sursă la începutul
căruia apare. Cu alte cuvinte nu putem specifica faptul că anumite clase dintr-un
fişier sursă aparţin unui pachet iar altele altui pachet.
Dacă nu este specificat un anumit pachet, clasele unui fişier sursă vor face
parte din pachetul implicit (care nu are nici un nume). În general, pachetul implicit
este format din toate clasele şi interfeţele directorului curent.
Pentru compilare trebuie să ne plasăm în directorul părinte al directorului
NumePachet.
Se execută comanda:
javac NumePachet\*.java

În cazul în care nu sunt erori în pachet, în directorul NumePachet trebuie să


se creeze fişierele .class.

72
Clasele care folosesc pachetul creat se aşează în afara directorului. Pentru ca
ele să aibă acces la pachet trebuie setată variabila sistem CLASSPATH:
SET CLASSPATH = CaleDirectorNumePachet

Exemplu 1: În directorul c:\lucru se formează un director Pachete în care se


salvează următoarele fişiere:
Fişierul A1.java conţine clasa:
package Pachete;
public class A1{
int a=0;
public int b=0;
private int c=0;
protected int d=0;

void a(){
System.out.println(a);
}
public void b(){
System.out.println("public "+ b);
}
protected void d(){
System.out.println("protected "+d);
}
}

Fişierul A2.java conţine clasa:


package Pachete;
public class A2 implements A3{
public void a3(){
A1 a1=new A1();
a1.a=1;
a1.b=1;
a1.d=1;
System.out.println(a1.a+" "+a1.b+" "+a1.d);
a1.a();
a1.b();
a1.d();
}
}

Fişierul A3.java conţine clasa:


package Pachete;
public interface A3{
public void a3();
}

Setăm variabila CLASSPATH:

73
SET CLASSPATH = c:\lucru

Pentru compilare ne poziţionăm în directorul c:\lucru şi executăm


comanda:
javac Pachete\*.java

Construim o clasă de test A4.java pe care o salvăm în c:\lucru:


import Pachete.*;
public class A4{
public static void main(String args[]){
A2 a=new A2();
a.a3();
A1 a1=new A1();
//a1.a(); eroare – metoda a() este ca şi protected
a1.b();
//a1.d(); eroare – metoda d() este protected
}
}
Se compilează şi se execută ca orice clasă Java .

Exemplu 2: Construim un pachet Tablou care conţine o clasă Matrice şi una


Vector.
package Tablou;
public class Vector{
private double a[];

public Vector(){
a=new double[1];
}

public Vector(int n, double a[]){


this.a=new double[n];
for(int i=0; i<n; i++)
this.a[i]=a[i];
}

public int getLungime(){


return a.length;
}

public double getElem(int poz){


return a[poz];
}

public double[] getVector(){


return a;
}

74
public void setElem(int poz, double val){
a[poz]=val;
}

public void setVector(double a[]){


this.a=new double[a.length];
for(int i=0; i<a.length; i++)
this.a[i]=a[i];
}

public String toString(){


String s="";
for(int i=0; i<a.length; i++)
s=s+a[i]+" ";
return s;
}
}

package Tablou;
public class Matrice{
private double a[][];

public Matrice(){
a=new double[1][];
}

public Matrice(int n, int m, double a[][]){


this.a=new double[n][m];
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
this.a[i][j]=a[i][j];
}

public int getNrLin(){


return a.length;
}

public int getNrCol(int l){


return a[l].length;
}

public double getElem(int l, int c){


return a[l][c];
}

public double[][] getMatrice(){


return a;
}

public String toString(){

75
String s="";
for(int i=0; i<a.length; i++){
for(int j=0; j<a[i].length; j++)
s+=a[i][j]+" ";
s+="\n";
}
return s;
}
}

O clasă care foloseşte pachetul Tablou ar fi:


1. import Tablou.*;
2. public class TestTablou{
3. public static void main(String args[]){
4. double x[][]={{2,4},{5,6},{1,3}};
5. Matrice m=new Matrice(3,2,x);
6. System.out.println(m);
7. double y[]={2,4,5,6};
8. Vector v=new Vector(4,y);
9. System.out.println(v);
10. java.util.Vector vv=new java.util.Vector(5);
11. for (int i=0;i<5;i++)
12. vv.add(new Integer(i));
13. System.out.println(vv);
14. }
15. }

Se observă că în linia 10 se creează un obiect folosind de data aceasta clasa


Vector din pachetul java.util. Pentru a face diferenţă între clasa pachetului
nostru şi clasa pachetului java.util trebuie să specificăm şi numele pachetului.

76
6. Excepţii

6.1. Aspecte generale

O excepţie este un eveniment ce se produce în timpul execuţiei unui program


şi care provoacă întreruperea cursului normal al execuţiei.
De exemplu, o împărţire la 0 sau utilizarea unui indice care depăşeşte o
dimensiune declarată a unui tablou reprezintă un eveniment care perturbă execuţia
normală a programului – este vorba despre o excepţie. Când apare o astfel de
eroare în timpul execuţiei programului sistemul generează automat un obiect de tip
excepţie ce conţine:
 informaţii despre excepţia respectivă;
 starea programului în momentul producerii excepţiei
Exemplu:
public class Exceptii {
public static void main(String args[]) {
int v[] = new int[10];
v[10] = 0; //exceptie, vectorul are elementele v[0]...v[9]
System.out.println("Aici nu se mai ajunge...");
}
}

La rularea programului va fi generată o excepţie şi se va afişa mesajul :


Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException :3
at Exceptii.main (Exceptii.java:4)

Java dispune de un mecanism care permite programatorului să preia controlul


programului în momentul în care apare o excepţie şi să o trateze.
Crearea unui obiect de tip excepţie se numeşte aruncarea unei excepţii
("throwing an exception"). În momentul în care o metodă generează o excepţie
(aruncă o excepţie) sistemul de execuţie este responsabil cu găsirea unei secvenţe
de cod dintr-o metodă care să trateze acea excepţie. Excepţiile sunt propagate
înapoi prin secvenţa de metode apelate până când o anumită metodă prinde
excepţia. Secvenţa de cod dintr-o metodă care tratează o anumită excepţie se
numeşte analizor de exceptie ("exception handler") iar interceptarea şi tratarea

77
excepţiei se numeşte prinderea excepţiei ("catch the exception").
Cu alte cuvinte la apariţia unei erori este "aruncată" o excepţie iar cineva trebuie să
o "prindă" pentru a o trata. Dacă sistemul nu găseşte nici un analizor pentru o
anumita excepţie atunci programul Java se opreşte cu un mesaj de eroare.
Ierarhia claselor ce conţin excepţii este:

Toate excepţiile Java sunt subclase ale clasei Exception.

6.2. Instrucţiunea try

try{
instrucţiuni ce pot declanşa excepţii
}
[catch(ClasaExceptie obiectExceptie){
instrucţiuni de tratare a excepţiei de clasă ClasaExceptie
}]*
[finally{
instrucţiuni care se execută necondiţionat în final
}]

Instrucţiunea try conţine un bloc de instrucţiuni ce trebuie executate. Punerea


unor instrucţiuni în cadrul lui try înseamnă că există posibilitatea apariţiei unor
excepţii sau terminării anormale a unei instrucţiuni. O instrucţiune try poate avea
oricâte clauze catch (opţionale) în care sunt tratate excepţiile. De asemenea,
instrucţiunea try poate avea o clauză finally a cărui bloc se execută întotdeauna

78
înaintea părăsirii instrucţiunii try. Instrucţiunea try trebuie să aibă fie o clauză
catch, fie una finnaly.

Formele generale ale instrucţiunii try.


1.
try{
...
}
catch(ClasaExceptie obiectExceptie){
...
}

2.
try{
...
}
catch(ClasaExceptie obiectExceptie){... }
...
catch(ClasaExceptie obiectExceptie){... }

3.
try{
...
}
finnaly{... }

4.
try{
...
}
catch(ClasaExceptie obiectExceptie){... }
...
catch(ClasaExceptie obiectExceptie){... }
finnaly{... }

În cazul în care este declanşată o excepţie şi există mai multe clauze catch,
este căutată, în ordine, acea clauză care poate trata excepţia. Adică este găsită o
clauză a cărui parametru are un tip care se potriveşte cu tipul excepţiei. Ordinea în
care clauzele catch apar este importantă: clauzele catch mai specifice trebuie să
apară înaintea celor mai generale. Dacă nu există o clauză care să trateze excepţia,
aceasta este propagată în sus, la instrucţiunile imediat următoare.

79
Excepţii uzuale:
ArithmeticException Depăşire limită tip sau împărţire la 0
NumberFormatException Conversia nepermisă a unui
String la un tip numeric
IndexOutOfBoundsException Indice ilegal într-un şir
NegativeArraySizeException Crearea unui şir cu număr negativ
de elemente
NullPointerException Tentativă de a folosi o referinţă care
are valoarea null
SecurityException Încălcarea normelor de securitate în
timpul execuţiei

6.3. Crearea unei excepţii

Adeseori poate apărea necesitatea creării unor excepţii proprii pentru a pune
în evidenţă cazuri speciale de erori provocate de clasele unei librării, cazuri care nu
au fost prevăzute în ierarhia excepţiilor standard Java.
O excepţie proprie trebuie să se încadreze în ierarhia excepţiilor Java, cu alte
cuvinte clasa care o implementează trebuie să fie subclasă a clasei Exception.
public class ExceptieNoua extends Exception{ ... }

Exemplu:
1. public class Exc extends Exception{
2. public Exc(){
3. super(); //apeleaza constructorul clasei Exception
4. ...
5. }
6. }

Într-o clasă în care se doreşte folosirea unei excepţii există o metodă care creează
excepţia (obiect al clasei de excepţii), mai multe metode care aruncă excepţia
primită şi, eventual o metodă care o prinde, adică o tratează. Dacă într-o metodă
apare o excepţie – creată în metoda respectivă sau ca urmare a apelării unei
metode care a aruncat o excepţie, atunci ea trebuie fie să fie tratată, fie să fie
aruncată mai departe. În ambele cazuri codul care ar putea genera excepţia trebuie
pus în cadrul unei instrucţiuni try care să aibă o clauză catch cu parametru care
să coincidă cu clasa excepţiei. Dacă excepţia se doreşte să fie tratată, atunci în

80
clauza catch se pune un cod corespunzător. Dacă se doreşte ca excepţia să nu fie
tratată atunci ea trebuie aruncată mai departe (metodei care a făcut apelul) şi acest
lucru se realizează prin adăugarea clauzei throws ClasaExceptie în antetul
metodei.

Exemplu 1: În clasa RationalIred se verifică dacă numitorul fracţiei este 0. Dacă da


atunci se creează o excepţie – linia 53.
1. public class Exc extends Exception{
2. public Exc(){
3. super();
4. System.out.println("Numitor 0");
5. }
6. }

7. public class Rational{


8. private long m,n;

9. public Rational(){
10. this(1,0);
11. }
12. public Rational(long m,long n){
13. setm(m);
14. setn(n);
15. }
16. public Rational(long m){
17. this(m,1);
18. }
19. public void setm(long m){
20. this.m=m;
21. }
22. public long getm(){
23. return m;
24. }
25. public void setn(long n){
26. this.n=n;
27. }
28. public long getn(){
29. return n;
30. }
31. public Rational produs(Rational r){
32. return new Rational(m*r.m,n*r.n);
33. }
34. public String toString(){
35. return m+"/"+n;
36. }
37. }

38. public class RationalIred extends Rational {

81
39. public RationalIred(){
40. super();
41. }
42. public RationalIred(long m,long n) throws Exc{
43. setm(m);
44. try{
45. setIn(n);
46. }
47. catch(Exc e){throw e;}
48. }
49. public void setIn(long n) throws Exc{
50. if (n!=0)
51. super.setn(n);
52. else
53. throw new Exc();
54. }
55. private void simplifica(){
56. long x=getm(), y=getn();
57. while(x!=y){
58. if(x>y) x-=y;
59. else y-=x;
60. }
61. setm(getm()/x);
62. setn(getn()/x);
63. }
64. public RationalIred produs(RationalIred r){
65. RationalIred p=new RationalIred();
66. p.setm(getm()*r.getm());
67. p.setn(getn()*r.getn());
68. p.simplifica();
69. return p;
70. }
71. }

72. public class TestRational{


73. public static void main(String[] args) {
74. RationalIred r1,r2,p;
75. try{
76. r1=new RationalIred(
77. Integer.parseInt(args[0]),
78. Integer.parseInt(args[1]));
79. r2=new RationalIred(
80. Integer.parseInt(args[2]),
81. Integer.parseInt(args[3]));
82. }
83. catch(Exc e){
84. System.exit(1);
85. }
86. System.out.println(r1);
87. System.out.println(r2);
88. p=r1.produs(r2);
89. System.out.println(p);

82
90. }
91. }

83
7. Intrări şi ieşiri

Informaţia poate fi preluată de oriunde (fişier, disk, reţea, memorie, alt


program) şi poate fi de orice tip (obiecte, caractere, imagini, sunete).
Pentru a aduce informaţii, un program Java deschide un flux (canal de
comunicaţii) la o sursă de informaţii şi citeşte informaţia. Un flux care citeşte date se
numeşte flux de intrare.

Similar, un program poate trimite informaţii către o destinaţie externă


deschizând un flux (canal de comunicaţii) către acea destinaţie şi scriind serial
informaţiile respective. Un flux care scrie date se numeşte flux de ieşire.

Algoritmul de citire este:


deschide flux
cât timp există informaţie
citeşte informaţia

84
închide flux

Algoritmul de afişare este:


deschide flux
cât timp există informaţie
scrie informaţia
închide flux

Pachetul java.io conţine o colecţie de clase folosite pentru citiri şi afişări.


Prin urmare, orice program care necesită operaţii de intrare / ieşire trebuie să
importe pachetul java.io:
import java.io.*.

7.1. Clasificarea fluxurilor

Există trei tipuri de clasificare a fluxurilor:


• După "direcţia" canalului de comunicaţie deschis, fluxurile se împart în:
o fluxuri de intrare (pentru citirea datelor)
o fluxuri de ieşire (pentru scrierea datelor)
• După tipul de date pe care operează:
o fluxuri de octeţi (comunicarea serială se realizează pe 8 biţi)
o fluxuri de caractere (comunicarea serială se realizează pe 16
biţi)
• După acţiunea lor:
o fluxuri pentru citirea / scrierea datelor
o fluxuri pentru procesarea datelor

7.2. Ierarhia claselor pentru lucrul cu fluxuri

7.2.1. Fluxuri de caractere

Clasele rădăcină pentru ierarhia claselor ce se ocupă cu fluxurile de caractere


sunt Reader (pentru fluxuri de intrare) şi Writer (pentru fluxuri de ieşire).

85
Ierarhia claselor pentru fluxuri de intrare pe caractere este:

Ierarhia claselor pentru fluxuri de ieşire pe caractere este:

7.2.2. Fluxuri de octeţi

Clasele rădăcină pentru ierarhia claselor ce se ocupă cu fluxurile de octeţi sunt


InputStream (pentru fluxuri de intrare) şi OutputStream (pentru fluxuri de ieşire).
Subclasele lor sunt folosite pentru citiri şi scrieri de date binare cum ar fi imagini şi
sunete.
Ierarhia claselor pentru fluxuri de intrare pe octeţi:

86
Ierarhia claselor pentru fluxuri de ieşire pe octeţi:

7.3. Superclasele de intrare / ieşire

Clasele Reader şi InputStream definesc metode similare pentru citirea


datelor, tipul parametrilor variind.
Clasa Reader
int read()
int read(char cbuf[ ])
int read(char cbuf[ ], int index, int lungime)
Clasa InputStream
int read()
int read(byte cbuf[ ])
int read(byte cbuf[ ], int index, int lungime)

87
Analog, clasele Writer şi OutputStream definesc metode similare pentru
afişarea datelor, tipul parametrilor variind.
Clasa Writer
int write()
int write(char cbuf[ ])
int write(char cbuf[ ], int index, int lungime)
Clasa OutputStream
int write()
int write(byte cbuf[ ])
int write(byte cbuf[ ], int index, int lungime)

7.4. Crearea unui flux

Orice flux este un obiect al clasei ce implementează fluxul respectiv. Crearea


unui flux se realizează similar cu crearea obiectelor, prin instrucţiunea new().
Exemple:
//crearea unui flux de intrare pe caractere
FileReader in = new FileReader("fisier_intrare.txt");

//crearea unui flux de iesire pe caractere


FileWriter out = new FileWriter("fisier_iesire.txt");

//crearea unui flux de intrare pe octeti


FileInputStream in = new
FileInputStream("fisier_intrare.txt");

//crearea unui flux de iesire pe octeti


FileOutputStrem out = new
FileOutputStream("fisier_iesire.txt");

Prin urmare, crearea unui flux de date care scrie / citeşte informaţii de la un
dispozitiv extern are formatul general:
FluxPrimitiv numeFlux = new FluxPrimitiv (dispozitiv extern)

88
7.5. Citirea datelor de la tastatură

7.5.1. Obiectul System.in

În general, tastatura reprezintă perifericul standard pentru introducerea datelor.


Clasa System conţine o variabilă membru care reprezintă tastatura sau fluxul de
intrare standard. Această variabilă membru se numeşte in şi este o instanţă a clasei
InputStream.

Exemplu 1: Se citesc de la tastatură caractere. Fiecare caracter citit se adaugă la un


şir de caractere. Citirea se încheie când se apasă tasta Enter.
1. class Citire1 {
2. public static void main(String args[]) {
3. StringBuffer s=new StringBuffer();
4. char c;
5. try {
6. while((c=(char)System.in.read()) != ’\n’)
7. s.append(c);
8. }
9. catch(Exception e) {
10. System.out.println(”Error:”+e.getMessag
e());
11. }
12. System.out.println("Sirul este:"+s);
13. }
14. }

Exemplu 2: Se citesc de la tastatură caractere. Ele sunt memorate într-un vector de


bytes (linia 5). Citirea se încheie când se apasă tasta Enter. Pe baza vectorului se
formează un String (linia 10) care este afişat.
1. class Citire2 {
2. public static void main(String args[]) {
3. byte buf[]=new byte[30];
4. try {
5. System.in.read(buf);
6. }
7. catch(Exception e) {
8. System.out.println(”Error:”+e.getMessage());
9. }
10. String s=new String(buf);
11. System.out.println(s);
12. }

89
13. }

7.5.2. Clasa InputStreamReader

Reprezintă legătura dintre fluxurile de octeţi şi fluxurile de caractere: citeşte


octeţi şi îi transformă în caractere. Transformarea octeţilor în caractere este
efectuată conform unei reguli de codificare. Dacă nu se specifică o astfel de regulă,
atunci se utilizează codificarea implicită (dată de proprietatea de sistem ”file
encoding”).
Clasa InputStreamReader are următorii constructori:
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String enc)

Metoda principală pentru citirea unui caracter este:


int read()

Exemplu 3: Se citesc de la tastatură caractere. Fiecare caracter citit se adaugă la un


şir de caractere. Citirea se încheie când se apasă tasta Enter.
1. import java.io.*;
2. class Citire3 {
3. public static void main(String args[]) {
4. InputStreamReader in=
5. new InputStreamReader(System.in);
6. char c;
7. StringBuffer s=new StringBuffer();
8. try {
9. while((c=(char)in.read()) != ’\n’)
10. s.append(c);
11. }
12. catch(Exception e) {
13. System.out.println(”Error:”+e.getMessage());
14. }
15. System.out.println(s);
16. }
17. }

7.5.3. Clasa BufferedReader

90
În cazul folosirii clasei InputStreamReader, citirea se face caracter cu
caracter (adică, discul este accesat de fiecare dată). Pentru a creşte eficienţa se
foloseşte un flux care utilizează o zonă tampon pentru citire (BufferedReader).
Clasa BufferedReader are definită metoda read() cu aceeaşi signatură ca şi cea
definită în InputStreamReader dar, în plus, defineşte şi metoda readLine().
Această metodă poate fi folosită pentru a citi un şir de caractere terminat cu ’\n’,’\r’
sau ’\r\n’.

Exemplu 4: Se introduce un şir de caractere de la tastatură. La apăsarea tastei Enter


şirul este citit în întregime şi este depus într-un String.
1. import java.io.*;
2. class Citire4 {
3. public static void main(String args[]) {
4. InputStreamReader in1=
new InputStreamReader(System.in);
5. String s=new String();
6. try {
7. BufferedReader in= new BufferedReader(in1);
8. s=in.readLine();
9. }
10. catch(Exception e) {
11. System.out.println(”Error:”+e.getMessage());
12. }
13. System.out.println(s);
14. }
15. }

7.6. Citirea şi scrierea datelor din fişier

7.6.1. Clasele FileReader şi FileWriter

Clasa FileReader este folosită la citirea datelor dintr-un fişier text. Cei mai
importanţi constructori ai săi sunt:
• creează un flux care citeşte caractere din fişierul nume
public FileReader(String nume) throws
FileNotFoundException

91
• creează un flux care citeşte caractere din fişierul varFis.
public FileReader(File varFis) throws
FileNotFoundException

Clasa FileWriter este folosită la scrierea datelor într-un fişier text. Cei mai
importanţi constructori ai săi sunt:
• creează un flux care scrie caractere in fişierul nume
public FileWriter (String nume) throws IOException

• creează un flux care citeşte caractere din fişierul varFis


public FileWriter (File varFis) throws IOException

Exemplu 5: Citeşte caracter cu caracter un fişier în linia 8. Când valoarea


caracterului citit este –1 înseamnă că s-a ajuns la sfârşitul fişierului. Caracterele sunt
adăugate la un şir de caractere în linia 9, care la sfârşit este afişat.
1. import java.io.*;
2. public class CitireFis {
3. public static void main(String args[]) {
4. int c;
5. StringBuffer s=new StringBuffer();
6. try {
7. FileReader in= new FileReader(”cit4.txt”);
8. while((c=in.read())!=-1)
9. s.append((char)c);
10. }
11. catch(Exception e) {
12. System.out.println(”Error:”+e.getMessage());
13. }
14. System.out.println(s);
15. }
16. }

Exemplu 6: Copiază conţinutul unui fişier în alt fişier.


1. import java.io.*;
2. public class CitireFis {
3. public static void main(String[] args){
4. try{
5. FileReader in = new FileReader("cit4.txt");
6. FileWriter out = new FileWriter("out.txt");
7. int c;
8. while ((c = in.read()) != -1)
9. out.write(c);
10. in.close();
11. out.close();
12. }

92
13. catch (IOException e) {
14. System.out.println("Error: " + e.toString());
15. }
16. }
17. }

8. Applet-uri

8.1. Ce este un applet?

Unul dintre scopurile limbajului Java a fost crearea unor programe mici
(applet) care să ruleze în interiorul unui browser Web.
Un applet reprezintă o suprafaţă de afişare (container) ce poate fi inclusă într-o
pagina Web şi gestionată printr-un program Java. Un astfel de program se mai
numeşte miniaplicaţie.
Codul unui applet poate fi format din una sau mai multe clase. Una dintre
acestea este principală şi extinde clasa JApplet, fiind clasa ce trebuie specificată în
documentul HTML ce descrie pagina de Web în care dorim să includem applet-ul.
Diferenţa fundamentală dintre un applet şi o aplicaţie constă în faptul că, un applet
nu poate fi executat independent, ci va fi executat de browser-ul în care este
încărcată pagina Web ce conţine applet-ul respectiv. O aplicaţie independentă este
executată prin apelul interpretorului java, având ca parametru numele clasei
principale a aplicaţiei, clasa principală fiind cea care conţine metoda main.
Un applet nu se poate atinge de hardisk-ul local prin citiri sau scrieri. Scrierea
este împiedicată din cauza viruşilor care s-ar putea instala, iar citirea deoarece nu se
doreşte preluarea de informaţii de pe staţia locală.
Un neajuns al applet-urilor ar putea fi timpul destul de lung necesar încărcării
lor. O metodă de înlăturare a acestui neajuns ar fi arhivarea applet-urilor într-un fişier
JAR (Java ARchive) care să cuprindă toate componentele. Astfel, fişierul compresat
este download-at la o singură tranzacţie cu server-ul.
Un avantaj al folosirii applet-urilor este lipsa necesităţii instalării lor. De fapt,
instalarea este automată de câte ori utilizatorul încarcă pagina Web care conţine
applet-ul.
Pachetul care oferă suport pentru crearea de applet-uri este javax.swing.
Clasa JApplet furnizează tot ce este necesar pentru construirea şi întreţinerea unui

93
applet. Crearea unui applet implică implementarea metodelor puse la dispoziţie de
clasa JApplet care ne ajută să descriem comportamentul dorit al applet-ului.
Ierarhia de clase este:
java.lang.Object
|
+--java.awt.Component
|
+--java.awt.Container
|
+--java.awt.Panel
|
+--java.applet.Applet
|
+--javax.swing.JApplet

8.2. Funcţiile unui applet

Execuţia unui applet începe în momentul în care un browser afişează o pagină


Web în care este inclus applet-ul respectiv şi poate trece prin mai multe etape.
Fiecare etapă este strâns legată de un eveniment generat de către browser şi
determină apelarea unei metode specifice din clasa ce implementează appletul.
 Încărcarea în memorie – se creează o instanţă a clasei principale a
applet-ului şi se încarcă în memorie.
 Iniţializarea – se apelează metoda init ce permite iniţializarea
diverselor variabile, citirea unor parametri de intrare, etc. Metoda init
este responsabilă şi pentru aşezarea tuturor componentelor pe formă.
 Pornirea – se apelează metoda start
 Execuţia propriu-zisă – constă în interacţiunea dintre utilizator şi
componentele afişate pe suprafaţa applet-ului.
 Oprirea temporară – În cazul în care utilizatorul părăseşte pagina Web
în care rulează applet-ul se apelează metoda stop a acestuia, dându-i
astfel posibilitatea să se oprească temporar cât timp nu este vizibil,
pentru a nu consuma inutil din timpul procesorului. Acelaşi lucru se
întâmplă dacă fereastra browser-ului este minimizată. În momentul când
pagina Web ce conţine applet-ul devine din nou activă, va fi reapelată
metoda start.

94
 Oprirea definitivă – La închiderea tuturor instanţelor browser-ului folosit
pentru vizualizare, applet-ul va fi eliminat din memorie şi va fi apelată
metoda destroy a acestuia, pentru a-i permite să elibereze resursele
deţinute. Apelul metodei destroy este întotdeauna precedat de apelul lui
stop.

8.3. Structura generală a unui applet

import javax.swing.JApplet;
import java.awt.*;
import java.awt.event.*;

public class StructuraApplet extends JApplet {

public void init() {


/* codul descrie acţiunile care dorim să fie efectuate la instanţierea clasei
applet-ului. */
}

public void start() {


/* codul descrie acţiunile care dorim să fie executate la lansarea applet-
ului în execuţie sau la reîntoarcerea în pagina applet-ului */
}

public void paint(Graphics g) {


/* codul descrie acţiunile care dorim să fie executate la fiecare redesenare
a ferestrei applet-ului */
}

public void stop() {


/* codul descrie acţiunile care dorim să fie executate la oprirea temporară
a applet-ului (pagina Web nu mai este vizibilă, fereastra browser-ului este
minimizată, etc) */
}

public void destroy() {


/* codul descrie acţiunile care dorim să fie executate la distrugerea applet-
ului (browser-ul părăseşte documentul .html din care a fost apelat applet-ul) */
}

95
}

Observaţie: Aceste metode sunt apelate automat de browser şi nu trebuie


apelate explicit din program !

8.4. HTML

Un browser Web interpretează conţinutul (textul) unui fişier .html (Hyper Text
Markup Language). Limbajul HTML constă într-o colecţie de marcaje (tag-uri).
Marcajele au rolul de a descrie modul în care va apărea afişat textul, de a comanda
browser-ului să utilizeze şi alte resurse Internet, aflate în fişiere diferite.
Sintaxa unui marcaj este:
<NumeTag [parametri ]> text </NumeTag>

Parametrii se scriu sub forma:


NumeParametru = valoare
Structura unui document .html este:
<HTML>
<HEAD>
<TITLE>
titlul documentului
</TITLE>
</HEAD>
<BODY>
. . .
<APPLET parametrii>
<PARAM parametrii>
<PARAM parametrii>
. . .
<PARAM parametrii>
</APPLET>
. . .
</BODY>
</HTML>

Considerăm cunoscute noţiunile de bază ale HTML. Ceea ce ne interesează


pentru construirea applet-urilor este marcajul <APPLET>. Acesta are parametrii
obligatorii şi opţionali.
Parametrii obligatorii:

96
 CODE – valoarea lui este numele fişierului care conţine clasa applet-
ului: NumeClasa.class;
 WIDTH – valoarea lui este lăţimea ferestrei atribuită de browser applet-
ului la afişarea documentului .html;
 HEIGHT – valoarea lui este înălţimea ferestrei atribuită de browser
applet-ului la afişarea documentului .html;
Parametrii opţionali:
 CODEBASE – valoarea lui este adresa URL (Universal Resource
Locator) sau calea la fişierul cu clasa applet-ului. Dacă parametru
lipseşte, căutarea clasei se face în directorul curent (cel din care a fost
încărcat fişierul .html);
 VSPACE – valoarea lui este înălţimea zonei (exprimată în pixeli) care
se lasă liberă deasupra şi dedesubtul ferestrei applet-ului;
 HSPACE – valoarea lui este lăţimea zonei (exprimată în pixeli) care se
lasă liberă în stânga şi în dreapta ferestrei applet-ului;
 ALT – Specifică textul ce trebuie afişat dacă browser-ul înţelege
marcajul <APPLET> dar nu poate rula applet-uri Java.
 NAME – Oferă posibilitatea de a da un nume respectivei instanţe a
applet-ului, astfel încât mai multe applet-uri aflate pe aceeaşi pagină să
comunice între ele folosindu-se de numele lor.
 ALIGN – Semnifică modalitatea de aliniere a applet-ului în pagina Web.
Acest atribut poate primi una din următoarele valori: left, right,
top, texttop, middle, absmiddle, baseline, bottom,
absbottom, semnificaţiile lor fiind aceleaşi ca şi la marcajul IMG.

Marcajul <PARAM> nu este obligatoriu şi poate să apară atunci când se


doreşte ca applet-ul să preia parametrii. Un parametru este definit prin:
 NAME – reprezintă numele variabilei recunoscut de applet;
 VALUE – reprezintă valoarea recepţionată de applet; este de tip String.

8.5. Exemple

Exemplu 1: Exemplifică ordinea apelării metodelor.

97
import javax.swing.*;
import java.awt.*;

public class app1 extends JApplet{


public void init(){
System.out.println("Sunt in init");
}

public void start(){


System.out.println("Sunt in start");
}

public void paint(Graphics g){


g.drawString("Sunt in paint", 20, 120);
System.out.println("Sunt in paint");
}

public void stop(){


System.out.println("Sunt in stop");
}
public void destroy(){
System.out.println("Sunt in destroy");
}
}

Documentul .html este:


<HTML>
<HEAD>
<TITLE> Primul Applet </TITLE>
</HEAD>
<BODY>
<APPLET CODE="app1.class" WIDTH=300 HEIGHT=200>
</APPLET>
</BODY>
</HTML>

Exemplu 2: Afişează nişte figuri geometrice.


import javax.swing.*;
import java.awt.*;

public class app2 extends JApplet{


public void paint(Graphics g){
g.setColor(Color.red);
g.drawRect(10,10,100,200);
g.setColor(new Color(200,100,255));
g.fillRect(20,20,50,50);
g.setColor(Color.blue);
g.drawOval(60,60,50,50);
}

98
}

Documentul .html este:


<HTML>
<HEAD>
<TITLE> Figuri geometrice </TITLE>
</HEAD>
<BODY>
<APPLET CODE="app2.class" WIDTH=300 HEIGHT=200>
</APPLET>
</BODY>
</HTML>

Exemplu 3: Afişează lista tuturor font-urilor cunoscute de sistem.


import java.awt.*;
import javax.swing.*;

public class app3 extends JApplet


{
public void init(){
Container c=getContentPane();
c.setLayout(new FlowLayout());
JTextArea ta=new JTextArea();
JScrollPane sp=new JScrollPane(ta);
sp.setPreferredSize(new Dimension(100, 100));
c.add(sp, BorderLayout.CENTER);
GraphicsEnvironment gr=GraphicsEnvironment.
getLocalGraphicsEnvironment();
Font []f=gr.getAllFonts();
for (int i=0;i<f.length;i++)
ta.append(f[i].getFontName()+"\n");
}
}

Documentul .html este:


<HTML>
<HEAD>
<TITLE> Ce de mai font-uri !!! </TITLE>
</HEAD>
<BODY>
<APPLET CODE="app3.class" WIDTH=300 HEIGHT=200>
</APPLET>
</BODY>
</HTML>

Exemplu 4: Setează un font şi îi tipăreşte caracteristicile.


import javax.swing.JApplet;

99
import java.awt.Graphics;
import java.awt.Font;

public class app6 extends JApplet {


private Font fon;

public void init()


{
fon=new Font("Courier", Font.ITALIC + Font.BOLD, 24);
}
public void paint (Graphics g)
{
int stil, dim;
String str, nume;

g.setFont (fon);
stil = fon.getStyle();

if ( stil == Font.PLAIN)
str = "Plin";
else if (stil == Font.BOLD)
str = "Bold";
else if (stil == Font.ITALIC)
str = "Italic";
else
str = "Bold italic";

dim = fon.getSize();
str += dim + " puncte ";
nume = fon.getName();
str += nume;

g.drawString (str, 20, 40);


g.drawString ("Familia de font-uri este " +
fon.getFamily(), 20, 60);

}
}

Documentul .html este:


<HTML>
<HEAD>
<TITLE> Ce font frumos !!! </TITLE>
</HEAD>
<BODY>
<APPLET CODE="app6.class" WIDTH=700 HEIGHT=200>
</APPLET>
</BODY>
</HTML>

100
Exemplu 5: Desenează un poligon şi îl copiază într-o altă zonă a ferestrei.
import javax.swing.JApplet;
import java.awt.*;

public class app7 extends JApplet {


int xValues[] = {20, 40, 50, 30, 20, 15, 20};
int yValues[] = {20, 20, 30, 50, 50, 30, 20};

private Polygon p2;

public void init ()


{
p2 = new Polygon();
p2.addPoint (70, 70);
p2.addPoint (90, 70);
p2.addPoint (100, 80);
p2.addPoint (80, 100);
p2.addPoint (70, 100);
p2.addPoint (65, 80);
p2.addPoint (60, 60);
}
public void paint (Graphics g)
{
//deseneaza conturul unui poligon
g.drawPolygon (xValues, yValues, 7);
//deseneaza un poligon
g.fillPolygon (p2);
//copiaza cele doua poligoane la noile coordonate
g.copyArea (0, 0, 100, 100, 10,10 );
}
}

Documentul .html este:


<HTML>
<HEAD>
<TITLE> Ce poligoane... </TITLE>
</HEAD>
<BODY>
<APPLET CODE="app7.class" WIDTH=300 HEIGHT=200>
</APPLET>
</BODY>
</HTML>

Exemplu 6: Desenează un poligon şi îl copiază într-o altă zonă a ferestrei.


import javax.swing.JApplet;
import java.awt.*;

101
public class app7 extends JApplet {
int xValues[] = {20, 40, 50, 30, 20, 15, 20};
int yValues[] = {20, 20, 30, 50, 50, 30, 20};

private Polygon p2;

public void init ()


{
p2 = new Polygon();
p2.addPoint (70, 70);
p2.addPoint (90, 70);
p2.addPoint (100, 80);
p2.addPoint (80, 100);
p2.addPoint (70, 100);
p2.addPoint (65, 80);
p2.addPoint (60, 60);
}
public void paint (Graphics g)
{
//deseneaza conturul unui poligon
g.drawPolygon (xValues, yValues, 7);
//deseneaza un poligon
g.fillPolygon (p2);
//copiaza cele doua poligoane la noile coordonate
g.copyArea (0, 0, 100, 100, 10,10 );
}
}

Documentul .html este:


<HTML>
<HEAD>
<TITLE> Ce poligoane... </TITLE>
</HEAD>
<BODY>
<APPLET CODE="app7.class" WIDTH=300 HEIGHT=200>
</APPLET>
</BODY>
</HTML>

Exemplu 7: Suma a două numere folosind preluarea parametrilor.


import javax.swing.*;
import java.awt.*;

public class suma extends JApplet


{
int m,n;
String s;

public void init(){

102
String sm=getParameter("m"),
sn=getParameter("n");
m=Integer.parseInt(sm);
n=Integer.parseInt(sn);
s=new Integer(m+n).toString();
}

public void paint(Graphics g){


g.drawString("Cmmdc = "+s, 50, 60 );
}
}

Documentul .html este:


<HTML>
<HEAD>
<TITLE> Suma... </TITLE>
</HEAD>
<BODY>
<APPLET CODE="suma.class" WIDTH=300 HEIGHT=200>
<PARAM name="m" value="2">
<PARAM name="n" value="3">
</APPLET>
</BODY>
</HTML>

103
9. Interfeţe grafice

9.1. Ce este o interfaţă grafică?

Interfaţa grafică se referă la toate tipurile de comunicare vizuală între un


program şi utilizatorii săi. Interfaţa grafică se referă nu numai la ceea ce utilizatorul
vede pe ecran ci şi la toate mecanismele de comunicare între acesta şi program.
Limbajul Java pune la dispoziţie numeroase clase pentru implementarea
diferitelor functionalităţi ale interfaţei grafice, însă ne vom ocupa în continuare de
acelea care permit realizarea unei intefeţe grafice cu utilizatorul (GUI – Graphical
User Interface).
În principiu, crearea unei aplicaţii grafice presupune următorii paşi:
1. crearea unei suprafeţe de afişare (cum ar fi o fereastră) pe care vor fi
aşezate obiectele grafice care servesc la comunicarea cu utilizatorul
(butoane, controale de editare, texte, etc);
2. crearea şi aşezarea obiectelor grafice pe suprafaţa de afişare în
poziţiile corespunzătoare;
3. definirea unor acţiuni care trebuie să se execute în momentul când
utilizatorul interacţionează cu obiectele grafice ale aplicaţiei;
4. "ascultarea" evenimentelor generate de obiecte în momentul
interacţiunii cu utilizatorul şi executarea acţiunilor corespunzătoare aşa
cum au fost ele definite.

În Java există două pachete de clase care oferă servicii grafice: java.awt şi
javax.swing. În acest curs ne vom ocupa de pachetul Swing care este o extensie a
pachetului awt. "Swing" a fost numele de cod dat proiectului care dezvolta
componente noi. Începând cu javax.swing este numele pachetelor pentru Swing
API.

104
Majoritatea obiectelor grafice sunt subclase ale clasei JComponent, clasă
care defineşte generic o componentă grafică care poate interacţiona cu utilizatorul.
Aşadar, printr-o componentă grafică vom înţelege orice obiect care are o
reprezentare grafică ce poate fi afişată pe ecran şi care poate interacţiona cu
utilizatorul. Exemple de componente sunt ferestrele, butoanele, bare de defilare, etc.
În general, toate componentele sunt definte de clase proprii ce se găsesc în pachetul
javax.swing, clasa JComponent fiind superclasa abstractă a tuturor acestor clase.

Crearea obiectelor grafice nu realizează automat şi afişarea lor pe ecran. Mai


întâi ele trebuie aşezate pe o suprafaţă de afişare, care poate fi o fereastră sau
suprafaţa unui applet, şi vor deveni vizibile în momentul în care suprafaţa pe care
sunt afişate va fi vizibilă. O astfel de suprafaţă pe care se aşează obiectele grafice
reprezintă o instanţă a unei clase obţinută prin extensia clasei Container; din acest
motiv suprafeţele de afişare vor mai fi numite şi containere. Clasa Container este o
subclasă aparte a clasei Component, fiind la rândul ei superclasa tuturor suprafeţelor
de afişare Java (ferestre, applet-uri, etc).
Pachetul Swing oferă programelor care folosesc componentele lui posibilitatea
să-şi aleagă natura interfeţei („look and feel”) sau, pur şi simplu, să o conserve pe
cea caracteristică platformei respective.

9.2. Primele aplicaţii Swing

9.2.1. Exemple

Exemplu 1: O aplicaţie de sine stătătoare, care nu utilizează applet-ul.


1. import javax.swing.*;
2. import java.awt.*;
3. import java.awt.event.*;

4. public class SwingTest {


5. private static String Prefix = "Numarul de click-
uri: ";
6. private int nrClick = 0;
7. JLabel eticheta = new JLabel(Prefix + "0 ");
8. JButton buton = new JButton("Buton Swing!");
9.
10. public Component creazaComponente() {
11. buton.addActionListener(new ActionListener() {

105
12. public void actionPerformed(ActionEvent e) {
13. nrClick++;
14. eticheta.setText(Prefix + nrClick);
15. }
16. });
17. JPanel panou = new JPanel();
18. panou.setBorder(BorderFactory.createEmptyBorder( 3
0,30,10,30));
19. panou.setLayout(new FlowLayout());
20. panou.add(buton);
21. panou.add(eticheta);
22. return panou;
23. }//creazaComponente
24.
25. public static void main(String[] args) {
26. try {
27. UIManager.setLookAndFeel(
UIManager.getLookAndFeel())
;
28. }catch (Exception e) { }
29. JFrame frame = new JFrame("Prima aplicatie
Swing");
30. SwingTest app = new SwingTest();
31. Component comp = app.creazaComponente();
32. frame.getContentPane().add(comp);
33. frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
34. frame.pack();
35. frame.setVisible(true);
36. }//main
37. }//class

În linia 17 se crează un panel (panou) pe care vor fi aşezate componentele.


În linia 18 se setează marginea panel-ului cu dimensiunile pentru (sus,
stânga, jos, dreapta).
În linia 29 se crează container-ul principal (din vârful ierarhiei) şi în linia 32 se
adaugă componentele pe el.
În liniile 33–35 se încheie setările pentru frame şi se afişează.

Exemplu 2: O aplicaţie care utilizează applet-ul.


1. import javax.swing.*;
2. import java.awt.*;

3. public class SwingAppletTest extends JApplet {

106
4. public void init() {
5. JLabel eticheta=new JLabel("O eticheta
frumoasa!");
6. eticheta.setHorizontalAlignment(JLabel.CENTER
);
7. label.setBorder(BorderFactory.createMatteBord
er( 1,1,2,2,Color.black));
8. getContentPane().add(eticheta,
BorderLayout.CENTER);
9. }
10. }

9.2.2. Comentarea exemplelor

9.2.2.1 Alegerea naturii interfeţei


În codul următor se specifică natura interfeţei:
try {
UIManager.setLookAndFeel(
UIManager. getLookAndFeel());
} catch (Exception e) { }

9.2.2.2 Setarea container-ului principal (din vârful ierarhiei)


Orice program care prezintă o GUI Swing conţine cel puţin un container Swing.
În general, container-ele principale sunt instanţe ale lui JFrame, JDialog sau (pentru
appleturi) JApplet. Fiecare obiect JFrame implementează o singură fereastră
principală, fiecare obiect JDialog câte o fereastră secundară şi fiecare obiect
JApplet implementează un applet în cadrul unui browser. Container-ul principal
Swing furnizează suportul necesar componentelor Swing pentru a fi afişate şi pentru
a manipula evenimentele. În exemplu 1 container-ul folosit este JFrame şi este creat
în linia 29. În exemplu 2 container-ul folosit este JApplet (vezi linia 3).
Aplicaţiile Swing grupează etichetele şi butoanele într-un container (un
JPanel) înainte să le adauge pe frame. Adăugarea componentelor pe panel
înseamnă că ele vor fi controlate de manager-ul de layout al panel-ului. Manager-ul
de layout al unui container determină dimensiunea şi poziţia fiecărei componente
care este adăugată pe container.

107
9.2.2.3 Manipularea evenimentelor
Aplicaţia din exemplu 1 conţine două evenimente tratate. Una tratează click-ul
pe buton (action events); cealaltă tratează închiderea ferestrei (window events):
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
numClicks++;
label.setText(labelPrefix + numClicks);
}
});
...
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

9.3. Containere principale

După cum am văzut, suprafeţele de afişare ale componentelor grafice


(containerele) sunt extensii ale clasei Container.
Spre deosebire de un applet care îşi poate plasa componentele direct pe
suprafaţa de afişare a browser-ului în care rulează, o aplicaţie independentă are
nevoie de propriile ferestre pe care să facă afişarea componentelor sale grafice. O
astfel de suprafaţă pe care se aşează obiectele grafice se numeşte suprafaţă de
afişare sau container şi reprezintă o instanţă a unei clase obţinută prin extensia
superclasei Container.
Cele mai importante containere principale sunt: JFrame, JDialog,
JWindow şi JApplet. Ierarhia de clase este:
java.awt.Container
|__ java.awt.Panel
|__ java.applet.Applet
|__ javax.swing.JApplet
|__ java.awt.Window
|__ java.awt.Frame
| |__ javax.swing.JFrame
|__ java.awt.Dialog
| |__ javax.swing.JDialog
|__ javax.swing.JWindow

108
9.3.1. Clasa JFrame

Clasa JFrame este folosită pentru implementarea ferestrelor principale.


Această componentă are caracteristic cadrul, bara de titlu şi controalele ferestrei
furnizate de sistemul de operare. Acestea nu pot fi modificate. Comportamentul
ferestrelor (redimensionare, minimizare, poziţionare) este controlat de sistemul de
operare.
Constructorii clasei JFrame sunt:
JFrame() – construieşte o fereastră, fără titlu, iniţial invizibilă.
JFrame(String title) – construieşte o fereastră, cu titlu specificat,
iniţial invizibilă.
Aşadar, o fereastră nou creată este invizibilă. Pentru a fi făcută vizibilă se va
apela metoda show().

Exemplu 3: Se construieşte şi se afişează o fereastră cu titlul "Prima


fereastra".
import javax.swing.*;
public class AplJFrame {
public static void main(String args[]) {
JFrame f = new JFrame("Prima fereastra");
f.show();
}
}

Câteva dintre metodele cele mai folosite ale clasei JFrame sunt prezentate în
continuare.
Metoda pack() este folosită pentru a da o dimensiune frame-ului. O
alternativă pentru pack() este setarea explicită a dimensiunii frame-ului prin
apelarea metodei setSize(). În general, folosirea lui pack() este preferabilă
folosirii lui setSize(), deoarece pack() lasă în seama layout manager-ului calculul
dimensiunii frame-ului care ţine seama şi de alţi factori care pot afecta dimensiunea
componentelor.
Metoda setVisible() este folosită pentru a afişarea frame-ului.
Metoda getContentPane() returnează obiectul contentPane al frame-ului.
Orice componentă se adaugă pe contentPane-ul frame-ului curent.
Exemplu 4:

109
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class AplicFrame{


public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
UIManager.getLookAndFeel());
} catch (Exception e) { }

/*Se creaza container-ul principal (din varful


ierarhiei) si se adauga componentele pe el*/
JFrame frame = new JFrame();

JLabel comp = new JLabel("eticheta1");


JLabel comp1 = new JLabel("eticheta2");
//eticheta2 va fi pusa peste eticheta1
frame.getContentPane().add(comp);
frame.getContentPane().add(comp1);

frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);
}
}

9.3.2. Ferestre secundare şi clasa JDialog

Pentru a crea ferestre secundare se foloseşte, de obicei, JDialog. Alte


ferestre secundare pot fi create cu:
JOptionPane – creează o fereastră standard de dialog
ProgressMonitor – creează o fereastră care arată progresul unei operaţii
JColorChooser – creează o fereastră pentru alegerea culorii
JFileChooser – creează o fereastră pentru selectarea unui fişier

Exemplu 5:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class AplicJOptionPane{

110
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
UIManager.getLookAndFeel());
} catch (Exception e) { }

JFrame frame = new JFrame();


JButton b=new JButton("Apasa-ma");
frame.getContentPane().add(b);
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(new Frame(),
"Fereastra de informare");
}
});
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);
}
}

Fiecare fereastră secundară este dependentă de una principală (de un frame).


O fereastră de dialog poate fi modală. Dacă este modală, ea blochează
accesul la oricare altă fereastră din program.
Cele mai simple ferestre modale pot fi create folosind una din metodele:
• JOptionPane.showMessageDialog – fereastră modală înzestrată
cu un buton. Se poate specifica mesajul, icoana şi titlul ferestrei .
• JOptionPane.showOptionDialog – fereastră modală înzestrată
cu butoane, mesaj, icoana şi titlul ferestrei. Pot fi modificate de
utilizator.
Exemplu 6:
Object[] options = {"Da!!!","Niciodata!!!","Cine stie!!!"};
int n=JOptionPane.showOptionDialog(
new Frame(),
"Ma parasesti?",
"Fereastra de Optiuni",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[2]);

111
• JOptionPane.showConfirmDialog – fereastră modală
înzestrată cu două butoane.
Exemplu 7:
JOptionPane.showConfirmDialog(
null,
"Alege un buton",
"Fereastra de confirmare",
JOptionPane.YES_NO_OPTION);

Parametrii folosiţi de aceste metode:


 parentComponent: poate fi frame-ul care conţine fereastra de dialog
(ea este afişată pornind de la coordonatele ferestrei părinte) sau null
(se foloseşte un frame implicit şi fereastra de dialog este centrată pe
ecran);
 message: mesajul care apare în fereastra de dialog;

 messageType: defineşte stilul mesajului. Valori posibile sunt:


– ERROR_MESSAGE
– INFORMATION_MESSAGE
– WARNING_MESSAGE
– QUESTION_MESSAGE
– PLAIN_MESSAGE
 optionType: defineşte mulţimea de butoane care apar pe fereastră:
– DEFAULT_OPTION
– YES_NO_OPTION
– YES_NO_CANCEL_OPTION
– OK_CANCEL_OPTION
Pot fi folosite şi alte tipuri de butoane;
 options: descriere detaliată a mulţimii butoanelor afişate pe fereastră;
în general, este un vector de String-uri;
 icon: icoana afişată pe fereastră;
 title: titlul ferestrei;

 initialValue: butonul selectat implicit.

112
Metodele showMessageDialog, showConfirmDialog şi showOptionDialog
returnează un întreg semnificând opţiunea utilizatorului. Valorile acestui întreg pot fi
YES_OPTION, NO_OPTION, CANCEL_OPTION, OK_OPTION şi CLOSED_OPTION.

Ferestre de dialog nemodale se pot crea cu JDialog.


JDialog este folosită pentru implementarea ferestrelor secundare (cum ar fi
dialog boxes şi alert boxes) şi a celor utilitare. Această componentă are
caracteristic cadrul şi bara de titlu furnizate de sistemul de operare. Aduce nou faţă
de clasa Dialog suportul pentru operaţia de închidere implicită.

Exemplu 8:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class Dialog{


public static void main(String a[]){
final JFrame frame=new JFrame("Frame-ul meu");
Container contentPane = frame.getContentPane();
contentPane.setLayout(new GridLayout(1,1));
JButton Buton = new JButton("Apasa-ma!");
contentPane.add(Buton);
Buton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Apasa-ma!")) {
final JDialog dialog=new JDialog(frame,
"O fereastra copil",true);
Container c=dialog.getContentPane();
JLabel label=new JLabel("Eticheta frumoasa");
c.add(label);
dialog.pack();
dialog.setVisible(true);
}
}
});
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

frame.pack();
frame.setVisible(true);
}
}

113
9.3.3. Clasa JWindow

Clasa JWindow este folosită pentru implementarea ferestrelor pline


(dreptunghiuri albe pline). Aceste ferestre nu conţin bară de titlu sau controale de
fereastră.
Exemplu 9:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class AplicJWindow {


public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
UIManager.getLookAndFeel());
} catch (Exception e) { }

final JFrame frame=new JFrame("Frame-ul meu");


Container contentPane = frame.getContentPane();
contentPane.setLayout(new GridLayout(1,1));
JButton Buton = new JButton("Apasa-ma!");
contentPane.add(Buton);
Buton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Apasa-ma!"))
{
JWindow win = new JWindow();
JRootPane pane=new JRootPane();
JLabel label=new JLabel("hasd");
pane.setLayout(new FlowLayout());
pane.add(label);
win.getContentPane().add(pane);
win.setSize(200,200);
win.setVisible(true);
}
}
});
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);

}
}

114
9.3.4. Clasa JApplet

Clasa JApplet este folosită pentru implementarea applet-urilor. A se vedea


exemplul 2.

Forma containere-lor principale este ilustrată în figura următoare:

9.4. Containere intermediare

Sunt componente JFC folosite pentru organizarea ferestrelor. Container-ele


intermediare folosesc la împărţirea ferestrei în mai multe zone sau la gruparea
componentelor. Swing furnizează următoarele containere intermediare:

Panel – Este cel mai flexibil şi frecvent utilizat container


intermediar. Se implementează folosind clasa JPanel. Un
panel grupează componentele dintr-o fereastră sau dintr-un
alt panel. Un panel poate folosi orice layout manager şi poate
avea o margine (border).

115
Scroll – Furnizează scroll bar (orizontal şi vertical) pentru
Pane componentele prea mari.
Split – Afişează două componente într-un spaţiu fix, oferind
Pane utilizatorului posibilitatea să redimensioneze fiecare
componentă.
Tabbed – Conţine mai multe componente dar afişează numai
Pane una la un moment dat. Utilizatorul poate alege între
componente.
Tool – Grupează componentele (în general butoane) într-o
Bar linie sau o coloană, permiţând utilizatorului să o mute
oriunde.

Forma containere-lor intermediare este ilustrată în figura următoare:

Exemplu 10: Pentru JScrollPane


JFrame frame = new JFrame("Doar un exemplu");
JTextArea t = new JTextArea(20, 40);
JScrollPane scrpane=new JScrollPane(t);

116
scrpane.setPreferredSize(new Dimension(100, 100));
frame.getContentPane().add(scrpane);
for(int i=0;i<100;i++)
t.append(i+"\n");//(new Integer(i)).toString());

Exemplu 11: Pentru JSplitPane

JFrame frame = new JFrame("Doar un exemplu");


JTextArea t=new JTextArea();
for(int i=0;i<100;i++)
t.append(i+"\n");
JLabel label=new JLabel("hjsdkljasldjasljdlafj");
JSplitPane splitpane=new JSplitPane();
splitpane.setOneTouchExpandable(true);
splitpane.setLeftComponent(t);
splitpane.setRightComponent(label);
splitpane.setPreferredSize(new Dimension(100, 100));
frame.getContentPane().add(splitpane);

Exemplu 11: Pentru JTabbedPane


import javax.swing.JTabbedPane;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JFrame;

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

public class AplicTabbed extends JPanel {


public AplicTabbed() {
JTabbedPane tabbedPane = new JTabbedPane();

Component panel1 = crearePanel("Salut");


tabbedPane.addTab("Unu", panel1);
tabbedPane.setSelectedIndex(0);

Component panel2 = crearePanel("Salut Salut");


tabbedPane.addTab("Doi", panel2);

Component panel3 = crearePanel("Salut Salut Salut");


tabbedPane.addTab("Trei", panel3);

Component panel4 = crearePanel("Salut Salut Salut


Salut");
tabbedPane.addTab("Patru", panel4);

//Se adauga tabbed pane-ul pe panel.


setLayout(new GridLayout(1, 1));
add(tabbedPane);

117
}

protected Component crearePanel(String text) {


JPanel panel = new JPanel(false);
JLabel label = new JLabel(text);
label.setHorizontalAlignment(JLabel.CENTER);
panel.setLayout(new GridLayout(1, 1));
panel.add(label);
return panel;
}

public static void main(String[] args) {


JFrame frame = new JFrame("Exemplu de TabbedPane");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

frame.getContentPane().add(
new AplicTabbed(), BorderLayout.CENTER);
frame.setSize(400, 125);
frame.setVisible(true);
}
}

Figura următoare ilustrează execuţia exemplului.

9.5. Folosirea gestionarilor de poziţionare (Layout Manager)

Un program poate avea interfeţe diferite, chiar dacă sunt folosite aceleaşi
componente. Acest lucru se datorează folosirii a diferiţi gestionari de poziţionare
care controlează dimensiunea şi poziţiile componentelor.
Gestionarea poziţionării este procesul prin care se determină dimensiunea şi
poziţia componentelor. Implicit, fiecare container are un gestionar de poziţionare –
un obiect care gestionează poziţionarea fiecărei componente de pe container. Acest
obiect implementează interfaţa LayoutManager. Acesta poate fi înlocuit cu altul care

118
să fie pe măsura cerinţelor. În general, se setează gestionarul de poziţionare pentru
două tipuri de containere: contentpane (foloseşte implicit BorderLayout) şi
JPanel (foloseşte implicit FlowLayout).
De câte ori se adaugă o componentă pe container trebuie ţinut cont de
gestionarul de poziţionare al containerului respectiv.

9.5.1. Setarea poziţionării (Layout Manager–ului)

Pentru schimbarea layout manager-ului folosit de un container se apelează


metoda setLayout. Metoda poate primi ca parametru orice instanţă a unei clase
care implementează interfaţa LayoutManager. Secvenţa de ataşare a unui gestionar
pentru un container este:
FlowLayout gestionar = new FlowLayout();
container.setLayout(gestionar);
sau:
container.setLayout(new FlowLayout());

De exemplu:
JPanel jp = new JPanel();
jp.setLayout(new BorderLayout());

Dacă argumentul este null, container-ul nu foloseşte un layout manager. În


acest caz trebuie specificate dimensiunile şi poziţiile fiecărei componente de pe
container.
Cei mai folosiţi gestionari în Java sunt: BorderLayout, BoxLayout,
FlowLayout, GridBagLayout şi GridLayout.

9.5.1.1 BorderLayout
BorderLayout este layout manager-ul implicit pentru fiecare container

principal. Un BorderLayout are cinci zone în care pot fi aşezate componentele:


nord, sud, est, vest şi centru.
Exemplu 12:
1. import javax.swing.*;
2. import java.awt.*;

119
3. import java.awt.event.*;

4. public class AplicBorderLayout extends JFrame{


5. public static void main(String[] args) {
6. AplicBorderLayout f=new AplicBorderLayout();
7. Container contentPane = f.getContentPane();
8. contentPane.setLayout(new BorderLayout());
9. contentPane.add(new JButton("Buton 1 NORD"),
BorderLayout.NORTH);
10. contentPane.add(new JButton("2 CENTRU"),
BorderLayout.CENTER);
11. contentPane.add(new JButton("Buton 3 VEST"),
BorderLayout.WEST);
12. contentPane.add(new JButton("Buton 4 SUD"),
BorderLayout.SOUTH);
13. contentPane.add(new JButton("Buton 5 EST"),
BorderLayout.EAST);
14. f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
15. f.setSize(400, 125);
16. f.setVisible(true);
17. }
18. }

Ţinând cont că pentru frame-uri gestionarul implicit este BorderLayout, linia 8


nu mai este necesară. Rezultatul execuţiei acestui program este:

9.5.1.2 BoxLayout

Gestionarul BoxLayout aşează componentele pe o singură linie sau coloană.


Respectă dimensiunile minime ale componentelor şi permite alinierea lor.

Exemplu 13:
import javax.swing.*;

120
import java.awt.*;
import java.awt.event.*;

public class AplicBoxLayout extends JFrame{


private static void adaugBut(String text,
Container container, float unde) {
JButton button = new JButton(text);
button.setAlignmentX(unde);
container.add(button);
}
public static void main(String[] args) {
AplicBoxLayout f=new AplicBoxLayout();
Container contentPane = f.getContentPane();
contentPane.setLayout(new BoxLayout(
contentPane, BoxLayout.Y_AXIS));
adaugBut("Buton 1", contentPane,
Component.CENTER_ALIGNMENT);
adaugBut("2", contentPane,Component.RIGHT_ALIGNMENT);
adaugBut("Buton 3", contentPane,
Component.LEFT_ALIGNMENT);
adaugBut("Buton 4 foarte lung", contentPane,
Component.CENTER_ALIGNMENT);
adaugBut("Buton 5", contentPane,
Component.LEFT_ALIGNMENT);

f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);}
});
f.pack();
f.setVisible(true);
}
}

Rezultatul execuţiei acestui program este:

121
9.5.1.3 CardLayout
Clasa CardLayout permite implementarea unei arii care conţine diferite
componente la momente diferite. Tabbed pane-urile sunt containere intermediare
care furnizează o funcţionalitate similară. Un CardLayout este în general controlat
de un Combo Box, starea lui determinând panel-ul de afişat.
Exemplu 14:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AplicCardWindow extends JFrame


implements ItemListener {
JPanel cards;
String BUTONPANEL = "Panel cu Butoane";
String TEXTPANEL = "Panel cu TextField-uri";

public AplicCardWindow() {
Container contentPane = getContentPane();

String comboBoxItems[] = { BUTONPANEL, TEXTPANEL };


JPanel cbp = new JPanel();
JComboBox c = new JComboBox(comboBoxItems);
c.setEditable(false);
c.addItemListener(this);
cbp.add(c);

contentPane.add(cbp, BorderLayout.NORTH);

cards = new JPanel();


cards.setLayout(new CardLayout());

JPanel p1 = new JPanel();


p1.add(new JButton("Buton 1"));
p1.add(new JButton("Buton 2"));
p1.add(new JButton("Buton 3"));

JPanel p2 = new JPanel();


p2.add(new JTextField("TextField", 20));

cards.add(p1, BUTONPANEL);
cards.add(p2, TEXTPANEL);
contentPane.add(cards, BorderLayout.CENTER);

addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

122
}

public void itemStateChanged(ItemEvent evt) {


CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards, (String)evt.getItem());
}

public static void main(String args[]) {


AplicCardWindow window = new AplicCardWindow();
window.setTitle("CardLayout");
window.pack();
window.setVisible(true);
}
}

În imaginea următoare se văd cele două stări ale ferestrei în funcţie de starea
Combo Box-ului:

9.5.1.4 FlowLayout
FlowLayout este layout manager-ul implicit pentru orice JPanel. Aşează
componentele de la stânga spre dreapta, de sus în jos.
Exemplu 15:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class AplicFlowLayout extends JFrame{


private static void adaugBut(String text,
Container container){
JButton button = new JButton(text);
container.add(button);
}
public static void main(String[] args) {
AplicFlowLayout f=new AplicFlowLayout();
Container contentPane = f.getContentPane();
contentPane.setLayout(new FlowLayout());
adaugBut("Buton 1", contentPane);
adaugBut("2", contentPane);
adaugBut("Buton 3", contentPane);

123
adaugBut("Buton 4 foarte lung", contentPane);
adaugBut("Buton 5", contentPane);

f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);}
});
f.pack();
f.setVisible(true);
}
}
Rezultatul execuţiei acestui program este:

9.5.1.5 GridLayout
GridLayout-ul aşează componentele în celulele unui tabel. Fiecare
componentă ocupă tot locul disponibil din celulă. Toate celulele au aceeaşi
dimensiune. La redimesionarea ferestrei GridLayout-ului, celulele îşi vor schimba
dimensiunile astfel încât să fie ocupat tot spaţiul ferestrei.
Clasa GridLayout are doi constructori:
public GridLayout(int rows, int columns)
public GridLayout(int rows, int columns,
int horizontalGap, int verticalGap)

Cel puţin unul din cele două argumente rows şi columns trebuie să fie nenul.
Argumentele horizontalGap şi verticalGap din cel de-al doilea constructor permit
specificarea numărului de pixeli dintre celule. Implicit ele au valoarea 0.

Exemplu 16:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class AplicGridLayout extends JFrame{


public static void main(String[] args) {
AplicGridLayout f=new AplicGridLayout();
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(0,2));

124
contentPane.add(new JButton("Buton 1"));
contentPane.add(new JButton("2"));
contentPane.add(new JButton("Buton 3"));
contentPane.add(new JButton("Buton 4 foarte lung"));
contentPane.add(new JButton("Buton 5"));
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);}
});
f.pack();
f.setVisible(true);
}
}

Rezultatul execuţiei acestui program este:

Constructorul apelat creează o instanţă a lui GridLayout care are două


coloane şi oricâte linii sunt necesare – new GridLayout(0,2).

9.5.1.6 GridBagLayout
GridBagLayout este cel mai sofisticat şi flexibil layout manager pe care
platforma Java îl furnizează. Aşează componentele în celulele unui tabel, fiecare
componentă putând să ocupe mai multe celule. Liniile / coloanele tabelului nu este
obligatoriu să aibă aceeaşi înălţime / lăţime. Pentru fiecare componentă care se
adaugă pe fereastră se setează o serie de constrângeri prin crearea unui obiect al
clasei GridBagConstraints. Aceeaşi instanţă a lui GridBagConstraints
poate fi folosită pentru mai multe componente, chiar dacă ele au constrângeri
diferite. GridBagLayout extrage valorile constrângerilor şi nu refoloseşte
GridBagConstraints. Clasa conţine următoarele atribute care pot fi setate:
gridx, gridy – Specifică linia şi coloana colţului din stânga sus a
componentei. Coloana cea mai din stânga are gridx=0 iar linia cea mai de sus are
gridy=0.

125
gridwidth, gridheight – Reprezintă numărul de coloane (pentru
gridwidth) sau de linii (pentru gridheight) pe care va fi afişată componenta. Valoarea
implicită este 1.
fill – Este folosită atunci când aria de afişare a componentei este mai mare
decât dimensiunea cerută, pentru a determina cum poate fi redimensionată
componenta. Valorile valide sunt:
• NONE (implicit),
• HORIZONTAL (măreşte componenta pe orizontală astfel încât să
acopere întreaga suprafaţă disponibilă dar nu schimbă înălţimea),
• VERTICAL (măreşte componenta pe verticală astfel încât să
acopere întreaga suprafaţă disponibilă dar nu schimbă lăţimea),
• BOTH (măreşte componenta astfel încât să acopere întreaga
suprafaţă disponibilă.
ipadx, ipady – Folosite pentru redimensionarea celulelor. Specifică cât
trebuie adunat la dimensiunea minimă a componentei. Valoarea implicită este 0.
Lăţimea / înălţimea va avea valoarea minimă plus ipadx*2 / ipady*2 pixeli (se aplică
în ambele capete ale componentei).
insets – Specifică distanţa dintre componentă şi colţurile suprafeţei pe care
se afişează. Valoarea atribuită este un obiect Insets.
anchor – Este folosită atunci când componenta este mai mică decât suprafaţa
pe care urmează să fie afişată, pentru a determina unde se plasează componenta.
Valori valide sunt CENTER (implicit), NORTH, NORTHEAST, EAST, SOUTHEAST,
SOUTH, SOUTHWEST, WEST şi NORTHWEST.
weightx, weighty – Folosite pentru a determina modul în care să fie
repartizat spaţiul dintre coloane / linii. Dacă nu se specifică nici o valoare (implicit
este 0) atunci toate componentele vor fi grupate în centru container-ului deoarece
GridBagLayout pune orice spaţiu în plus între tabel şi colţurile container-ului.

Exemplu 17:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AplicGridBagLayout extends JFrame {


final boolean shouldFill = true;
final boolean shouldWeightX = true;

126
public AplicGridBagLayout() {
JButton buton;
Container contentPane = getContentPane();
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
contentPane.setLayout(gridbag);
if (shouldFill) {
//inaltime implicita, latime maxima
c.fill = GridBagConstraints.HORIZONTAL;
}

buton = new JButton("Buton 1");


if (shouldWeightX) {
c.weightx = 0.5;
}
c.gridx = 0;
c.gridy = 0;
gridbag.setConstraints(buton, c); //constrangerile
impuse sunt atasate componentei
contentPane.add(buton);

buton = new JButton("2");


c.gridx = 1;
c.gridy = 0;
gridbag.setConstraints(buton, c);
contentPane.add(buton);

buton = new JButton("Buton 3");


c.gridx = 2;
c.gridy = 0;
gridbag.setConstraints(buton, c);
contentPane.add(buton);

buton = new JButton("Buton 4 foarte lung");


c.ipady = 40; //seteaza cu cat va creste
inaltimea componentei
c.weightx = 0.0;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 1;
gridbag.setConstraints(buton, c);
contentPane.add(buton);

buton = new JButton("Button 5");


c.ipady = 0; //se revine la inaltimea implicita
c.weighty = 1.0; //spatiu vertical intre celule
suplimentar
c.anchor = GridBagConstraints.SOUTH; //componenta va
fi plasata in partea de jos a ferestrei
c.insets = new Insets(10,0,0,0);

127
c.gridx = 1; //componenta se alinieaza cu
butonul 2
c.gridwidth = 2; //ocupa latimea a doua butoane
c.gridy = 2; //se afla pe a treia linie
gridbag.setConstraints(buton, c);
contentPane.add(buton);

addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}

public static void main(String args[]) {


AplicGridBagLayout window = new AplicGridBagLayout();
window.setTitle("Exemplu GridBagLayout");
window.pack();
window.setVisible(true);
}
}
Rezultatul execuţiei acestui program este:

9.6. Tratarea evenimentelor

Apăsarea unei taste sau a unui buton al mouse-ului declanşează un


eveniment. Pentru a trata evenimentul este necesar un obiect care să implementeze
interfaţa corespunzătoare şi să fie înregistrat ca un consumator de evenimente
(event listener). Componentele Swing pot genera mai multe tipuri de evenimente.
Câteva dintre interfeţele corespunzătoare ar fi:

ActionListener acţiuni asupra unui control (click pe un


buton, Enter după introducerea unui text într-

128
un câmp, selectarea într-un meniu)
ComponentListener redimensionări, deplasări, ascunderi ale
unei componente
FocusListener preluare / pierdere focus
ItemListener selecţie / deselecţie obiect în listă,
meniu, etc.
TextListener modificarea textului din control
AdjustmentListener modificarea unei valori variind între
două limite (ex: ScrollBar)
KeyListener acţionarea unei taste
MouseListener apăsarea butonului mouse-ului în timp
ce cursorul se află pe componenta respectivă
MouseMotionListener drag; mişcarea mouse-ului pe o
componentă
WindowListener închidere, minimizare, maximizare etc.
ContainerListener adăugare, ştergere componentă
ListSelectionListener schimbarea selecţiei într-o tabelă sau
într-o listă

Fiecare eveniment este reprezentat de un obiect care dă informaţii despre


eveniment şi identifică sursa evenimentului. Fiecare generator de eveniment poate
avea mai mulţi consumatori.

generator obiect eveniment /----> consummator de eveniment


de eveniment------------------------------------------> consummator de eveniment
\----> consummator de
eveniment

Un eveniment, o dată apărut, este distribuit tuturor ascultătorilor înregistraţi (nu


este consumat numai de primul).
Aşa cum am spus mai devreme, pentru ca evenimentele unei componente să
fie interceptate de către o instanţă a unei clase ascultător, această clasă trebuie
înregistrată în lista ascultătorilor componentei respective. Am spus listă, deoarece
evenimentele unei componente pot fi ascultate de oricâte clase - cu condiţia ca
acestea să fie înregistrate la componenta respectivă. Înregistrarea unei clase în lista
ascultătorilor unei componente se face cu metode din clasa Component de tipul

129
addXXXListener, iar eliminarea ei din aceasta lista cu removeXXXListener unde
XXX reprezintă tipul evenimentului.

9.6.1. Exemplu de tratare a unui eveniment

Sunt necesari următorii paşi:

1. Clasa trebuie să implementeze interfaţa corespunzătoare sau să


extindă o clasă care implementează interfaţa.

public class NumeClasa implements ActionListener {...}

2. Scrierea codului care înregistrează o instanţă a clasei (care va


consuma evenimentul) ca şi consumator pentru una sau mai multe componente.

Componenta.addActionListener(instantaNumeClasa);

3. Scrierea codul care implementează metodele din interfaţa


consumator.

public void actionPerformed(ActionEvent e) {


//cod care reacţioneaza la acţiune
}

Exemplu 18:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class AplicEv extends JFrame{

JButton uB,lB,rB;
JPanel pbut;
JTextField txt;
Listener lsn;
TextWorker txtWorker;
public AplicEv() {
uB=new JButton("Majuscule");
lB=new JButton("Minuscule");

130
rB=new JButton("Sterge");
uB.setActionCommand("ActMajuscule");
lB.setActionCommand("ActMinuscule");
pbut=new JPanel();
pbut.add(uB);
pbut.add(lB);
pbut.add(rB);
txt= new JTextField("Introduceti text!");
lsn=new Listener();
getContentPane().setLayout(new BorderLayout());
getContentPane().add("North",txt);
getContentPane().add("Center",lsn);
getContentPane().add("South",pbut);
txtWorker=new TextWorker(txt);
rB.addActionListener(lsn);
uB.addActionListener(lsn);
lB.addActionListener(lsn);

rB.addActionListener(txtWorker);
uB.addActionListener(txtWorker);
lB.addActionListener(txtWorker);
}
public static void main(String[] args) {
AplicEv f=new AplicEv();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.addWindowListener(f.lsn);

f.setSize(400, 125);
//f.pack();
f.setVisible(true);
}
}

class TextWorker implements ActionListener {


private JTextField txt;

public TextWorker(JTextField txt){


this.txt=txt;
}

public void actionPerformed(ActionEvent e){


String c=e.getActionCommand();
if(c.equals("Sterge"))
txt.setText("");
if(c.equals("ActMajuscule")){
String oldText=txt.getText();
String uText=oldText.toUpperCase();
txt.setText(uText);

131
}
if(c.equals("ActMinuscule")){
String oldText=txt.getText();
String lText=oldText.toLowerCase();
txt.setText(lText);
}
}
}

class Listener extends JTextArea implements ActionListener,


WindowListener{
public Listener(){
super();
this.setEditable(false);
}
public void actionPerformed(ActionEvent e){
append(e.paramString()+" [ "+e.toString()+" ]\n");
}
public void windowClosed(WindowEvent e){
append(e.paramString()+" [ "+e.toString()+" ]\n");
}
public void windowOpened(WindowEvent e){
append(e.paramString()+" [ "+e.toString()+" ]\n");
}
public void windowClosing(WindowEvent e){
append(e.paramString()+" [ "+e.toString()+" ]\n");
}
public void windowIconified(WindowEvent e){
append(e.paramString()+" [ "+e.toString()+" ]\n");
}
public void windowDeiconified(WindowEvent e){
append(e.paramString()+" [ "+e.toString()+" ]\n");
}
public void windowActivated(WindowEvent e){
append(e.paramString()+" [ "+e.toString()+" ]\n");
}
public void windowDeactivated(WindowEvent e){
append(e.paramString()+" [ "+e.toString()+" ]\n");
}
}

Rezultatul execuţiei programului este:

9.7. Folosirea componentelor

9.7.1. Clasa JLabel

132
Un obiect de tip JLabel (etichetă) reprezintă o componentă pentru plasarea
unui text pe o suprafaţă de afişare. O etichetă este formată dintr-o singură linie de
text static ce nu poate fi modificat de către utilizator, dar poate fi modificat din
program.

9.7.2. Clasa JButton

Un obiect de tip JButton (buton) reprezintă o componentă pentru plasarea


unui buton etichetat pe o suprafaţă de afişare.

9.7.3. Clasa JTextField

Un obiect de tip JTextField defineşte un control de editare a textului pe o


singură linie. Este util pentru interogarea utilizatorului asupra unor valori.

9.7.4. Clasa JTextArea

Un obiect de tip JTextArea defineşte un control de editare a textului pe mai


multe linii. Este util pentru editarea de texte, introducerea unor comentarii, etc .

9.7.5. Clasa JCheckBox

Un obiect de tip JCheckbox (comutator) reprezintă o componentă care se


poate afla în două stări : "selectată" sau "neselectată" (on/off). Acţiunea utilizatorului
asupra unui comutator îl trece pe acesta în starea complementară celei în care se
găsea. Este folosit pentru a prelua o anumită opţiune de la utilizator.

9.7.6. Clasa JRadioButton

Un obiect de tip JRadioButton defineşte un grup de comutatoare din care


doar unul poate fi selectat. Uzual, aceste componente se mai numesc radio
butoane.

133
9.7.7. Clasa JComboBox

Un obiect de tip JComboBox defineşte o listă de opţiuni din care utilizatorul


poate selecta una singură. La un moment dat, din întreaga lista doar o singură
opţiune este vizibilă, cea selectată. O componentă JComboBox este însoţită de un
buton etichetat cu o săgeată verticală la apăsarea căruia este afişată întreaga sa
listă, pentru ca utilizatorul să poată selecta o anumită opţiune.

9.7.8. Clasa JList

Un obiect de tip JList defineşte o listă de opţiuni care poate fi setată astfel
încât utilizatorul să poată selecta o singură opţiune sau mai multe. Toate opţiunile
listei sunt vizibile în limita dimensiunilor grafice ale componentei.

9.7.9. Clasa JScrollBar

Un obiect de tip JScrollbar defineşte o bară de defilare verticală sau


orizontală. Este utilă pentru punerea la dispoziţie a utilizatorului a unei modalităţi
sugestive de a alege o anumită valoare dintr-un interval.

1. Introducere în limbajul de programare Java..................................................1


1.1. Ce este Java?.........................................................................................1
1.2. Limbajul de programare Java ................................................................1
1.3. Java : un limbaj compilat şi interpretat....................................................3
1.4. Istoria limbajului Java.............................................................................3
1.5. Mediul Java............................................................................................4
1.6. Crearea unei aplicaţii simple ..................................................................4
1.7. Crearea unui applet................................................................................5
2. Programarea Orientată pe Obiecte şi Java...................................................7
2.1. Obiecte şi clase......................................................................................7
2.2. Atribute şi comportamente......................................................................8
2.2.1. Atribute.............................................................................................8
2.2.2. Comportament.................................................................................9

134
2.3. Principiile OOP.....................................................................................10
3. Elementele de bază ale limbajului de programare Java..............................11
3.1. Structura lexicală a limbajului...............................................................11
3.1.1. Setul de caractere..........................................................................11
3.1.2. Cuvinte cheie.................................................................................11
3.1.3. Identificatori....................................................................................11
3.1.4. Constante.......................................................................................12
3.1.5. Separatori......................................................................................13
3.1.6. Operatori........................................................................................13
3.1.7. Comentarii......................................................................................17
3.2. Tipuri de date........................................................................................17
3.3. Variabile................................................................................................18
3.4. Instrucţiuni............................................................................................20
3.4.1. Instrucţiunea vidă...........................................................................20
3.4.2. Instrucţiuni de decizie.....................................................................20
3.4.3. Instrucţiuni repetitive......................................................................23
3.5. Tablouri (vectori)...................................................................................28
3.5.1. Tablouri (vectori) unidimensionale..................................................28
3.5.2. Tablouri (vectori) cu mai multe dimensiuni.....................................29
3.5.3. Dimensiunea unui vector ...............................................................30
3.5.4. Tablouri cu dimensiuni variabile.....................................................31
3.6. Şiruri de caractere................................................................................32
4. Clase şi obiecte în Java..............................................................................33
4.1. Referinţe...............................................................................................33
4.2. Obiecte.................................................................................................34
4.2.1. Noţiuni generale.............................................................................34
4.2.2. Operatorul de atribuire =................................................................35
4.2.3. Operatorul de egalitate ==..............................................................37
4.3. Clase....................................................................................................38
4.3.1. Definirea claselor...........................................................................38
4.3.2. Variabile membru...........................................................................39
4.3.3. Metode...........................................................................................41
4.3.3.1 Definirea metodelor..................................................................41
4.3.3.2 Modificatorii metodelor..............................................................41

135
4.3.3.3 Tipul returnat de o metodă........................................................42
4.3.3.4 Parametrii unei metode.............................................................43
4.3.4. Constructorii unei clase..................................................................44
4.3.5. Obiectul this...................................................................................46
4.3.6. Supraîncărcarea şi supradefinirea metodelor.................................48
4.3.7. Modificatori de acces pentru membrii unei clase............................49
4.3.8. Membrii instanţă şi membrii clasă..................................................50
4.3.9. Argumente în linia de comandă......................................................53
4.4. Moştenirea............................................................................................55
4.4.1. Principiul moştenirii........................................................................55
4.4.2. Interfeţe..........................................................................................59
4.5. Probleme..............................................................................................62
5. Pachete.......................................................................................................70
5.1. Importul unui pachet, al unei clase sau a unei interfeţe........................71
5.2. Crearea unui pachet.............................................................................72
6. Excepţii ......................................................................................................77
6.1. Aspecte generale..................................................................................77
6.2. Instrucţiunea try....................................................................................78
6.3. Crearea unei excepţii............................................................................80
7. Intrări şi ieşiri ..............................................................................................84
7.1. Clasificarea fluxurilor............................................................................85
7.2. Ierarhia claselor pentru lucrul cu fluxuri................................................85
7.2.1. Fluxuri de caractere.......................................................................85
7.2.2. Fluxuri de octeţi..............................................................................86
7.3. Superclasele de intrare / ieşire.............................................................87
7.4. Crearea unui flux..................................................................................88
7.5. Citirea datelor de la tastatură................................................................89
7.5.1. Obiectul System.in.........................................................................89
7.5.2. Clasa InputStreamReader..............................................................90
7.5.3. Clasa BufferedReader....................................................................90
7.6. Citirea şi scrierea datelor din fişier.......................................................91
7.6.1. Clasele FileReader şi FileWriter ....................................................91
8. Applet-uri ....................................................................................................93
8.1. Ce este un applet?................................................................................93

136
8.2. Funcţiile unui applet .............................................................................94
8.3. Structura generală a unui applet ..........................................................95
8.4. HTML....................................................................................................96
8.5. Exemple................................................................................................97
9. Interfeţe grafice.........................................................................................104
9.1. Ce este o interfaţă grafică?.................................................................104
9.2. Primele aplicaţii Swing........................................................................105
9.2.1. Exemple.......................................................................................105
9.2.2. Comentarea exemplelor...............................................................107
9.2.2.1 Alegerea naturii interfeţei .......................................................107
9.2.2.2 Setarea container-ului principal (din vârful ierarhiei)...............107
9.2.2.3 Manipularea evenimentelor.....................................................108
9.3. Containere principale..........................................................................108
9.3.1. Clasa JFrame...............................................................................109
9.3.2. Ferestre secundare şi clasa JDialog ...........................................110
9.3.3. Clasa JWindow ...........................................................................114
9.3.4. Clasa JApplet ..............................................................................115
9.4. Containere intermediare.....................................................................115
9.5. Folosirea gestionarilor de poziţionare (Layout Manager)....................118
9.5.1. Setarea poziţionării (Layout Manager–ului)..................................119
9.5.1.1 BorderLayout..........................................................................119
9.5.1.2 BoxLayout...............................................................................120
9.5.1.3 CardLayout.............................................................................122
9.5.1.4 FlowLayout.............................................................................123
9.5.1.5 GridLayout .............................................................................124
9.5.1.6 GridBagLayout .......................................................................125
9.6. Tratarea evenimentelor ......................................................................128
9.6.1. Exemplu de tratare a unui eveniment ..........................................130
9.7. Folosirea componentelor....................................................................132
9.7.1. Clasa JLabel................................................................................132
9.7.2. Clasa JButton ..............................................................................133
9.7.3. Clasa JTextField .........................................................................133
9.7.4. Clasa JTextArea ..........................................................................133
9.7.5. Clasa JCheckBox.........................................................................133

137
9.7.6. Clasa JRadioButton .....................................................................133
9.7.7. Clasa JComboBox .......................................................................134
9.7.8. Clasa JList ...................................................................................134
9.7.9. Clasa JScrollBar ..........................................................................134

138

Você também pode gostar