Java Basis
Java Basis
Java este un limbaj de programare orientat obiect, asemãnator cu C++, dar cu un alt
conţinut important ceea ce il face un instrument foarte robust pentru dezvoltarea de aplicaţii
WWW. Menirea limbajului Java este de a fi un standard pentru transferul de conţinut executabil pe
Internet prin WWW. Datorită limbajului Java se schimbă natură pasivă a reţelei Internet, deoarece
un program binar portabil generat de compilatorul Java, poate fi încarcat şi executat în mod
interpretativ pe orice calculator legat la Internet.
Proiectarea orientată pe obiecte este un instrument puternic, deoarece facilitează definirea
clară a interfeţelor şi permite reutilizarea unor module de program identificate ca şi obiecte. Fiind
conceput ca un limbaj obiectual, tot ce există într-un program este incapsulat în obiecte, care în
Java poartă denumirea de clase, limbajul permiţâd moştenirea şi extinderea unei clase şi
reutilizarea oricărui program sau modul în alte programe.
O clasa Java este o colecţie de variabile şi de metode, care încapsulează o anumită
funcţionalitate, într-un obiect reutilizabil şi încărcabil în mod dinamic. Mediul Java încarcã în mod
dinamic clasele, ceea ce înseamnă ca un program Java care se execută poate adăuga funcţionalităţi
noi în mod dinamic, prin încãrcarea claselor necesare la un moment dat.
Portabilitatea programelor este un deziderat major, care nu se poate realiza numai printr-o execuţie
interpretativa şi în acest sens în mediul Java pentru Internet un program sursă este compilat mai
intâi în cod binar portabil (codul binar), care este apoi adaptat cerinţelor codului nativ al
calculatorului pe care se execută. Aceast mecanism este o maşină Java virtuală (JVM), care la
rândul ei este implementată pe orice calculator ca şi interpretorul Java. Portabilitatea este asigurată
şi prin standardizarea tipurilor fundamentale.[LEMA-96]
Robusteţea mediului permite scrierea unor programe suple şi puternice, care funcţionează
corect astfel încât totul se decide dinamic, în timpul execuţiei, pentru a evita conflicte. Gestiunea
memoriei se realizează automat, nu prin instrucţiuni scrise în programul sursă ci printr-un sistem
complex implementat astfel încât să gestioneze clasele şi obiectele utilizate, interfeţele necesare şi
să elibereze în mod dinamic spaţiul de memorie neutilizat.
Avand în vedere ca mediul Java este un mediu de programare şi utilizare distribuit pe Internet,
care este implementat pe principiile tehnologiei Corba, se impun metode de protecţie atât pentru
sistemele clienţilor, cât şi pentru servere. Java permite crearea unor sisteme protejate, realizate
prin:[An-97]
Eliminarea pointerilor ca punctele slabe ale securităţii sistemelor împreună cu
aritmetica pointerilor, recunoscută ca o cauză importantă ce determină distrugeri
accidentale ale sistemelor.
Gestiunea automată a memoriei prin alocarea spaţiului la crearea un obiect şi
urmărirea pe parcursul execuţiei appletului până în momentul în care acesta nu mai este
referit, caz în care memoria este dezalocată automat. In opoziţie, gestiunea memoriei in C
şi C++ este realizată explicit de programatori cu ajutorul instrucţiunilor malloc şi free,
precum şi cu alte funcţii standard de gestiune a memoriei.
1
Alocarea dinamicã a memoriei este realizată automat în timpul execuţiei pentru
clasele create, eliminând alocarea statică a memoriei.
Gestionarea spaţiului alocat separat pentru fiecare clasă este soluţionată de
interpretorul Java care oferă spaţiu separat de variabile pentru clasele create.
Verificarea codului binar înainte de execuţie de către interpretorul Java, care
testeazã anumite convenţii ale limbajului şi ale mediului Java. Astfel se verifică dacă nu se
va execută o acţiune daunatoare pentru sistem: violarea restrictiilor de acces, efectuarea
unor conversii ilegale de date, depãşirea superioară sau inferioară a stivei, etc.
Reţea, clurul cu protocoale TCP/IP(Transmission Control , UDP(User Datagram
protocol), IP (Internet Protocol)
Internaţionalizare prin adaptarea programelor la setări locale de limbă şi fus orar.
Securitate la diverse niveluri, gestiunea cheilor publice şi private, restricţii selective
de acces, control şi securitate,etc.
Componente software reutilizabile -JavaBeans integrabile în arhitectura existentă.
Serializare/ deserializare de obiecte, care permite persistenţa şi comunicaţia între
obiecte la distanţă folosind Remote Method Invocation (RMI)
Acces la baze de date relaţionale, de diverse tipuri, folosint Java Database
Connectivity (JDBC)
Grafică bi/tridimensională, animaţie, etc.
Performanţele mediului sunt date şi de codul binar portabil rezultat în urma compilãrii, care
este adaptat în timpul execuţiei la codul nativ al calculatorului real pe care se rulează aplicaţia. In
anumite situaţii, compilarea este amânată pană în momentul execuţiei.
Java este un sistem dinamic extensibil, care poate achizitiona fişiere din orice punct al retelei
Internet. Fiind orientat pe obiecte, extensibilitatea dinamică se răsfrânge şi asupră obiectelor, caz
în care un program poate achizitiona în mod dinamic, din orice punct al reţelei, clasele de care are
nevoie în timpul execuţiei. In Java legarea variabilelor şi a metodelor se face tarziu (late binding),
chiar în momentul execuţiei iar interpretorul este cel care rezolvă referinţele simbolice şi
determină alocarea dinamică a memoriei. Regăsirea variabilelor şi a metodelor se face prin nume,
nu prin adrese relative. Orice clasa poate fi modificată in orice moment, fără a fi nevoie să se
recompileze toate subclasele sale. Avantajul referinţelor în momentul execuţiei este dat de
posibilitatea utilizării dinamice a claselor, care se pot actualiza tot timpul.
Limbajul Java a fost proiectat cu scopul de a se realiza un mijloc de transfer a conţinutului
executabil, dinamic, pe Internet iar funcţiile de reţea sunt cele care trebuie implementate în mediul
Java astfel încât să poată fi exploatat ca un mediu distribuit în Internet.
Odată cu paradigma business object, Enterprise1 Java s-a răspândit rapid în lumea calculatoarelor
desemnând acele aplicaţii Java dezvoltate pentru intranet-ul unei companii, care foloseşte
tehnologii Internet ca:e-mail, ftp, telnet, news, servicii Web,etc.
2
programul aşteaptă intervenţia utilizatorului, sau este ocupat cu accesul la fişiere sau la reţea. In
aplicaţiile cu un singur fir de aşteptare, unitatea centralã rãmâne neocupată intervale lungi de timp.
In mediul Java, acest timp este ocupat imediat de alte fire de execuţie, prin care se realizează
anumiţe acţiuni specifice.[Naugh-96]
Deşi este un limbaj de programare destinat WWW, permite definirea de aplicaţii independente,
fiind executate în mod interpretativ. Astfel se pot realiza aplicaţii pentru domenii ca: editoare de
texte, foi de calcul, baze de date, proiectare asistată de calculator. Utilizarea aplicaţiilor
independente în contextul unui mediu distribuit pe Internet oferă posibilitatea lansării de aplicaţii
care se află pe alte calculatoare dar pentru utilizarea applet-urilor java este necesară accesarea unor
site-uri Web cu browsere dotate cu interpretoare Java.
Pentru programatori, limbajul Java oferă o platformă unică pentru dezvoltarea de aplicaţii - un
calculator virtual, maşină virtuală Java şi aplicaţiile care se dezvoltă sau se distribuie pe reteaua
Internet. Pentru utilizatori, conţinutul executabil Java asigură integrarea perfectă a datelor cu
funcţiile şi interactiunile programelor, precum şi cu lucrul în retea, fără a fi sunt necesare aplicaţii
ajutatoare (helper applications) sau fişiere ajutătoare pentru diferite tipuri de protocoale, deoarece
Java permite încapsularea datelor şi a metodelor în clase.
3
Aplicaţiile de sine stătătoare (standalone) sunt foarte uşor de realizat deoarece Java este un limbaj
de programare complet, configurat OO. Când appleturile rulează fără browser disponibil java,
aplicaţiile standalone sunt complet autorizate, putând rula pe un calculator, sau preluâd avantajele
suportului Internet oferit de Java API. Spre exemplu Sun HotJava este scris complet în limbajul
Java.
Un alt exemplu este cel în care există o bază de date (BD) centrală pe un calculator şi toţi
utilizatorii din firmă au acces la ea, chiar dacă birourile sunt plasate în diverse locuri din oraş sau
chiar în oraşe diferite. Practic întregul program front-end care accesează BD este conceput ca
aplicaţie client ce nu trebuie portată şi recompilată pentru diverse platforme, avantaj resimţit mai
ales la construcţia interfeţei utilizator. Acelaşi program client este compilat o singură dată şi poate
rula pe toate platformele, iar funcţiile interfeţei utilizator sunt aceleaşi. Chiar dacă HTML este
independent de platformă, apar probleme când se introduce o cerere incompletă sau impropriu
formulată în cadrul unui formular. Java oferă posibilitatea de a crea “forme inteligente” (smart
form) care verifică legitimitatea cererilor de intrare ale clientului, eliminând consumurile
inadecvate de lăţime de bandă din scenariul anterior.
Din punct de vedere teoretic nu sunt restricţii cu privire la aplicaţiile de sine stătătoare, respectiv
tot ce realizează acestea poate realiza un applet rezident pe pagina Web. Se preferă appleturile
deoarece oferă securitate a structurilor construite pe un [Link] poate utiliza structuri de date
gestionate de Security Manager şi indiferent de localizarea calculatorului poate activa sau inhiba
programe Java pentru a prelucra operaţii certe: încărcarea automată a unui program sau formă
dintr-o locaţie Internet, închiderea/deschiderea unui fişier,[Link] lucru este utilizat pentru a
preveni încărcarea unui applet infectat (ca şi virulsul Troian Horse), care poate crea prejudicii
acestui applet (sau sistemului local de fişiere) ori să faciliteze curiozităţi neautorizate din exterior.
Unele caracteristici de securitate sunt accesibile din caseta de dialog a meniului Security
Preferences dar nu pot fi modificate de utilizator şi nici nu pot fi alterate de codul încărcat de un
host la distanţă. Netscape ca şi alte browsere impune doar limitări extinse la appleturile ce
beneficiază de înteaga gama de facilităţi Java, dar este necesară dezvoltarea browserelor pentru a
limita extensiile de către acei utilizatori care pot relaxa restricţiile de securitate locală ale
appleturilor. Interacţiunea utilizator-utilizator prin reţea poate fi necesară pentru a avea aplicaţii
Java de sine stătătoare, care sunt implementate cu politici diferite de securitate pe Netscape, luând
măsuri specifice pentru drepturi, pentru a se asigura că nu pot apare breşe de securitate.[An_96]
Protocol handler este un progam care aparţine JDK şi permite unui browser disponibil Java
interpretarea unui nou tip de protocol. Acest lucru elimină inconvenientul browserelelor
tradiţionale, unde apariţia unui nou protocol implica dezvoltarea browserului, astfel încât să
conţină tot codul ce permite manipularea solicitărilor făcute de protocol, ceea ce implică realizarea
unui program monilitic, care consumă multă memorie RAM. Dezvoltarea browserelor disponibile
Java este modulară şi extensibilă iar browserul în sine este un program cu flux liniar, care
utilizează un set de protocoale ce reprezintă repertoriul curent ce poate fi interpretat.
Manipulatorul poate fi încărcat "transparent" astfel încât utilizatorul nu trebuie să fie preocupat de
detalii, singura sarcină fiind accea de a naviga în URL-ul propice. Protocul handler încarcă în
background tot ce trimite browserul iar browserul îşi încarcă doar handler-ele necesare realizând o
optimizare a memoriei RAM ocupate.
Content handlers are rolul de a furniza o alternativă a ideii de aplicaţii standallone, permiţând
programatorului Java să scrie codul ce extinde browserul, dându-I abiliatea de a interpreta
conţinutul inline fără a solicita apelul unor aplicaţii externe. In dezvoltarea browserelor
programatorii şi-au dat seama că nu se poate determina tipul conţinutului trimis prin MIME şi
apoi să se lege browserul de "helper-e" prezente pe calculatorul local al utilizatorului. Content
4
handler este încărcat automat la fel ca şi protocul handler, atunci când se accesează pagina Web, ce
conţine un nou tip (video, audio, conţinut special de pe Web, etc) deşi Netscape nu suportă
modelul Java pentru content handler.
Pentru a realiza o aplicaţie Java sunt necesare un editor de texte, JDK (Java Development Kit) şi
un browser disponibil [Link] de platforma utilizată, la despachetarea JDK se crează
directorul JAVA şi o serie de subdirectoare (lib - ce conţine fişierul [Link], bin - ce conţine
codul binar executabil pentru unelte Java memorate, javac - interpretor java de sine stătător şi
appletviewer). Acestea nu se despachetează pentru a nu consuma spaţiu de memorie pe disc. In
final se setează variabilele de mediu CLASSPATH care identifică locaţia unde se caută uneltele
Java pentru orice clasă care nu este găsită în partea standard, inclusă în JDK.
In momentul de fată sunt întâlnite mai multe tipuri de aplicaţii scise în limbajul Java:
♦ appleturi - aplicaţiile ce rulează într-un browser ce suportă Java şi respectă convenţii clar
definite;
♦ aplicaţiide sine stătătoare (standalone)- foarte uşor de realizat deoarece Java este un limbaj
de programare complet, configurat OO. Când appleturile rulează fără browser disponibil java,
aplicaţiile standalone sunt complet autorizate, putând rula pe un calculator, sau preluâd
avantajele suportului Internet oferit de Java API. Spre exemplu Sun HotJava este scris complet
în limbajul Java.
♦ appletcation sau applet-aplicaţiile care sunt tratate în context, fie ca aplicaţii grafice
standalone de către interpretorul Java, fie appleturi de către browser disponibil java, sau
appletviewer.
♦ servlet - aplicaţii similare cu appleturile dar care rulează într-o aplicaţie ce rezidă pe un Web
server care suportă Java şi respectă conveţiile impuse. Practic servle-urile rezidă în aplicaţii
Web interactive şi înlocuiesc CGI-urile, mărind performanţele aplicaţiilor.
Crearea şi editarea codului Java presupune încapsularea în clase Java. In general fiecare clasă
trebuie să meargă cu propriul fişier sursă, numit prealabil înaintea clasei (spre exemplu:
[Link]). De fapt se pot edita mai multe clase într-un fişier sursă, depinzând de declaraţiile
public realizate şi se poate utiliza un editor standard, pentru Windows sau Unix.
Dacă se utilizează IDE (Java Integrated Development Environment) ca şi Symatecs Café pentru
Windows NT sau Natural Intelligence Roaster pentru Macintosh, se apelează la editorul
încorporat. IDE are avantajul creării documentului sursă, compilării, rulării şi depanării într-un
mediu încorporat.
Dacă appletul este integrat într-un fişier HTML, apelul se face din secţiunea BODY astfel:
5
}
Explicaţiile codului:
Pentru a avea acces la metodele de desenare pe ecran se importă clasa/clasele în care sunt declarate
aceste metode (Graphics), din pachetul [Link]. Pachetul este o legătură de clase aflate în relaţie.
Appletul este declarat ca şi clasa public, pentru a putea fi accesibilă interpreterului construit în
Web browser sau aplletviewer, de oricâte ori rulează.
Când codul sursă este compilat, numele fişierelor class este luat din numele clasei din codul sursă
şi nu din numele fişierului ce conţine codul sursă, (spre exemplu: [Link]) iar dacă în codul
sursă sunt încă două clase declarate (A şi B), atunci vor apare 3 fişiere: [Link], [Link] şi
[Link]. Menţinerea paralelismului între fişierul sursă şi fişierul de ieşire este făcută uşor,
permiţând recompilarea automată a oricărei clase necesare.
Metoda paint este apelată din exteriorul appletului ori de câte ori interpreterul java are nevoie să
afişeze sau să reafişeze un applet. Atunci când este apelată, se trece obiectul în context grafic,
(clasa Graphics) ca parametru. De aceea se importă clasa Graphics pentru a furniza compilatorului
caracteristicile clasei. AWT este legat de limbajul Java şi nu este construit în acesta astfel încât ori
de câte ori [Link]() este apelat, se apelează metoda definită în clasa Graphics pentru a
desena în context grafic. Primul parametru este şirul desenat iar ceilalţi doi sunt coordonatele
verticale şi orizontale ale punctului de unde începe linia de bază a primului caracter din şir.
Punctul este măsurat în pixeli din marginea stânga-sus a appletului pe pagină, astfel încât y creşte
ca şi cum s-ar muta în jos pe ecran.[Ramb_96]
Compilarea aplletului presupune că directorul ce conţine codul binar Java este în PATH iar
uneltele JDK sunt în CLASSPATH. Comanda de compilare este:
javac nume_fiş[Link]
Compilatorul rulează şi apoi se întoarce la prompter iar în cazul erorilor de compilare se fac
corecţiile necesare, relansând compilatorul. De obicei apelul compilatorului se face din directorul
unde se află fişierul sursă, rezultând, conform exemplului anterior:
[Link]
[Link]
[Link]
Dacă se doreşte vizualizarea sursei compilate se foloseşte:
javap -c Primul
şi apare reprezentarea în instrucţiuni a codul binar generat pentru acest fişier.
Execuţia appletului solicită un browser disponibil Java sau appletviewer oferit de JDK. Browserul
permite vizualizarea întregii pagini ce conţine appletul iar appletviewer vizualizează doar appletul,
ignorând comenzile HTML ce nu privesc execuţia appletului.
Exemple:
[Link]
sau appletviewer [Link]
Dacă apelul se face din alt director se indică şi calea completă către fişier astfel:
C:>appletviewer [Link] (la Windows 98)
sau:
appletviewer [Link] (la UNIX)
6
Observaţie:
Argumentul din appletviewer nu este fiş[Link] sau .java ci mai degrabă URL-ul fişierului html,
care include protocolul utilizat pentru acest fişier (file sau http dacă este accesat la distanţă).
Aplicaţiile standalone (de sine stătătoare) sunt semnificativ diferite faţă de appleturi în termeni de
structură. Appleturile moştenesc avantajele atributelor şi comportamentului claselor din AWT şi ca
rezultat, sunt capabile să iasă "din tipar pentru a utiliza facilităţi ale GUI din AWT. Aplicaţiile
standalone pot fi utilizate cu GUI din AWT dar solicită efort suplimentar pentru a le realiza.
Toate aplicaţiile au definită o metodă main(), care indică interpretorului de unde începe execuţia
programului.
Exemplu :
class NumeClasa{
public static void main (String args[]) {
[Link] ("Test de programare Java");
…
}
}
Daca în clasa care se defineşte se vor folosi elemente din alte clase disponibile în mediul Java, este
nesesară realizarea unui import de clase iar declaraţia de import trebuie să apară înaintea claselor
care folosesc elementele respective.
Exemplu : import NumeClasa
Metoda main() trebuie să accepte argumente din linia de comandă, sub forma şirului de caractere
args[ ] şi nu returneaza nici o valoare (tipul void). Metoda este aceeaşi pentru toate instanţele
clasei, fapt specificat prin cuvântul cheie static, şi poate fi invocată de orice altă clasa, fiind
declarată public. Funcţia main() ia parametri din tabloul de obiecte String trecute în linia de
comandă.
Apelând aplicaţia
Java ClasaIn master 9 9.5
Constatăm că tabloul are 3 elemente ("master","9", "9.5") iar dimensiunea acestuia este
dată de variabila [Link]
[Link] ("Test de programare Java"); echivalent cu printf din C şi cont din C++ apelând
tipărirea la consolă. Termenul de aplicaţie stand alone este greşit utilizat pentru că aplicaţia însuşi
necesită interpreterul Java pentru a o utiliza deci nu este de sine stătătoare.
Exemplu:
java Clasa
După scrierea unui program, se impune utilizarea unui compilator Java (javac) pentru a traduce
programul sursa într-un cod binar portabil. Acestă preia programul sursă Java scris în format
Unicode şi identifică elementele lexicale ale limbajului (tokens). Aceste elemente lexicale pot fi
identificatori, cuvinte cheie, literali, operatori şi separatori. In programul sursă Java, elementele
lexicale trebuie să fie separate între ele cu ajutorul următorilor separatori lexicali: spatiu (blanc),
sfârşit de linie (Enter), sau comentariu. Compilatorul traduce programul sursa Java într-un cod
binar, independent de calculator, neglijând separatorii lexicali.[java_1]
[Link]
7
Comentariile sunt secvenţe de caractere care nu afectează semantica programelor, ele având rolul
de a explica secvenţe de instrucţiuni din programul sursă. In limbajul Java există trei stiluri de
comentarii:
• Stilul /* … */, utilizat iniţial în limbajul C standard, a fost preluat apoi in C++, iar acum este
disponibil în Java şi se foloseste în cazul comentariilor pe mai multe linii.
• Stilul // … a fost adaugat în limbajul C++ pentru a uşura scrierea comentariilor într-o linie,
acest tip de comentariu fiind disponibil şi în Java.
• Stilul /** … */ este nou adaugat de limbajul Java şi este utilizat pentru întocmirea automată a
documentaţiei pentru programele Java. Acesta se poate plasa numai în faţa declaraţiilor, textul
comentariului fiind copiat automat în documentaţia aplicaţiei de către generatorul automat al
documentatiei (javadoc).
Declararea unui pachet se face prin inserarea la începutul fişierului a unei declaraţii de forma:
package nume_pachet, unde numele pachetelor sunt identificatori Java. Grupurile de instrucţiuni
package leagă clasele şi interfeţele pentru a evita conflictele şi pentru o mai bună organizare.
Spre exemplu definim clasa ecran utilizată atât de appletul aplic1 cât şi de aplic2. Acestea
se disting prin pachetul unde sunt plasate astfel:
aplic1_pack.ecran
aplic2_pack.ecran
unde aplic1_pack şi aplic2_pack sunt directoare din CLASSPATH.
Exemplul sugerează faptul că fiecare clasă şi interfaţă are nume unic, clasele şi interfeţele din
aceaşi pachet au nume unic şi pachetele la rândul lor au nume unic. Problema gravă apare când 2
persoane au clase pe acelaşi host, caz în care se recomandă numirea ierarhică a pachetelor.
8
Exemplu:
NumeOrganizaţ[Link]
Numele pachetelor este separat cu punct în componente, nefiind limitat numărul componentelor
dintr-un pachet. Fiecare componentă reprezintă un element din structura ierarhică, mapat direct pe
structura de directoare a sistemului unde se află memorat pachetul.
Instrucţiunea package este prima linie din unitatea de compilare, toate clasele şi interfeţele din
unitate fiind legate de acest pachet. O unitate de compilare poate avea mai multe clase şi interfeţe
membre, dar numai o instrucţiune package. Fiecare clasă aparţine unui pachet iar dacă o unitate
de compilare nu are instrucţiunea package este plasată în pachetul implicit (fără nume). Pentru
aplicaţii simple nu este recomandată dar dacă apar aplicaţii complexe cu multiple clase şi interfeţe
este de recomandat organizarea acestora într-un pachet, conform figurii 1.1.
1 FIRMA
2 FURNIZOR CLIEN
Considerăm pachetele Furnizori şi Clienţi (nivel 2) care corespund celor 2 subdirectoare create ca
făcând parte din directorul FIRMA (nivel 1), sub CLASSPATH. Fiecare din cele 2 subdirectoare
vor conţine unităţile de compilare (nivel 3) proprii.
Astfel includem:
package [Link];
package [Link];
9
Instrucţiunea import permite claselor utilizarea numelor abreviate pentru referirea claselor şi
interfeţelor declarate în exteriorul acestei unităţi de compilare, ceea ce conduce la un cod uşor de
citit. In schimb aceasta nu permite alte avantaje decât convenţia sintactică utilă pentru
programatori. Import se poate utiliza o singură dată într-un pachet cu nume complet de calificare
astfel:
import [Link];
şi odată plasată se poate referi clasa importată simplu: Applet fără calificare completă
[Link].
Fiecare pachet sau program java importă automat toate clasele şi interfeţele exenţiale din java şi
nu este necesar importul explicit de interfeţe ca [Link], [Link],
[Link], [Link],etc. Instrucţiunile package şi import nu generează cod ci au un
rol bine definit în programarea OO.
10
Relaţia 1-1 între clasele public şi numele fişierului sursă permite compilartorului căuarea,
verificarea şi recompilarea fişierului sursă ce este memorat, cu menţiunea că numele clasei şi
fişirului sunt case-sensitive.
In mediul Java există mai multe pachete care conţin biblioteci de clase, unele având caracter
general, altele fiind orientate spre diferite tipuri de aplicaţii. Acestea conţin metode care se pot
folosi în programe dar pentru a putea folosi anumite clase dintr-o bibliotecă, trebuie să importăm
clasele respective sau întreaga biblioteca. Singura bibliotecă prezentă tot timpul este biblioteca de
baza a limbajului Java numită [Link].[Laur-98]
Bibliotecile de clase se împart în două categorii: cele destinate a fi folosite în programe care, după
ce sunt compilate, urmează să fie executate cu ajutorul interpretorului Java. In a doua categorie
sunt incluse applet-uri, adică subclase ale clasei Applet din pachetul [Link]. Aceste clase
sunt folosite în programe care urmează să fie executate de către browser pentru conţinut dinamic
(executabil) Java.
Mediul Java oferă pachete cu biblioteci de clase în care se gasesc metode pentru functiile de baza
ale modulelor sistemului. Compilatorul Java creaza o structură de directoare sub formă de arbore,
pentru fiecare nume de pachet fiind creat un director. In denumirea clasei se gaseste operatorul
punct (.) pentru a lega directorul java de subdirectorul care conţine o biblioteca de clasa. Pentru a
se referi aceste biblioteci sau anumite clase din biblioteci este necesară folosirea aceluiaşi operator
astfel:
[Link]
unde biblioteca poate fi ună din clasele lang, io, util, applet, awt sau net, iar clasa este clasa din
biblioteca respectivă.[Proda-97]
Java Runntime Environment (JRE) conţine maşina virtuală Java, clasele de bază şi alte fişiere
necesare rulării, Java 2 SDE (Software Development Kit) incluzând pe lângă JRE compilatorul
javac, debugger-ul şi alte instrumente de dezvoltare. O trecere în revistă a bibilotecilor existente în
limbajul Java:
[Link] – aici se pot gasi clase în care sunt implementate funcţiile de bază din
mediul Java şi acest pachet va fi încărcat automat, odată cu compilatorul, fără a fi
necesară o declaraţie explicită de import. Această bibliotecă conţine clase pentru
extensia tipurilor elementare de date, pentru prelucrarea sirurilor de caractere, pentru
funcţii matematice, pentru interactiuni de baza cu sistemul, pentru fire de executie,
clase abstracte şi pentru biblioteci.
[Link] se utilizează pentru verificarea entităţilor Java, a claselor şi
obiectelor, foarte utilă în realizarea unor aplicaţii dinamice şi flexibile.
[Link] – cu rol de implementare a applet-urilor, care sunt destinate a fi
executate de un browser pentru conţinut executabil Java. Pentru a crea un applet
executabil într-o pagină Web sau rulat cu appletviewer, se poate extinde această clasa
cu metode de includere a efectelor sonore, legături cu alte pagini Web, pentru definirea
unor formate.
[Link] (Abstract Window Toolkit) – în această biblioteca se afla clasele de bază
care oferă instrumente pentru crearea elementelor de interfaţă grafica. Prin includerea
acestor elemente de interfaţă grafica, appletul va deveni o altă intefată grafica. Clasele
11
din acest pachet includ [Link], [Link], [Link]
[Link], [Link], [Link] metode pentru crearea de ferestre,
meniuri, butoane, comutatoare, liste, bare de defilare verticale şi orizontale, operarea cu
fonturi, imagini 2D şi 3D, [Link] ce permite definirea de clase şî metode de
intrare.
[Link] – conţine clase de bază pentru implementarea operaţiilor de intrare-ieşire în
mediul Java. Se pot efectua citiri de la dispozitivul de intrare, scrieri la unitatea
standard de ieşsire, citiri de pe disc sau din retea. Pentru efectuarea acestor operatii este
necesară folosirea metodelor gată pregatite pentru diferite structuri de informaţii:
fişiere, zone tampon (buffere), filtre, pipes.
[Link] – este destinată funcţii speciale în mediul Java, ca suport pentru lucrul cu
date calendaristice, operaţii cu stive, operaţii cu tabele sau operaţii cu vectori. Dacă
appleturile folosesc algoritmi de compresie/ decompresie au la dispoziţie [Link]
şi [Link]
[Link] – cuprinde clase de baza pentru crearea de interfeţe pentru protocoale de
reţea (telnet, ftp, nttp, WWW) şi legături de tip socket.
[Link] se foloseşte pentru diverse funcţii matematice standard implementate.
[Link] este destinată creării de componente reutilizabile, denumite beans-uri.
[Link], [Link], [Link], [Link] asigură accesul la
obiectele distribuite şi facilitează acces la metode ale acestora. Pachetele sunt destizate
dezvoltării aplicaţiilor distribuite folosind Remote Method Invocation (RMI).
[Link], [Link], [Link] asigură mecanismele de
securitate a softului în care sunt incluse.
[Link] facilitează maparea API OMG CORBA în limbajul Java,
incluzând clasa ORB pe care programatorul o poate utiliza ca şi un Object Request
Broker.
[Link], [Link], [Link],
[Link], [Link] permit dezvoltarea metodelor de intrare care
pot fi utilizate cu orice JRE.
Pentru a folosi clasele din bibliotecile de mai sus este posibil importul pachetului în întregime,
folosind declaraţia de import corespunzătoare.
Exemple:
import [Link].*;
import [Link].*;
Dacă se doreşte includerea selectivă a unor clase, pentru a reduce dimensiunile programului binar,
se precizează în declaraţiile respective.
Exemple:
import [Link];
import [Link];
Prezentăm câteva detalii ale clasei applet, destinată a fi utilizată în realizarea unei pagini HTML,
care pune accentul mai ales pe o interfaţă grafică atractivă şi interactivitate mare.
In proiectarea de applet-uri trebuie urmărit scopul aplicaţiei respective şi modul în care acesta
poate fi atins de potenţialii utilizatori pentru că un applet Java este mai mult decât un cod care să
realizeze operaţii elementare de calcul şi afişare - un mod de realizare a interfeţei cu utilizatorii.
12
Biblioteca de clase applet conţine peste 40 de clase şi interfeţe pentru dezvoltarea de programe de
tip applet iar functia de baza a acestora este de a realiza, prin intermediul metodelor obţinute, un
control asupră applet-urilor din mediu.
Clase cum sunt Basicstyle, Document ajută in controlul vizualizarii documentelor HTML şi a
oricarui applet la care se face referire din aceste documente. Clasa applet este superclasa pentru
toate applet-urile nou create şi pot fi vizualizate de browser iar un applet creat moşteneste toate
metodele clasei applet, care constau nu numai din clasa applet şi din metodele superclaselor
acestei clase, care fac parte din awt (nu din clasa applet).[Naugh-96]
Setul de caractere Unicode, care se foloseşte acum în locul setului de caractere standard ASCII
permite reprezentarea caracterelor pe 16 biti, în timp ce setul de caractere ASCII foloseşte numai
8 biti. Cele doua subseturi de caractere sunt compatibile, vechiul standard ASCII fiind un subset al
setului Unicode. Această necesitate de extindere a setului de caractere - determinată de nevoia de
a reprezenta mai mult de 256 de caractere - a apărut din dorinţa de a reprezenta literele ce există în
diferite alfabete de pe glob.
Cuvintele cheie, sau cuvintele rezervate, sunt identificatori utilizati în limbajul Java într-un mod
bine precizat prin gramatica limbajului, fiind interzisăa utilizarea lor în alte scopuri. Un
identificator este o secventă de litere, cifre şi alte caractere în format Unicode, primul caracter
fiind obligatoriu o literă, un caracter underscore (_) sau simbolul dolar ($). Aceştia trebuie să fie
diferiţi de cuvintele cheie şi se utilizează pentru a desemnă variabile, clase şi metode.
Literalii se folosesc pentru a desemna valori constante în cadrul unui program Java şi au la baza
doua categorii de date: numere şi caractere. Literalii numerici se împart în două subcategorii:
întregi ( cu format: zecimal, hexazecimal, octal) şi flotanţi (numere cu parte fracţionară). Un
caracter literal se referă la o singură valoare din setul de caractere Unicode, în timp ce un şir de
caractere se referă la o succesiune de unul să mai multe caractere. Pe lângă aceştia mai există
caracterul boolean, literal considerat numeric pentru compatibilitate cu limbajele C şi C++, iar
valorile de adevar true şi false în C şi C++, sunt reprezentate prin valorile intregi 1 şi 0.
Constantele literale pot fi exemplificate astfel:
Intregi
5 întreg
5l (intreg scurt)
5L(întreg cu tip lung)
O5 întreg octal
OxaBa (hexazecimal case-sensitive)
Double şi Float
4.5, 6.7d, 7.8D - constante duble
3.4E8 - constante duble cu exponent
6.7f sau 6.7F - tip float
Booleene: true, false
Constante caracter (Escape)
\ continuare în linia următoare
\n linie nouă
\t tab orizontal
13
\r carriage return
\f form feed
\\ backslash
\' apostrof simplu
\" apostrof dublu
\ddd formă octal
\xdd formă hexa
\uddd caracter unicode
"exemplu" sir de caractere
14
Tipulile întregi sunt tip de dată şi pot fi caracterizate: byte ( 8 biţi), short (16 biţi), int (32 biţi) şi
long (64 biţi) dar spre deosebire de clasă nu există un comportament asociat tipului întreg.
Clasa Integer din [Link] are declaraţia:
class IntegerClass // conţine variabile intregi
//si set de metode de activare
int MAX_VALUE;
int MIN_VALUE;
public static String toString(int i) //metoda
{…}
}
Spre deosebire de C sau C++ unde dimensiunea diferitelor tipuri de primitive este dependentă de
calculator la Java tipurile de primitive au dimensiune fixă, indiferent de hard-ul unde rulează
maşina virtuală Java.
Tipurile întregi sunt cu semn, fiecare variabilă declarată întreg putând lua valori +/- iar tipul
determină nivelul valorii şi proprietăţile aritmetice ale variabilei ce-l deţine. Dacă o valoare
depăşeşte dimensiunea de reprezentare se trunchiază automat la modulo rang.
Exemplu:
Dacă byte b=-129; => b=-129-(-256)=127
Dacă byte b=128; => b=-128-256=128
Tipul Floating-Point (IEEE 754) permite reprezenarea float (32 biţi) şi double (64 biţi) implicit
fiind double. Pentru testarea depăşirii superioare sau inferioare se utilizează variabila NaN (not a
number).
Tipul caracter este definit conform reprezentării Unicode la 16 biţi/caracter (spre deosebire de C
unde se reprezintă la 8 biţi/caracter) iar la iniţializare se foloseşte apostof simplu.
Exemplu:
char a, b='parola', c='\n';
Tipul boolean are două valori (true sau false) iar maşina virtuală Java îl gestionează în mod
propriu, manipulând biţi individuali ai caracterelor întregi, astfel încât se pot declara mai multe
variabile boolean, fiecare solicitând un bit. In Java valorile booleene nu sunt numere şi nu pot fi
convertite sau operate ca întregi.
Tablourile sunt liste de elemente separate prin virgulă, crete cu operatorul new.
Exemple:
int col[ ]= new int [3];
int [ ]col= new int [15];
int col[ ]; // echivalent cu int [ ] col
…
col = new int[3]; //alocarea dinamică a memoriei
Variabila col are lungime 3 (întreagă) indexată [0-2] şi poate beneficia de alocare
dinamică ceea ce permite programatorului să rezerve spaţiu optim pentru memoria alocată.
Exemple:
int n=2;
double d=5.5;
double Dtablou1[ ]=new float[n+1] //corect
double Dtablou2[ ]=new float[d] //eronat
15
double Dtablou3[ ]=new float[int(d+2)] //corect
//iniţializarea elementelor
Dtablou[0]=0.1;
Dtablou[1]=0.12;
Dtablou[2]=-0.13;
//tablouri multidimensionale
int mat1[ ] [ ] = new int [2] [3];
//sau
int [ ] [ ]mat1 = new int [3] [5];
La tablourile multidimensionale precizarea ultimei dimensiuni este opţională:
int [ ] [ ]mat1 = new int [3] [ ];
Este necesară însă definirea celei de a n-a dimensiuni prealabil utilizării ei:
Exemplu:
for (i=1, i<3, i++) {
mat1[I]=new int [5];
}
Alocarea memoriei pentru tablouri se face tot cu operatorul new, cu excepţia iniţializării în
timpul declarării:
char litere[ ]={'a','j', 'p','l','m','n'};//tablou de 6 elemente
Operatorul new este utilizat pentru memorarea oricărui tip compus (tablou, obiecte din
clasă, interfeţe) iar alocarea explicită pentru tipurile de bază nu este necesară.
Exemplu:
char a; // nu trebuie new
char char Tab1[ ] = new char[3];
In timpul compilării se crează clasa tablou are marchează clasa compilată şi este un obiect
ce nu trebuie subclasat explicit (figura 1.2).[Hoff_96]
Obiect
Array
Este deja cunoscut faptul că în C pointerul este adresa unei variabile, orice porţiune de memorie
fiind accesibilă prin pointeri. Pointerul aritmetic oferă unul din cele mai puternice concepte C
oferind posibilitatea calculelor (+,-,/,*) şi putând fi utilizat la accesarea memoriei. In Java s-a
elinminat accest concept recunoscută fiind periculozitatea utilizării eronate a pointerilor aritmetici
şi s-a introdus handler (manipulator).[Chan_95] Un handler Java este asociat cu un obiect şi nu cu
o adresă.
16
Exemple:
int col [ ];//handler null
Instrucţiunea precedentă alocă memorie pentru cei 4 manipulatori (mat1[0], mat1[1], mat1[2],
mat1[3]) şi fiecare punct la null. Alocarea dinamică pentru tabloul actual se realizează cu secvenţa:
for (i=1, i<3, i++){
mat1[I]=new int [3];
}
matricea mat1 este:
0 1 2...
3
int int
int int int int int int
int
int int int
2
1.4.3. Operatori
Operatorii sunt folosiţi pentru a realiza anumite operaţii elementare între obiecte, fiecare operator
joacă şi rolul de separator între două elemente lexicale şi au prorpietăţi similare cu cei din C:
precedenţa (ordinea în care sunt interpretaţi) şi asociativitatea (direcţia de evaluare). [Laur-98]
17
Operatori Precedenţa Asociativitatea
< Mai mic
> Mai mare
<= Mai mic sau egal
>= Mai mare sau egal
== Test de egalite
!= Test not equal
& Si binar
^ XOR binar
| OR binar
&& And
|| OR
?! Operator ternar condiţional Dreapta la stânga
=,+,=,- Atribuiri
=,*=,/+,
%=,&=,^=,|
=,<<=,>>=
a operand b Echivalent cu a=a operand b
a+=b echivalent cu a=a+b
Dacă rezultatul calculelor este de tip întreg şi operandul este long se realizează conversia la tipul
long, înrest rezultatul este int.
Exemplu:
class Test1{
public static void main(String args[ ]) {
short i=10, j=11,k;
int m;
k=i+j; //eroare, trebuie forţată explicitarea
k=(short) (i+j); // k=21
m=i+j; // m=21
}
}
Exemplu:
class Test2 {
public static void main(String args[ ]) {
Integer i= new Integer(0);
int overflowN=i.MAX_VALUE+1;
//valoarea maximă posibilă
[Link] ("valoarea minimă posibilă=" +i.MIN_VALUE);
[Link] ("valoarea care depăşeşte="+overflowN);
18
if(i. MIN_VALUE=overflowN)
[Link] ("truncherea");
}
}
Rezultatul programului:
valoarea minimă posibilă=-2147483648
valoarea care depăşeşte=-2147483649
truncherea
Operatorii acceptaţi pentru tipuri întregi sunt =,-,*,/,%,++,-- şi op=
Operatorii ~,<<,>>,>>>,&,^,| iau operanzi de tip întreg şi întorc valori întregi iar operatorii
<,>,<=,>= iau operanzi de tip întreg şi întorc valori booleene. Pentru tipurile de virgulă flotantă
sunt acceptaţi operatorii de tip întreg mai puţin cei la nivel de bit. Definiţia modulo este diferită de
cea dată pentru întregi. Dacă x şi y sunt double sau float:
x%= [Link](x/y)*y
Dacă numărul are parte fracţionară 5 este convertit la întregul superior.
[Link](7.0/2.0)= [Link](3.5)=4
Spre deosebire de tipul întreg la cele float depăşirea superioară generează Inf(infinit) şi cea
inferioară generează 0 iar rezultatul împărţirii cu o generează Inf.
Exemple:
double depsup=1.0/0.0 // overflow
double depinf=27/0.0 // underflow
Operatorii relaţionali se utilizează cu precauţii în comparaţii pentru că dacă a<b este fals, nu
implică a>=b sau a!=b nu înseamnă a>b || a<b
NaN este un număr fără semnificaţie, fără semn şi nu poate fi comparat nici măcar cu el însuşi,
pentru că rezultă din calcule.
Exemplu:
double a=0.0/0.0;
if ([Link](a))
[Link] ("a este NaN");
else
[Link] ("a nu este NaN");
double b=a;
if ([Link](b))
[Link] ("b este NaN");
else
[Link] ("b nu este NaN");
if (a==b)
[Link] ("a==b");
else
[Link] ("a!=b");
Rezultatul obţinut:
a este NaN
a!=b
19
Operatorii de tip boolean sunt relaţionali sau logici şi folosesc şi produc valori booleene.
Exemplu:
return((mask>0)?true:false;
echivalent cu:
if (mask>0)
return true;
else
return false;
Transformarea subclaselor şi superclaselor este permisă dar deşi o instanţă poate fi transformată în
superclasă, transformarea unei subclase generează erori de execuţie. Interpreterul Java verifică
dacă subclasa este extensie a unei superclase transformate şi dacă un obiect nu este instanţă de
subclasă (sau una din subclase) se rulează rutina Class CastException. Expresiile sunt combinaţii
de variabile, literali şi operatori ce determină un rezultat. Atribuirea este procesul de memorare a
valorii iar variabila căreia I se atribuie se numeşte variabila stângă. Separatorii Java din expresii
sunt ( ), { }, [ ] ;,. Ordinea de evaluare este dată de dictată de precedenţele operatorilor şi de
separatorii incluşi.
20
1.5. Instrucţiuni de control al fluxului de execuţie
1.5.1 Instrucţiunea label
label:
Instrucţiunea label serveşte la etchetarea blocului în care se află. Ea nu modifică fluxul de
prelucrare ci serveşte ca marker pentru eventuale salturi în secvenţe normale. Java procedează la
scurtcircuitarea evaluărilor astfel încât pentru un operator de tip && la prima evaluare de expresie
falsă renunţă la evaluarea expresiei rămase. Pentru o mai bună optimizare, dacă în compilare se
identifică valoarea falsă întotdeauna, la o evaluare de expresie dintr-un if, nu se generează cod
pentru ramura true.
1.5.2. Instrucţiunea IF
if <expl1> {
Instrucţiuni1 ;
[else } if <expl2> {
instrucţiuni2;
}else {
instrucţiuni3 ;]
}
switch (expr) {
case const1: instrucţiuni1;
break;
case const2: instrucţiuni2;
break;
…
default: instrucţiuniN;
}
Instrucţiunea switch este în realitate echivalentul unui if imbricat, unde:
expr - este o expresie tip caracter, byte, short sau int;
const1, const2, constN - valori constante ce sunt asociate execuţiei grupurilor
de instructiuni;
instrucţiuni1, instrucţiuni2, … - grupuri de instrucţiuni care se execută
condiţionate de const1, const2, constN;
default -- grup de instrucţiuni (instrucţiuniN) care se execută dacă nici una din
condiţiile de const1, const2, constN nu este îndeplinită.
Exemplu:
import [Link].*;
21
class UnDictionar {
public static void main (String args [ ] ){
char alege;
[Link] ("Selectati una din lectiile de instruire:");
[Link] ("AWT");
[Link] ("API");
[Link] ("Corba");
…
[Link]();
try {
switch (alege=(char)[Link]();
{
case "W": [Link] ("am selectat AWT");
break;
case "P": [Link] ("am selectat API");
break;
case "C": [Link] ("am selectat Corba");
…
default: [Link] ("Selectie eronata");
}
catch(IOException e)
{ [Link] ([Link]());
}
}
}
Instrucţiunea while permite execuţia grupului de instrucţiuni până când expresia logică
expl evaluată este adevărată.
Exemplu:
int i;
boolean test=false;
while (test == false){
i=(int)([Link]()/500);
}
if (i%2==0)
test=true;
}
1.3.5. Instrucţiunea do
do {
instrucţiuni;
}
while (exprl) ;
22
Spre deosebire de instrucţiunea while, instrucţiunea do permite execuţia grupului de
instrucţiuni cel puţin odată, prealabil evaluării expresiei logice expl .
Exemplu:
int i;
boolean test=false;
do {
i=(int)([Link]()/500);
}
if (i%2==0)
test=true;
}
while (test == false)
Instrucţiuea for (de ciclare) execută grupul de instrucţiuni, pornind de la expresia1, până
când este îndeplinită condiţiă dată de expresia booleană, cu pasul (incrementul) dat de
expresie2.
Exemplu:
int k=7;
int []vo= new int[k];// vector
for (int i=0, i<k, i++) {
vo[i]=(int)([Link]()/100);
}
Exemplu:
public int cautMatrice (int [ ] [ ] matrice, int [ ] tinta){
int sumaMatr=0;
for (int nTinta=1, nTinta<[Link], nTintai++) {
nouaTinta:
for (int i=o, i<[Link],i++) {
for (int j=0, i<matrice[0].length, j++) {
sumaMatr++;
break nouaTinta;
}
}
}
23
return sumaMatr;
}
24
1.5.9. Instrucţiunea return
return [valoare intoarsă];
Instrucţiunea return este utilizată de o metodă sau constructor pentru a întoarce controlul la
apelant şi apare în mod uzual la finalul metodei sau constructorului. Dacă metoda întoarce
tip void sau constructorul nu are tip întors, return este opţional. Se poate folosi şi pentrua
forţa întoarcerea, ca mod de prevenire a execuţiei restului metodei, ceea ce salvează nivelul
indentărilor, permiţând un cod uşor de citit (în aceste cazuri este inclusă în if).
Exemplu:
void Lot (int x) {
if (x<=20) {
return;
} else return;
void altLot (int x){
if (x>20) {
return;
}
}
In cazul în care metoda sau constructorul este declarat cu tip de valoare întoarsă, instrucţiunea
return trebuie să întoarcă tipul corespunzător declaraţiei. Dacă return este inclus într-un bloc try,
urmat de finally, instrucţiunile finally din bloc sunt executate înainte de a reda controlul
apelantului.
Crearea şirurilor în Java se realizează cu operatorul new iar concatenarea lor cu append
Exemplu:
String d = new StringBuffer ("Am obtinut");
.append (calif)
.append ("la testul de baza")
.toString();
25
obiectului respectiv. Fiecare clasă implementează toString în virtutea implementării moştenite din
clasa Object.
Exemplu:
class Point {
int x,y;
Point (int x, int y);
this.x=x;
this.y=y;
}
public String toString() {
return "punctul ("+x+","+y+")";
}
}
class DemoSir() {
public static void main ( String args [ ] ) {
Point p = new Point (20,30);
[Link]("Obtinem"+p);
}
}
Versiunea clasei Point include suprascrierea metodei toString din object, formată dintr-un şir
conţinând valorile curente (x,y) ale instanţei Point. Ieşirea este dată de:
Obtinem punctul (20,30).
Metoda getChars nu include char la sfârşitul indexului şi este foarte utilă în special la exportul
String într-un mediu ce nu suportă 16-biţi Unicode. Protocoalele Internet folosesc 8-biţi ASCII
pentru text. Faţă de această metodă, apar particularităţi de xtragere a caracterelor la metodele:
toCharArray, care întoarce un tablou de caractere pentru întregul şir;
26
getBytes care ia caractere dintr-un tablou de biţi, în ordinea apariţiei acestora şi este
similară cu getChars cu deosebirea că al treilea parametru este tablou de byte.
Cele două şiruri sunt comparate pe dimensiunea len caractere, începând de la cele două offset-uri
specificate. Pentru verificări speciale impuse şirurilor se folosesc două metode
pereche:startsWith, care verifică dacă şirul începe cu parametrul transmis şi endWith, care
verifică dacă şirul se termină cu parametrul transmis şi sunt deosebit de utile în programarea
appleturilor.[Chan_95]
Exemple:
"[Link]("ie") returnează true
"[Link]("Cat") returnează true
"[Link]("eg",3) returnează true
Egalitatea dintre şiruri poate fi testată fie cu metoda equal, fie cu operatorul ==, deosebirea fiind
fundamentală deoarece metoda equal compară caracterele din interiorul tipului String pe când
operatorul == compară două referinţe obiect.
Exemplu:
class DemoEgalSir() {
public static void main ( String args [ ] ) {
String s1= "Exemplu de utilizare a metodei equal");
String s2= new String(s1);
[Link](s1+"egal cu sirul s2"+s2+'->"+ [Link](s2));
[Link](s1+"==cu sirul s2"+s2+'->"+ (s1==s2));
}
}
In exemplul de mai sus, s1 este creat ca instanţă de şir iar s2 este creată prin construtor String care
ia intrarea şi o întoarce caracter. Fiind obiecte distincte ele nu sunt == dar sunt equal. Ordinea într-
un şir este determinată cu metoda compareTo.
Exemplu:
class DemoBubbleSortlSir() {
static String arr[ ] = {"acum", "facem","ordonare", "prin", "comparatie", "de",..}
public static void main ( String args [ ] ) {
for (int j=0, j<[Link], j++) {
27
for (int i=0, i<[Link], i++) {
if arr[i].compareTo(arr[j])<0) {
String t= arr[j];
arr[j] = arr[i];
arr[i]=t;
}
[Link](arr[j]);
}
}
}
Căutarea în şir se poate face cu indexOf sau lastIndexOf care sunt supraîncărcate în orice mediu,
pentru a căuta caractere sau subşiruri, începând de la offset până la sfârşitul sursei String.
Exemple de utilizare:
int indexOf ( int ch);
int lastIndexOf ( int ch);
int indexOf ( String str);
int lastIndexOf ( String str);
int indexOf ( int ch, int index); - cautare de la indexul precizat
int lastIndexOf ( int ch, int index);
int indexOf ( String str, int index );
int lastIndexOf ( String str, int index);
Această clasă oferă o gamă diversificată de metode necesare efectuării operaţiilor de bază la
nivelul tipurilor int, double, float, etc.Fără a intra în detalii de funcţionare, cunoscute de altfel la
limbajele de generaţia a treia şi a patra, prezentăm câteva funcţii utile:[Naugh_96]
28
asin/acos/atan (double a) - arcsinus, arccosinus, arctangentă;
atan2 (double a, double b) - arctangentă(a/b);
Random este clasa ce generează 5 tipuri de numere aleatoare care pot fi extrase din obiectul
Random:[java_1]
int, uniform distribui în rang int, extras cu metoda nextInt;
long, uniform distribui în rang long, extras cu metoda nextLong;
float, uniform distribui în rang float, extras cu metoda nextFloat;
double, uniform distribui în rang double, extras cu metoda nextDouble;
nextGaussian, care întoarce distribuţia Gaussiană double, centrată 0.0, cu deviaţie standard
de 1.0 (curba clopot- bell curve);
Clasa Date este utilizată la reprezentarea orei şi/sau timpului şi are câţiva constructori de bază:
Date(year, month, date);
Date(year, month, date, hours, minutes);
Date(year, month, date, hours, minutes, seconds).
29
Reprezentarea long poate fi realizată prin getTime iar comparaţia dintre două obiecte de tip Date
se face cu una din metodele:
Boolean before (Data cand);
Boolean after (Data cand);
Boolean equals (alta Data ).
Obiectele Date pot fi convertite în String prin metoda toString sau toLocalString respectiv
toGMTString. Dacă se doreşte obţinerea unui offset în minute faţă de GMT se foloseşte
getTimezoneOffset.
Runtime este clasă încapsulată în procesul de rulare a interpreterului Java. Practic nu se poate
instanţia Runtime, se pot doar referi obiecte ce rulează prin metoda statică [Link].
Sunt câteva metode de control a stării şi comportamentului maşinii virtuale prin
SecurityException. Metoda exit (int cod) dă o ieşire cu codul erorii întâlnmite la execuţia
programului.[java_8]
Managementul memoriei se face prin GC iar metodele totalMemory() şi freeMemory() din
Runtime dau memoria totală ocupată respectiv memoria liberă.
Metoda exec() permite apelul altor programe cu nume specificat la fel ca şi parametri de intrare.
Problema este că programul se execută independent de sistem. Metoda exec() întoarce obiectul
Process care poate fi utilizat la controlul modului în care programul java interacţionează cu noul
proces executabil.
Exemplu:
class ExeDemo {
public static void main (String args [ ] ) {
Runtime s = [Link]();
Process p=null;
Sting cmd[ ] = {"notepad", "java/lang/[Link]"};
try {
p=[Link](cmd);
} catch (Exception e) {
[Link] ("eroare la execuţie"+cmd[0]);
}
}}
Procesul returnat de exec poate fi manipulat după ce noul program a început rularea şi se poate
distruge procesul cu metoda destroy().
Metoda waitfor() determină aşteptarea programului până când a terminat subprocesul iar metoda
exitValue() întoarce valoarea de ieşire din subproces ( număr natura sau 0 dacă ieşirea a avut loc
fără probleme).
[Link] Java
2.1.1. Caracteristicile claselor în Java
30
Arhitectura limbajului Java este bazată pe metodologia orientată spre obiecte. Inafară de tipurile
fundamentale (int, float, char, boolean), în Java totul se reprezintă prin obiecte denumite clase.
Prin încapsularea caracteristicilor limbajului în clase, Java devine un mediu extensibil în care
programatorii pot folosi rutinele din alte programe sau aplicaţii. Limbajul Java evalueaza structura
claselor în mod dinamic în momentul executiei şi datorită dinamicii, bibliotecile de clase pot fi
reutilizate cu uşurinţă.
Clasa Object
Clasa 1 Clasa n
Limbajul Java pune la dispozitie metode şi operatori pentru crearea variabilelor de clasă, dar este
necesară definirea unei metode de creare a clasei şi ulterior se poate crea o altă clasa că şi copie a
obiectului (adică a definiţiei de clasă) utilizând operatorul new. [Lema_98]
Metoda de creare are acelaşi nume cu numele clasei şi nu returnează nici o valoare dar prelabil
apelului metodei de creare trebuie alocată memoria necesară instanţierii şi initializată cu valorile
specificate sau implicite. Pentru a crea o clasă care foloseşte o altă clasă (initial construită),
este necesară o instanţiere a clasei cu operatorul new.
Exemplu:
clasa varClasa= new clasa()
unde clasa este numele clasei, varClasa este numele variabilei care se declară, iar clasa este
constructorul variabilei respective. In continuare, variabila varClasa va putea conţine o referintă la
un obiect de clasa clasa sau la un obiect derivat din clasa creată.[Lema-96]
La executia unui applet sau o aplicaţie de sine stătătoare într-un browser, în mediul Java se
creeaza o instanţiere (adica o variabilă) a clasei încărcate. Toate clasele in limbajul Java sunt
descendente dintr-o clasa superioară numită Object, clasele proprii putând fi create prin derivare
31
sau moştenire din Object sau din orice altă clasa, care la rândul ei moşteneste direct sau indirect
clasa Object. In figura de mai jos se prezintă structură ierarhică a claselor din mediul Java.
Pe fiecare ramură din ierahia de mai sus, subclasa moşteneşte proprietăţile superclasei şi astfel,
chiar dacă o clasă nu succede direct din clasa Object, ci în urma unei şir de succesiuni, această
clasă este totusi o subclasă a lui Object. Clasa Object este singură clasa care nu are o superclasa şi
poate fi considerată ca un tip fundamental dar dacă pentru clasă nu se declară explicit ascendentul,
în mod implicit acea clasă este o succesoare directă a clasei Object.[Naugh-96]
}
Dacă se declară o clasa cu public class NumeClasa, această clasă nou creată va fi o subclasă a
clasei obiect, deoarece nu este specificată în declaraţie clasa din care este derivata. Clasa se
declară public pentru ca apoi să fie plasată intr-un pachet şi exportata. In cazul in care clasa este
declaraţă in acelasi fişier in care este şi utilizata, declaraţia public nu este necesară.
După crearea unei clase este necesară definirea variabilelor clasei. Pentru fiecare variabila din
interiorul unei clase, se va specifica tipul precum şi identificatorul variabilei după modelul: tip
nume. In clase se includ şi metode, pentru a realiza anumite calcule, iar rezultatul să poată fi
returnat sub forma unei valori de tipul tipReturnat, conform declaraţiei de metodă:
TipReturnat nume(parametru1, parametru2,…) {
// corpul funcţiei
}
In alte cazuri o metoda indică faptul ca s-au incheiat cu succes anumite operaţii, nefiind necesară
returnarea unui rezultat iar o astfel de metodă (care nu returnează o valoare în urma execuţiei), are
în definiţie cuvântul void.
Alături de metoda de creare există şi o metoda de finalizare care are rol de a închide fişierele care
au fost deschise şi de curăţare a obiectului pentru care este finalizator, pentru ca ulterior
colectorul de reziduri să elimine obiectul din memorie. Nu există nici o garanţie că limbajul Java
va invoca metoda de finalizare definită, considerand metoda ca şi o optimizare a codului, motiv
pentru care este indicat ca aplicaţia să nu depinda prea mult de această metodă pentru a evita
anomalii în execuţie.
Pentru a se şterge un obiect, trebuie apelată metoda de finalizare care distruge variabila
respectivă, şi ulterior se apeleaza colectorul de reziduri. In limbajul Java nu este necesară apelarea
în mod implicit a distrugerii unei variabile de clasă, deoarece sistemul are un mecanism de
colectare a rezidurilor care descoperă situaţiile în care o variabilă de clasa ( sau un obiect) nu mai
este referită şi o distruge automat. Se recomandă însă ca metoda de finalizare să fie apelată
explicit pentru a nu apărea manifestări accidentale în execuţie.
Aceesibilitatea clasei şi informaţiile despre variabilele şi metodele definite în clasă sunt date prin
modificatorii clasei. Dacă aceştia sunt omişi în întregime, obiectele din clasă sunt definite şi
accesate de alte clase din acelaşi pachet iar această clasă poate avea la rândul ei subclase în acelaşi
pachet. Sunt cunoscuţi trei modificatori de clasă: public, abstract şi final.
32
O clasă declarată public este global accesibilă, ceea ce însemnă că orice clasă definită în acelaşi
pachet poate accesa obiectele din această clasă. Dacă nu este declarată public, accesibilitatea se
limitată la nivelul pachetului sau claselor din care derivă. Dacă o clasă este declarată public, ea
trebuie să fie publică în codul sursă şi mai mult, numele fişierului sursă trebuie să fie acelaşi cu
numele clasei public, cu extensie java.
Exemplu
public class Clasa1 {
Corpul clasei
…}
Observaţie:
In fişierul [Link] există doar o clasă declarată public.
In general se declară o clasă public, atunci când se doreşte a fi global accesibilă, astfel încât orice
applet public permite utilizatorului care navighează în pagină, să îl execute. Suplimenar se pot
declara pachete relative la clase, ce au intenţia de a furniza funcţionalitate generală, adesea pentru
a fi reutilizate în programe diferite. Pentru a face clasele accesibile în exteriorul pachetului, acestea
trebuie declarate public. Totuşi nu toate clasele dintr-un asemenea pachet pot fi utilizate în
exterior; unele sunt destinate doar uzului intern deşi se poate declara o clasă public, care poate fi
invizibilă în exteriorul pachetului.
O clasă abstract este cea care conţine una sau mai multe metode abstract. Uneori se declară o
metodă în clasă fără a preciza detaliile interne ce presupun metode de implementare diferite pentru
fiecare subclasă. Spre exemplu, dacă declarăm clasa [Link], are sens să se definească
metoda de afişare pentru fiecare tip de format al fişierului (JPEG,GIF,BMP, etc.) pentru că este
cunoscut faptul că există în plus informaţii legate de dimensiunea fişierelor, care determină
implementări diferite. Intr-un asemenea caz este necesară structurarea definiţiilor acestei metode
ale subclaselor. Pentru a realiza acest lucru, se lasă definiţia blank şi se declară metoda abstractă.
Dacă o clasă conţine una sau mai multe metode abstract, atunci clasa însuşi se declară abstract,
pentru a evita erori de complilare. Nu trebuie instanţiat direct un obiect din clasa abstract. Pentru
a-l utiliza este necesară crearea unei subclase ce include definiţiile pentru metodele lăsate blank în
clasa abstract, iar această clasă trebuie apoi instanţiată.
Clasele abstract permit implementarea polimorfismului pur, în care aceste clase abstract nu pot fi
ele însele instanţiate ci au rol de a servi ca şi clase de bază pentru un grup de clase aflate în relaţie.
Aceste clase de bază sunt generice astfel încât este greu sau aproape imposibil de definit detaliile
sau comportamentul acestora. Detalliile sunt lăsate subclaselor şi fiecare subclasă implementează
comportamente diferite. De aceea se începe fără implementări finalizând apoi cu implementări
distincte, proprii fiecărei subclase. Clasele abstracte se pot declara public sau fără acces implicit,
caz în care sunt vizibile doar în interiorul pachetului.[Ramb_96]
Clasele final nu pot fi subclase, sunt opuse lui abstract, motiv pentru care nu pot fi simultan final
şi abstract pentru că generează erori de complilare. Există două motive pentru care se folosesc
aceste clase: eficienţa şi posibilitatea de a extinde metodele definite în clasele părinte. De aceea
când o metodă dintr-o clasă este apelată, nu este posibil să se determine la momentul compliării ce
versiune a metodei se execută, deoarece versiunea metodei definită în clasă poate fi extinsă într-o
subclasă, cu acelaşi nume şi tip de parametri. Acest lucru trebuie determinat dinamic, în timpul
33
execuţiei de fiecare dată când se rulează acea secţiune de cod, depinzând de segmentele generate
când obiectul este instanţiat.
De fiecare dată când se fac determinări, se poate solicita încărcarea unei clase ce nu a fost anterior
rezidentă în memorie. Aceste performanţe se asociază cu costul încărcării clasei. Cum o clasă
finală nu are subclase, pentru a garanta faptul că aceste metode nu vor fi estinse, instrucţiunile ce
le compun sunt incluse în codul compilat, eliminând necesitatea de a lua o decizie şi posibilitatea
încărcării unei noi clase, în timp ce programul rulează. Al doilea motiv de declarare a acestor clase
final este dat de securitatea şi claritatea asigurată, deoarece se poate specifica o clasă cu
comportament cert, se poate dori ca nimeni să nu aibă posibilitatea de modificare a
comportamentului unei clase, extinzându-I metodele. Declarând-o final, se previn subclase
asociate, respectând funcţionalitatea şi securitatea ei.[java_8]
Numele clasei este identificator unic în acelaşi pachet. La importul claselor din alte pachete,
numele claselor din pachetul propriu nu trebuie să intre în conflict cu numele celor din pachetele
importate. Prin convenţie, programatorii Java scriu primul caracter din clasă cu majuscule, pentru
a asigura numele clasei şi variabilelor distincte, făcând codul uşor de citit.
Clasa Cont
abstract void tip();
String tip() {/*…*/}
abstract void sold();
extends
Clasa ContSintetic
void tip();
String tip() {/*…*/}
void sold();
extends
Clasa ContAnalitic
void tip();
String tip() {/*…*/}
void sold();
implements abstract void detaliu();
extends extends
extends extends
Clasa
Clienti Clasa
Clasa
Clasa Clasa
Agenti
A
Furnizori ContBancar
34
Clasele extends specifică clasa din care se moştenesc, fiind superclase imediate sau clase părinte.
O subclasă estinde funcţionalitatea clasei părinte, în Java existând doar moşteniri simple (figura
2.2.). Clasele final nu apar în clase extends iar în absenţa clauzei extends, clasa moşteneşte
implicit caracteristicile clasei Object (rădăcina tuturor claselor).
Moştenirea, conceptul central OOP este implementat în Java cu un puternic mecanism de control
ceea ce însemnă că se pot specifica acele caracteristici ale clasei, care vor fi/ nu vor fi vizibile în
subclase şi acele metode care pot/ nu pot fi extinse.
Implicit o clasă moşteneşte toate câmpurile (variabile şi metode), exceptând constructorii, din
superclasă. Inafara constructorilor, variabilele şi metodele declarate private, vor fi invizibile
oricărei clasă ce o moşteneşte.
implements Interfata1, Interfata2,…InterfaţaN
Mecanismul interface oferă unele funcţionalităţi ce permit implementarea moştenirilor multiple,
evitând caracteristici circulare şi alte elemente periculoase ce implică moştenirile multiple.
[An_96] O clasă poate extinde doar o superclasă dar poate implementa oricâte interfeţe (nelimitate
ca număr). Interfeţele se specifică în declaraţia de clasă după cuvântul rezervat implements ca şi
listă separată prin virgulă.Clauza implements este opţională, prezentă doar dacă se implementează
interfeţe (figura 2.2.).
35
int dx=this.x-x;
int dy=this.y-y;
int dz=this.z-z;
return [Link](dx*dx+dy*dy+dz*dz);
}
double distance (Point3D other){
return distance(other.x, other.y, other.z);
}
double distance(int x, int y){
double dx=(this.x/z)-x;
double dy=(this.y/z)-y;
return [Link](dx*dx+dy*dy);
}
}
class Point3Ddist {
public static void main (String args[ ])[
point3D p1= new Point3D(30,40,10);
point3D p2= new Point3D(0,0,0);
Point p= new Point(4,9);
[Link] ("p1 este "+p1.x,p1.y,p1.z);
[Link] ("p2 este "+p2.x,p2.y,p2.z);
[Link] ("p este "+p.x,p.y);
[Link] (" distanta p1-p2"+[Link](p2);
[Link] ("[Link](8,5)"+[Link](8,5));
[Link] ("[Link](p)"+[Link](p));
}
}
Definind punctele p1 şi p2 tridimensionale, am solicitat distanţa între un punct tridimensional şi
unul bidimensional apelând distanţa din 3D cu un obiect de tip Point din 2D şi executând metoda
distance moştenită din Point, deoarece Poit3D nu supraîncarcă distance(Point p) ca metodă în
Point. Apelul distance(int x, int y ) se face din Point3D şi nu din Point (2D) dat fiind faptul că în
Java, metoda este selectată bazându-se pe tipul instanţei la un moment dat şi nu pe clasa în care
metoda curentă este executată.
Când se apelează la o metodă utilizând operatorul punct (.) şi referinţa obiect, declararea tipului
obiectului referit este verificată la compilare, pentru a se asigura că metoda apelată există în
declaraţia de clasă. In rulare, obiectul referinţă poate fi referit ca şi o instanţă a unei sublclase a
tipului de referinţă declarat. In acest caz, Java foloseşte actuala instanţă pentru a decide ce metodă
apelează evenimentul pe care subclasa supraîncarcă metoda ce a fost apelată3. [Hoff_96]
Exemplu:
Presupunem două clase care au o superclasă cu o singură metodă supraîncărcată în clasă.
class A {
void apel(){
3
Dynamic method dispatch
36
[Link].("Metoda de apel a lui A");
}
}
class B extends A {
void apel(){
[Link].("Metoda de apel a lui B");
}
}
class disp () {
public static void main(String args [ ]){
A a = new B();
A apel();
}
}
Această formă de polimorfism dinamic al execuţiei este cel mai puternic mecanism pe care îl oferă
programarea OO atât pentru codul reutilizat cât şi pentru robusteţea programelor.
In clasa disp definim metoda main() în interiorul căreia se declară variabila a de tip A, care
memorează o referinţă la o instanţă din clasa B. In linia următoare apelăm apel() ca metodă a lui a
dar când compilatorul Java verifică dacă a are această metodă rezultatul este corect. In schimb
Java runtime notează că referinţa este de fapt instanţa lui B şi astfel cheamă metoda apel a clesei
B. Vom obţine astfel:
Metoda de apel a lui B
2.1.6. Finalizarea
In timp ce Java runtime este un sistem colector de deşeuri (garbage collector system) nu este
necesar managementul memoriei însă apar unele situaţii de excepţie în care se impune efectuarea
unui cod special atunci când un obiect este solicitat de garbage collector. Spre exemplu dacă o
clasă foloseşte resurse non-Java ( spre exemplu: fişiere manipulate sau fonturile ferestrei sistem)
trebuie utilizată metoda de finalizare pentru a ne asigura că sunt eliberate toate resursele. Această
metodă funcţionează similar cu destructorul din C şi nu se poate confunda cu final.
Rezolvarea acestor excepţii se face adăugând metoda finalize în orice clasă caz în care Java
runtime o apelează de oricâte ori se reclamă eliberarea saţiului pentru un obiect. Metoda trebuie să
ia explicit orice acţiune solicitată pentru a elibera resursele deoarece garbage collector rulează
periodic, verificând obiectele care nu mai sunt referite de alte stări în lucru, sau referite indirect,
prin alte obiecte.
Colectorul de reziduri elibereaza resursele de memorie utilizate de obiectele pe care le distruge dar
obiectele mai păstrează şi alte tipuri de resurse cum ar fi descriptorii sau socket-urile. Colectorul
de reziduri nu poate elibera aceste resurse, astfel încât este necesară o metodă de finalizare proprie
fiecarui obiect care să realizeze operaţii specifice cum ar fi închiderea de fişiere care ramân
deschise accidental sau terminarea unei conexiuni în reţea.
[Link] şi metode
2.2.1. Variabilele
37
In Java variabilele înmagazinează dată iar conform paradigmei OO înglobează starea unui obiect
dat. Acestea sunt divizate în 2 categorii: variabile de instanţă, ce permit individualizarea
obiectelor din clasă şi variabile statice, care se referă la toate obiectele dintr-o clasă dată. Fiecare
obiect individual dintr-o clasă dată este numit instanţă sau instanţiere a clasei. Când se creează un
obiect specific al unei clase, se instanţiază un obiect din clasă şi spaţiul este alocat pentru toate
variabilele de instanţă ale obiectului. Fiecare obiect ce este instanţiat are un spaţiu alocat
independent de variabilele de instanţă.
Variabilele static, pe de altă parte, sunt create odată şi sunt folosite de toate obiectele din clasa
dată şi de clasele moştenite. Nu are importanţă câte obiecte se creează dintr-o clasă, se face o copie
a variabilelor statice ce aparţin clasei. Spre exemplu, în clasa [Link], variabila
MAX_VALUE este statică şi conţine valoarea maximă a unui întreg. Deoarece acest număr este
unic, nu are importanţă câte obiecte întregi sunt instanţiate, se face o singură copie a acestei
variabile şi astfel se alocă memorie minimă.
Referirea variabilelor de instanţă a unui obiect se face prin:
numele_instanţei_specifice.numele_variabilei_de_instanţă.
Exemplu:
In clasa Clasa1 definim variabile de instanţă por şi două obiecte care instanţiază clasa: ap2
şi ap3. Referinţa la variabilă se va face:
[Link]
[Link]
In definiţia de clasă varibilele statice şi de instanţă se pot referi şi fără calificare (suprafata, por,
etc)
38
}
class Clasa1 extends Superclasa {
int i,n;
public void main Method (int n) {
this.n=n; // necesar this, altfel apare conflict de nume
i=super.n; //i=10
}
}
This şi super sunt folosite numai în interiorul metodelor non-statice.
Inainte de a iniţializa un obiect el nu are valoare dar după iniţializare el are valoare implicită null.
Există situaţii în care atribuirea explicită a valorii null este necesară pentru obiecte, în special la
determinarea structurii dinamice de date ca arbori, liste, etc. Aceste structuri pot creşte şi se pot
extinde fără limite iar valoarea null marchează sfârşitul structurii. Un alt caz este thread(firul) de
execuţie, care se opreşte setându-l pe null. [Lema_98]
Observaţie: Se poate atribui valoarea null obiectelor sin orice clasă dar nu şi metodelor şi
variabilelor unor tipuri primitive de dată ( int, float, char, etc).
Exemplu: String str;
După această declaraţie str, este manipulat de obiectul String. Manipulatorul (handle) este similar
cu pointerul C, C++. După declaraţie nu se alocă memorie lui str, considerat ca manipulator null.
Handle nu are sens de "poiter la pointer" ca şi în C sau C++ ci mai degrabă ca referinţă la obiect şi
nu implică adresă fizică.
Observaţie: Spre deosebire de C++ unde variabilele protected sunt aceesibile nimai în clasa dată şi
sublcasele ei, Java extinde conceptul la nivel de pachet, în interiorul căruia variabilele sunt
aceesibile tuturor claselor, chiar dacă aceste clase nu derivă din clasa în care au fost create.
39
Variabilele private sunt accesibile numai în clasele în care sunt declarate şi restricţiile se extind şi
la clasele derivate.
Variabilele static sunt instanţiate odată şi împărţite între toate obiectele clasei în care sunt
declarate şi în toate subclasele moştenite.
Există distincţie între variabilele statice (care aparţin clasi ca întreg) şi varibilele de instanţă care
sunt create separat pentru fiecare obiect al clasei şi este instanţiat ca aparţinând obiectului. Toate
variabilele ce nu sunt explicit declarate static sau final sunt variabile de instanţă.. Static poate fi
combinat cu orice specificator de acces: public, protected, private sau implicit.
Variabilele final sunt de fapt constantele şi de aceea la declararea lor se atribuie şi valoare, altfel
valoarea nu mai poate fi modificată. Deseori se declară constante ca final static. Tip-ul poate fi tip
primitiv, tablou, tip obiect, incluzând obiectele din această clasă. Nume variabilă începe de obicei
cu literă mică.[java_1], [java_8]
2.2.4. Metodele
Comenzile executate de Java sunt conţinute în metode, excepţie făcând blocurile statice. Toate
metodele sunt aflate în clase şi esistă o strictă similitudine cu OO din C++, unde funcţiile pot
exista independente de obiecte dacă programatorul doreşte.
Blocurile statice conţin cod executabil în interiorul metodei şi sunt excepţii. Aceste coduri sunt
folosite pentru a iniţializa variabilele statice ce nu pot fi complet iniţializate sau liniile de declaraţii
(ca şi tablourile).
Blocul static se referă doar la variabile statice şi la cele locale decarate în interiorul blocului.
Exemplu:
class Repar{
static double[] vcos= new double[100]; // variabile statice
static {
// blocul static
for (int i=1, i<100, i++) {
vcos[I]=[Link]((double)i/100.0);
}
…}
}
}
Chiar variabila locală I este implicit statică deoarece este declarată în bloc static şi nu este
accesibilă din esteriorul acestui [Link] interiorul clasei Repar sunt date valori specifice pentru
[Link].
40
Modificatorii metodei pot fi public, protected şi private, cu aceeaşi semnificaţie ca şi
modificatorii de variabilă. Apar câţiva modificatori adiţionali, definiţi pentru metode şi în absenţa
modificatorilor accesul implicit este similar cu cel al variabilelor. Metodele fără modificatori au
câteva caracteristici: sunt moştenite de orice clasă declarată în interiorul pachetului, vizibile în
orice clasă şi disponibile pentru a fi supraacoperite în orice clasă ce o extinde în interiorul
pachetului şi sunt inaccesibile în exteriorul pachetului
Metodele static sunt în acord cu noţiunea de OO încapsulat şi constau în general din metode de
instanţiere care au acces la variabilele de instanţă ale unui obiect instanţiat în [Link]
de instanţiere sunt invocate folosint numele obiectului ca şi codificator.
Exemplu:
[Link](argumente);
Metodele statice la fel ca şi variabilele statice sunt instanţiate odată pentru toate obiectele din clasă
şi de aceea nu pot referi variabile de instanţă, care aparţin obiectelor specifice, nu clasei ca
î[Link] statice pot accesa variabile statice şi sunt implicit final fără a putea fi
supraîncărcate de clase derivate. Invocarea se face cu numele clasei ca şi calificator sau numele
obiectului instanţiat ca şi calificator de clasă.
Exemple: Metoda static din [Link]
String unSir= new String();
String altSir= new String();
UnSir =[Link](5);// echivalente
UnSir =[Link](5);// echivalente
UnSir =[Link](5);// echivalente
Metodele statice nu pot utiliza this şi super şi sunt împărţite de toate instanţele clasei, motiv pentru
care nu aparţin unei instanţe [Link] o metodă cu this pot fi sute de obiecte ce
instanţiază clasa şi nu se poate determina la care se face referire. La super, care este nivelul
moştenirii la care se află metoda? Care clasă e superclasă?- Intrebări fără răspuns. De aceea
metodele statice nu pot face referire la câmpuri non-statice.
Exemplu:
public class Test1{
String str="un sir"// constructor apelat implicit
public static void main (String args[ ]) {
[Link] (str);//eroare, str nu este variabilă non-statică
[Link] ([Link]);//eroare, nu se foloseşte this în metodă
}
}
Metoda final nu poate fi acoperită de clase derivate şi se poate combina cu public, private,
protected sau static sau specificată însuşi cu combinaţiile acestora, în concordanţă cu accesul
implicit precizat. Metoda abstact este declarată dar are implementări diferite în subclase, având
inteles contextual. Ea nu poate fi combinată cu metode ce restrâng moştenirea sau acoperirea
(private, static sau final) iar deoarece un constructor nu poate fi moştenit, nu poate fi final.
Native este metodă proprie în esenţă un apel exterior la funcţii scrise în alt limbaj de programare
(C, C++, etc.). Dearece Java este multithread (multifir) este necesară furnizarea mecanismului de
control al concurenţei pentru că sunt câteva operaţii care se execută simultan iar alte operaţii
41
(citire, scriere de date comune implică manipulări delicate. Declarând metoda sycronized se
garantează că doar un fir va fi executat la un moment dat.[Naugh_96]
Apelul unei metode presupune şi transferul parametrilor (argmentelor) care sunt substituiţi în
interiorul metodei în timpul execuţiei acesteia. Parametri de tip primitiv (int, float, char, boolean)
sunt transferaţi prin valoare, ceea ce înseamnă că se crează o copie locală cu acceaşi valoare ca
parametrul în interiorul metodei iar în exteriorul metodei nu se resimt modificările făcute în copia
locală. Obiectele de tip tablou sunt transferate prin referinţă, ceea ce înseamnă că în interiorul
metodei nu există o copie locală ci poate fi chemat prin valoare. Modificările afectează obiectul
actual şi de aceea ele persistă şi după metodă. [An_96] La declararea metodei se cunosc explicit
tipurile de parametri ce urmează a fi primiţi din lista de argumente a metodei. In OOP nu este
necesară precizarea tuturor informaţiilor solicitate în lista de parametri deoarece metoda ştie deja
despre ele şi are acces la toate variabilele de instanţă precum şi la cele statice în care este
definită.In lista de termeni se precizează doar acele informaţii la care metoda nu are acces, ca şi
instanţele variabilelor pentru alte obiecte, care pot fi diferite de fiecare dată când metoda este
apelată.
Exemplu:
class Fargum{
double d=3.14;
public void fMetoda (double d, Fargum other){
x=x*2.0;
d=other.d;
other.d=0.0; //efect global
}
}
42
Rezultatele obţinute:
Inainte de apel
noud 28.8
nouFargum.d 14.4
altFargum.d 19.2
După apel
noud 28.8
nouFargum.d 1105.92
altFargum.d 0
De multe ori se doreşte crearea unei metode utilizată în exteriorul contextului oricărei instanţe, caz
în care se folosesc metodele statice, care pot apela direct doar metode static şi nu pot fi referite ca
this şi super .In cadrul acestor metode se declară doar variabile static.
Exemplu:
class Static {
static int a=3;
static int b;
static void metoda (int x) {
[Link] ("x="+x);
[Link] ("a="+a);
[Link] ("b="+b);
}
static {
[Link] ("Initializarea blocului static");
b=a*8;
}
public static void main (String args[] ){
metoda (33);
}
}
Un alt mod de a utiliza static este crearea metodelor ce pot fi apelate direct, referind numele clasei
în care sunt declarate. Similar cu apelul metodelor de instanţă prin variabilele de referinţă ale
obiectului, se apelează metoda static pentru a referi variabile static, utilizând . (punct) în numele
clasei.
Exemplu:
class StaticClass {
static int a=23;
43
static int b=90;
static void apel () {
[Link] ("a="+a);
}
class StaticprinNume {
public static void main (String args[] ){
[Link] ();
[Link] ("b="+StaticprinNume.b);
}
}
Modificatorii sunt cuvinte cheie ale limbajului Java care specifică proprietăţi speciale pentru unele
variabile sau metode. Un astfel de modificator este cuvântul rezervat static iar variabilele şi
metodele declarate static într-o clasă, sunt acelaşi pentru toate clasele, adică pentru toate
variabilele de tipul acelei clase. Variabilele statice pot fi accesate fără a fi nevoie o instanţiere a
clasei respective şi analog, nici metodele statice nu au nevoie de o instanţiere a clasei pentru a fi
folosite. Metodele statice pot utiliza variabile statice declarate în interiorul clasei.
Semnătura unei metode este definită prin lista de argumente specificată (număr, ordine şi tip) al
fiecărui [Link] se disting prin prin combinaţii de nume şi semnătură. In Java, la fel ca
şi în C++, este posibilă crearea metodelor supraîncărcate (overloading), care au acelaşi nume şi
semnături diferite. Deseori este utilă oferirea unor funcţionalităţi similare pentru diferite tipuri de
argumente, ceea ce permit metodele cu acelaşi nume iar când acestea sunt apelate, nu apar
ambiguităţi la execuţie, pentru că metodele sunt distinse prin semnătură.
Exemplu:
In clasa [Link] sunt metodele:
public static String valueOf(int i) {…}
public static String valueOf(float i) {…}
Metoda String valueOf(i) ia de fiecare dată tipul de parametru transferat şi în converteşte
în şir. Este normal ca paşii ce se execută la conversia întregului să difere de cei executaţi a
conversia float. Compilatorul foloseşte semnătura pentru a determina versiunea ce trebuie
executată.
Metoda supraîncărcării este mecanismul prin care Java furnizează polimorfismul adhoc în care
copilatorul decide versiunea metodei prin semnătura ei, la momentul apelului metodei, în contrast
cu polimorfirmul pur, furnizat de clasele abstracte. [Chan_96]
44
2.2.9. Valoarea întoarsă de metode
Toate metodele cu exceptia constructorilor, trebuie declarate cu valoare întoarsă şi în caz contrar
cu void, deoarece în Java, omiterea tipului întors este o eroare, spre deosebire de C, C++ care
declară implicit tip int.
Spre deosebire de metodele care întorc void, instrucţiunea return se include în corpul metodelor în
orice punt de execuţie; aceasta opreşte execuţia metodei şi redă controlul metodei apelante.
Compilatorul se asigură de acest lucru şi trateaza fiecare if..then…else din metodă pentru a se
asigura că pe orice ramură metoda este terminată.
Exemplu:
Class MulteIntoarceri {
void maIntorc(String s){
if [Link]("M-am intors"){
return;//intoarcere rapida
}
…// alte instructiuni
return //optional
}
int eronat (Boolean b, Boolean t} {
int i;
double d;
if (b) {
…
return; //eroare, trebuie intors int
}else if (t){
…
return d;// eroare, d este double
}else if (i>0t){
return i;//bine
}else{
…
// lipseste return pentru ca nu este declarat void
}
}
}
Numele metodei urmează regulile anterior descrise şi se recomandă scrierea cu literă mică pentru a
o distinge de constructorii apelaţi.
Lista de argumente se include între paranteze, solicitate chiar în lipsa parametrilor, pentru a fi
distinse de declaraţii de variabile şi metode. Fiecare parametru este precedat de tip
Exemplu:
void diM(String s, int[ ] unTablou, double altTablou[ ])
//sir, tablou de intregi, tablou de reale duble
In general se aşteaptă ca excepţiile să fie rare iar în lipsa lor throws poate fi omis. In rest fiecare
exceptie tratată este separată prin virgulă.
45
2.3. Constructorii
Declaraţiile pure ale unui obiect nu alocă spaţii pentru variabile de instanţă ale acestora. Când un
obiect este delcarat, se instanţiază valoarea null. Instanţierea obiectului se face cu operatorul new.
Exemplu: Contul c=new Contul();
Constructorul este în fapt apelul unei metode speciale definită în orice clasă şi acesta împarte
acelaşi nume cu clasa în care este definit, având rolul de a iniţializa variabilele de instanţă ale unui
obiect, atunci când obiectul este iniţializat.[Lema_98]
46
Când se declară clase derivate, se moştenesc variabilele de instanţă din superclasă. Deoarece
constructorul din clasa derivată nu este el însuşi moştenit, este necesară o iniţializare a variabilelor
de instanţă moştenite. Acest lucru se poate face manual, ceea ce ia mult timp, însă dacă sarcina
este preluată de superclasă este mult mai comod, mai ales dacă se moştenesc varibile private la
care utilizatorul nu are acces. Din fericire, apelând la constructorul super cu condiţia că apare ca
primă instrucţiune în corpul constructorului.
Exemplu:
class Aclass extends AsuperClass {
double unDublu;
Aclass (int I, int j, double d){
super(i,j);//apel Aclass(i,j)
UnDublu=d; //nu a fost iniţializat de super
}
…
}
Se poate declara o clasă fără a specifica constructorul, fapt mai comod în special când o clasă este
moştenită direct din altă clasă. Omiţând constructorul din clasă, compilatorul Java, generează
automat constructorul implicit din superclasă.
Exemplu:
class FinalAclass extends B {
// nu se furnizează constructor
// compilatorul generează automat
FinalAclass{
super();//apel B()
}
…
}
Dacă superclasa imediată (B în exemplu) nu are constructor care să preia argumentele, apar erori
de compilare.
In programare se pot declara constructori private, furnizând metode public static care apelează
constructorul şi întoarce obiectul construit. Pentru crearea unui obiect din exteriorul pachetului se
apelează metoda static însă este util să se verifice argumentele din constructor şi să se trateze
excepţiile care pot apare. Constructorul în sine nu tratează excepţiile dar metodele static pot
analiza excepţiile şi să apeleze constructorul cu argumente corecte.
Limbajul Java pune la dispozitie o metoda pentru crearea claselor complet abstracte, cunoscute ca
şi interfete. Interfeţele sunt destinate pentru a suporta rezoluţiile metodelor dinamice în timpul
execuţiei. Pentru ca o metodă să poată fi apelată dintr-o clasă în alta, ambele clase trebuie să fie
prezente la un moment dat în timpul compilării, pentru a ne asigura că semnăturile metodelor sunt
compatibile. Mecanismul de deconectare a metodei/metodelor din ierarhia moştenirii este protocol
în C obiectual şi interfaţă în Java.[Chan_95], [java_1]
47
public inteface nume_intefată {
// listă metodelor abstracte
}
Exemplu:
interface P(){
byte[]pack();
void unpack(byte b[]);
}
class Punct {
int x,y;
Punct (int x, int y) {
this.x=x;
this.y=y;
}
}
class AltPunct extends Punct implements P {
AltPunct (int x, int y){
super (x,y);
}
AltPunct(){
this (0,0);
}
private byte p(int t, int n) {
return (byte)((t>>n)&Oxff); //octal
}
public byte pack()[]{
byte ret[]=new byte[8];
ret[0]=p(x,24);
ret[1]=p(x,16);
ret[2]=p(x,8);
ret[3]=p(x,0);
ret[4]=p(y,24);
ret[5]=p(y,16);
ret[6]=p(y,8);
ret[7]=p(y,0);
return ret;
}
private int n(byte b, int n){
return ((b&Oxff)<n);
}
public void unpack(byte b[]){
x=u(b[0],24| b[1],16| b[2],8| b[3],0);
x=u(b[4],24| b[5],16| b[6],8| b[7],0);
}
public String toString(){
return("Noul punct"+x+'.'+y);
48
}
}
class PointPack{
public static void main(String args[]){
P p=Altpunct(123456789,555566667);
byte packed[]=[Link]();
AltPunct pnou= new AltPunct();
[Link](packed);
[Link] ("p"+pnou);
}
}
Interfeţele pot avea şi subinterfeţe, care moştenesc variabile (constante în cazul interfeţei) şi
metodele interfeţei din care derivă, dar au posibilitatea de a folosi variabile şi metode proprii.
Pentru a implementa o intefaţă, se utilizeaza cuvantul cheie implements. O clasa poate
implementă mai multe interfete iar daca o clasă declară implementarea unei interfeţe, este
obligatoriu ca ea să implementeze toate metodele din intefaţa respectivă. Programele Java
utilizează interfeţele pentru a suplini lipsa moştenirilor multiple, adică a claselor care derivă din
două sau mai multe clase.
Putem utiliza interfeţele pentru a importa constante împărţite în multiple clase, declarând simplu o
interfaţă ce conţine toate numele şi toate variabilele. Când se implementează apoi această interfaţă,
toate numele acestor variabile vor fi folosite în scop de constante (similar cu fişierul header din
C++ utilizat la crerea unor constante definite prin #defined ca şi constructor). Dacă interfaţa nu
conţine metode, orice clasă ce o implementează nu trebuie să implementeze nimic în plus şi se
comportă ca şi un import de constante dintr-o clasă, ca variabile de tip final.
Exemplu:
import [Link];
interface ConstanteImpartite {
int a=0;
int a1=1;
int a2=2;
int a3=3;
int a4=5;
}
class Prima implements ConstanteImpartite {
Random r=new Random();
int intreb{
int prob= (int)(100*[Link]());
if (prob<30)
return a;
else if prob(<60)
return a1;
else if prob(<75)
return a2;
else if prob(<90)
49
return a3;
}
}
class Doi implements ConstanteImpartite {
static void rasp (int rez) {
switch(rez) {
case a:
[Link] ('Da");
case a1:
[Link] ('Nu");
case a2:
[Link] ('Poate");
case a3:
[Link] ('Nu sunt sigur");
}
}
public static void main (String args[]){
Prima q1= new Prima();
rasp([Link]);
rasp([Link]);
rasp([Link]);
rasp([Link]);
}
}
In interiorul celor două clase codul care referă constantele este dat ca şi cu ele ar fi definite sau
moştenite direct. Toate metodele declarate într-o interfaţă sunt implicit abstract şi similar, toate
variabilele dintr-o interfaţă sunt implicit static şi final deoarece sunt formate ca şi constante. Spre
deosebire de clasă, o interfaţă poate extinde multiple interfeţe moştenind variabilele şi metodele
definite în interior. Orice clasă ce implementează o asemenea interfaţă trebuie să ofere definiţii
pentu toate metodele definite în interfaţă şi toate interfeţele esenţiale.
Exemplu:
interface Simplu1 {
int a;
void absolM1(){
}
interface Simplu2 {
String str;
void absolM2(){
}
Interface Combinata extends Simplu1,Simplu2 {
void absolM3(){
}
}
//ImpClasa cere implementarea metodelor absolM1()
// absolM2(), absolM3()
50
class ImpClass implements Combinata {
public absolM1 (){
// definitia metodei 1
}
public absolM2 (){
// definitia metodei 2
}
public absolM3 (){
// definitia metodei 3
}
// alte metode ale clasei ImpClasa
}
Dacă o clasă implementează o interfaţă sublcasele moştenite pot extinde aceste metode
implementate, respectând restricţiile impuse de specificatorii de acces. In plus dacă o clasă
implementează o interfaţă sau un set de interfeţe nu este necesară includerea acestora în clauzele
implements ale subclaselor.
Metoda constructorului lansează un fir a căriu corp, când este rulat ia metoda run() furnizată d
epropriul applet- cheia înţelegerii interfeţelor. Dacă appletul este declarat Runnable, appletul este
tratat ca obiect Runnable şi orice metodă ( ca şi constructorul anterior) care ia Runnable ca
parametru, poate accepta appletul. Când se apelează metodele ce fac parte din interfaţa Runnable -
în cazul de faţă run()- appletul propriu a furnizat metoda consistentă cu cererea, ceea ce este ca şi
cum ar fi clasă obişnuită numită Runnalbe şi appletul propriu este derivat din clasă. Interfaţa
Runnable este cel mai intuitiv exemplu care ilustrează în acelaşi timp un important concept de
proiectare: keep it simple.
Există doar o metodă implementată în interfaţa Runnalbe şi de aceea este foarte uşor de
implementat în orice clasă proiectată. Dacă se definesc n metode, este greu de imaginat că cineva
consideră convenabilă implementarea tuturor acestor interfeţe iar dacă aceste metode sunt
disparate în câteva interfeţe este facilă implementarea acelor interfeţe care asigură funcţionalitate
absolut necesară.[Ramb_96]. Modificatorii de interfaţă sunt public şi abstract iar în lipsa lor
interfaţa este accesibilă doar în interiorul pachetului. O interfaţă spre deosebire de clasă, poate
extinde mai multe interfeţe.
51
Incercăm să sintetizăm în cele ce urmează caracteristicile specificatorilor de acces la nivelul
claselor, variabilelor şi metodelor.
Public
Clasa - accesibil tuturor claselor din exteriorul pachetului;
Variabile - vizibile tuturor claselor ce acceseză această clasă şi din exteriorul pachetului;
- vizibile în toate clasele derivate din această clasă în şi din exteriorul pachetului;
Metode - vizibile tuturor claselor ce acceseză această clasă şi din exteriorul pachetului;
- vizibile în toate clasele derivate din această clasă în şi din exteriorul pachetului;
- pot fi suprascrise în toate clasele derivate din aceasta în şi din exteriorul pachetului.
Protected
Clasa - inaplicabilă;
Variabile - vizibile tuturor claselor ce acceseză această clasă în interiorul pachetului;
- vizibile numai în clasele derivate în exteriorul pachetului;
Metode - vizibile tuturor claselor ce pot extinde această clasă în interiorul pachetului;
- vizibile doar claselor derivate din această clasă în exteriorul pachetului;
[default] (implicit)
Clasa - în interiorul pachetului accesibile tuturor claselor;
- în exteriorul pachetului inaccesibile;
Variabile - vizibile tuturor claselor în interiorul pachetului;
- vizibile numai în clasele derivate în exteriorul pachetului;
Metode - vizibile tuturor claselor ce pot suprascrie această clasă în interiorul pachetului;
- vizibile doar claselor derivate din această clasă şi pot fi suprascrise de aceste clase, în
exteriorul pachetului;
Private protected
Clasa - inaplicabilă;
Variabile - vizibile doar claselor derivate din aceasta în interiorul şi exteriorul pachetului;
Metode - vizibile doar claselor derivate din această clasă în interiorul/exteriorul pachetului
- pot fi acoperite de clase derivate
Private
Clasa - inaplicabilă;
Variabile - vizibile doar în interiorul clasei;
Metode - - vizibile doar în interiorul clasei.
Final
Clasa - nu pot fi extinse;
Variabile - atribute cu valoare permanentă în declaraţiile lor;
- valoarea nu poate fi schimbată în orice clasă chiar dacă sunt sau nu sunt derivate din
acestă clasă;
metode - nu poate fi acoperită.
Static
Clasa - inaplicabilă;
Variabile - numai copia variabilelor se împarte de toate subclasele;
Metode - - metoda este împărţită de toate subclasele dar nu poate fi extinsă.
Abstract
Clasa - conţine una sau mai multe metode abstracte;
- nu poate fi instanţiată;
Variabile inaplicabilă;
52
Metode - nu este definită şi va fi pusă la dipoziţie de subclasă;
- trebuie acoperită când este subclasată sau subclasa însuşi este abstract.
Native
Clasa - inaplicabilă;
Variabile inaplicabilă;
Metode - este definită în alt limbaj (exterior) ca şi C, C++, etc.
Syncronized
Clasa - inaplicabilă;
Variabile inaplicabilă;
Metode - la momentul dat, numai un fir poate spune obiectului instanţat să
execute această metodă;
- dacă este static, numai un fir poate executa această metodă la un timp dat, periodic.
53
Private Nomodifie Private Protected Public
r Protected
diferite
Diferite pachete non- Nu Nu Nu Nu Da
subclasă
In definirea unei clase se pot include şi nivele de protecţie pentru variabile şi metode, cu ajutorul
unor cuvinte rezervate numite modificatori de acces: protected, public sau private. In lipsa acestor
nivele de protecţie implicit se consideră nivelul prietenos (friendley).[An_96]
In Java protected induce comportament similar cu friend din C++ iar private protected ca şi
protected din c++.
Semnificatiile acestor nivele de protecţie sunt diferite, astfel:
• Protected – metodele şi variabilele sunt declarate protected, sunt disponibile în
clasa în care sunt definite şi în subclasele din această clasă.
• Public - metodele şi variabilele sunt declarate public, fiind disponibile în toate
clasele.
• Private - metodele şi variabilele sunt declarate private, fiind disponibile numai în
clasa în care sunt definite; nici măcar subclasele derivate din această clasă nu au acces
la ele.
• Prietenos(friendly) – nivelul implicit, ele sunt disponibile pentru toate clasele din
pachetul curent.
O variabilă sau o metodă nu poate avea declaraţe mai multe nivele de protecţie simultan, sau în
discordanţă cu pachetul din care face parte, acestea determinând erori la compilare.
Exemplu:
package p1;
public class Protectia {
int n=1;
private int n_pri=2;
protected int n_pro=3;
private protected int n_pripro=4;
public n_pub=5;
public Protectia(){
[Link] ("Constructorii de bază");
[Link] (n);
[Link] (n_pri);
[Link] (n_pro);
[Link] (n_pripro);
[Link] (n_pub);
}
}
class Derivata extends Protectia {
Derivata(){
[Link] ("Constructori derivati");
[Link] (n);
//numai în clasă
54
//[Link] (n_pri);
[Link] (n_pro);
[Link] (n_pripro);
[Link] (n_pub);
}
}
class acPachet {
acPachet(){
Protectia p=new Protectia();
[Link] ("Constructori in acelaşi pachet");
[Link] (p.n);
//numai în clasă
//[Link] (p.n_pri);
[Link] (p.n_pro);
//in clasa si subclasa
[Link] (p.n_pripro);
[Link] (p.n_pub);
}
}
In pachetul p2 două definiţii de clasă acoperă două condiţii ce sunt afectate de controlul accesului.
Prima clasă este subclasă a lui [Link] ce garantează acces la toate variabilele [Link], cu
excepţia lui n_pri (deoarece ea este private) şi n declarată prin protecţie implicită (în interiorul
clasei sau în pachet nu în subclase extrapachet).Clasa AltPachet are acces doar la o variabilă n_pub
declarată public.
Exemplu:
package p2;
class Protectia2 extends [Link] {
Protectia2 () {
[Link] ("Constructor derivat din alt pachet");
// numai in clasa sau pachet
//[Link] (n);
//numai in clasa
//[Link] (n_pri);
[Link] (n_pro);
[Link] (n_pripro);
[Link] (n_pub);
}
}
class AltPachet{
AltPachet (){
[Link] p= new [Link]();
[Link] ("Constructor in alt pachet");
// numai in clasa sau pachet
[Link] (p.n);
//numai in clasa, subclasa si pachet
//[Link] (p.n_pro);
//numai in clasa sau sbclasa
55
//[Link] (p.n_pripro);
[Link] (p.n_pub);
}
}
56
3. Tehnica programării în Java
Spre deosebire de aplicaţiile monouser, unde programatorul scrie metoda principală care
direcţionează activitatea programului de la început la sfârşit, appleturile nu au în general o metodă
main() fiind manipulate de appletviewer sau Web browser care decide asupra iniţializării, rulării,
întreruperii şi distrugerii appletului.[Ramb_96]
start() stop()
Iniţializarea Execuţia Oprirea
appletului appletuluiu appletului
init() start()
destroy()
Distrugerea
appletului
Conform figurii 3.1., programul principal aşteaptă ca appletul să fiec în măsură să execute metode
clare ca: init(), start(0, stop(), destroy() ce constituie ciclul de viaţă al unui applet şi sunt definite în
clasa [Link]. Deşi sunt metode cu corp void se aşteaptă ca programatorul să le
defineasă astfel încât ele să poată fi utilizate în scopul solicitat de appletul proiectat.
Metoda init() este apelată la prima încărcare a appletului, practic odată în tot ciclul de viaţă al
appletului şi se foloseşte pentru a iniţializa variabilele de instanţă, pentru setarea dimensiunii
appletului final, fundalul şi primplanul acestuia sau pentru stabilirea unor condiţii iniţiale de
execuţie propriu-zisă.
Metoda start() este similară cu main() method a appletului şi este apelată imediat după init()
declanşând execuţia appletului. Dacă appletul este oprit, metoda poate fi apelată din nou, pentru a
57
re-rula appletul, apărând ori de câte ori se doreşte instanţierea firelor sau pentru execuţia unui task
principal din applet.
Metoda stop() este apelată când appletul rulează şi utilizatorul minimizează fereastra browserului
sau reîncarcă pagina. Dacă se doreşte oprirea appletulului sau a firelor, metoda poate fi apelată şi
succedată de start() pentru a re-rula appletul..
Metoda destroy() este apelată când appletul poate fi eliminat din memorie (purge) deşi garbage
collector face acest lucru şi fără metoda în sine. In mod normal extinderea metodei se impune doar
în situaţii limită când appletul foloseşte resurse ale altor clase externe care trebuie gestionate de
către utilizator.
Exemplu:Structura generală a unui applet
import [Link];
import [Link].*;
import [Link].*;
public class StructuraApplet extends Applet {
public void init() {
}
public void start() {
}
public void stop() {
}
public void destroy() {
}
Pentru a construi un applet este nevoie să creăm o clasă care este derivată din clasa de bază Applet
aflată în pachetul [Link]. Clasa Applet este clasa ce oferă cadrul absolut necesar comunicării
cu browserul WWW, practice o interfaţă de comunicare a unui program Java cu browserul. Orice
applet este implementat prin crearea unei subclase a clasei Applet. Ierarhia claselor din care deriva
Applet este prezentată în figura 3.2. Fiind derivata din clasa Container, clasa Applet descrie de fapt
suprafete de afisare, asemenea claselor Frame sau Panel.
58
Figura 3.2. Ierarhia de clasă a appletului
Tagul html de conexiune cu fişierul class este tagul APPLET şi are varianta minimală de forma:
<APPLET CODE=”[Link]”
WIDTH=300
HEIGHT=200>
</APPLET>
Exemplu:
import [Link];
import [Link].*;
public class AppletExemplu extends Applet {
public void paint(Graphics g) {
[Link](new Font("Arial", [Link], 16));
[Link]("Java", 0, 30);
}
}
59
In cazul în care compilarea a reusit va fi generat fisierul [Link].
Pentru a vizualiza un applet trebuie creat un document HTML (ex: [Link]), în care se
specifică cel putin următoarele informaţii:
clasa ce contine codul appletului
latimea si înaltimea suprafetei alocate pe pagina Web
<HTML>
<HEAD>
<TITLE> Exemplu de applet </TITLE>
</HEAD>
<APPLET CODE="[Link]" WIDTH=100 HEIGHT=50></APPLET>
</HTML>
Vizualizarea acestui document se poate face cu orice browser (Internet Explorer, Netscape, etc),
sau cu utilitarul appletviewer ce vine în pachetul JDK.
appletviewer [Link]
60
ALT = textAlternativ specifică textul ce trebuie afisat daca browserul întelege tagul
APPLET dar nu poate rula appleturi Java.
NAME = numeInstantaApplet oferă posibilitatea de a da un nume respectivei instanţe
a appletului, astfel încât mai multe appleturi aflate pe aceeasi pagina să comunice între ele
folosindu-se de numele lor.
WIDTH = latimeInPixeli respective HEIGHT = înaltimeInPixeli - specifică laţimea şi
înalţimea suprafeţei în care va fi afişat appletul.
ALIGN = aliniere - semnifică modalitatea de aliniere a appletului în pagina Web şi
poate primi una din urmatoarele valori: left, right, top, texttop, middle, absmiddle,
baseline, bottom, absbottom similare cu si la tagul IMG.
VSPACE = spatiuVertical şi HSPACE = spatiuOrizontal - specifică numărul de
pixeli dintre applet şi marginile suprafeţei de afişare.
< PARAM NAME = numeParametru1 VALUE = valoare1 >
Tag-urile <PARAM> sunt folosite pentru specificarea parametrilor unui applet.
text HTML alternativ - textul ce va fi afisat în cazul în care browserul nu poate interpreta tagul
APPLET iar browserele care înteleg Java vor ignora acest text.
Tipul parametrilor este şir de caractere, indiferent dacă valoarea este între ghilimele sau nu şi
fiecare applet are în plus un set de parametri prestabiliţi ale caror nume nu vor putea fi folosite
pentru definirea de noi parametri (folosind metoda de mai sus). Aceştia apar direct în corpul
tagului APPLET şi definesc informaţii generale despre applet (spre exemplu parametri CODE,
WIDTH sau HEIGHT). Folosirea parametrilor primiţi de către un applet se face prin intermediul
metodei getParameter() care primeşte ca argument numele unui parametru şi returnează valoarea
acestuia. In cazul în care nu exista nici un parametru cu numele specificat, metoda întoarce null,
caz în care programul trebuie să atribuie o valoare implicită variabilei associate respectivului
parametru.
import [Link];
import [Link].*;
61
public class AppletExemplu extends Applet {
String text, numeFont;
int dimFont;
public void init() {
text = getParameter("textAfisat");
if (text==null)
text="Java"; // valoare implicita
numeFont = getParameter("numeFont");
if (numeFont==null)
numeFont="Arial";
try {
dimFont = [Link](getParameter("dimFont"));
}
catch(NumberFormatException e) {
dimFont = 16;
}
}
public void paint(Graphics g) {
[Link](new Font(numeFont, [Link], dimFont));
[Link](text, 20, 20);
}
}
In general se evită definirea şi utilizarea unui număr mare de parametri în appleturi deoarece le
face practic neutilizabile, datorită dificultăţii de memorare a acestora. Soluţia recomandată este
utilizarea şi extinderea metodei getParameterInfo() definită în clasa [Link] pentru
appleturile proiectate, ceea ce oferă posibilitatea vizualizării tuturor parametrilor appletului
precum şi a altor informaţii ofetite de appletviwer.
Exemplu:
public String[ ][ ] getParrameterInfo() {
String [ ] [ ] Info={
{"MESSAGE", "String", "mesaj afisat"},
{"PAUSE", "int", "durata pauzei"},
{"STEPSIZE", "int", "dimensiunea pasului"},
{"FONTNAME", "String", "nume font"},
{"FONTSTYLE", "int", "stil font 0-PLAIN, 1-BOLD"+
"2-ITALIC"+"combinatii"},
{"FONTSIZE", "int", "dimensiunea fontului"},
{"MSG_COLOR", "int", "nume culoare"}
};
return Info;
}
In exemplul de mai sus, metoda întoarce un tablou de tablou de şiruri. Variabila locală Info se
iniţializează în timpul declaraţiei iar tabloul este iniţializat unidimensional, fiecare element fiind
la rândul lui un tablou. Dacă şirul este prea lung, pentu o linie, el se întrerupe cu " şi se continuă cu
operatorul de concatenare + deşi se poate folosi simplu return pentru continuarea textului pe o
nouă linie deoarece compilatorul recunoaşte faptul că nu s-a terminat şirul.
62
Observaţie: Java nu are operator de supraîncărcare (overloading) şi nu permite programatorilor
atribuirea unui alt inţeles operatorilor. Singura excepţie de la regulă este + (concatenarea şirurilor),
deşi operatorii aritmetici (+,-,*,/) care pot fi utilizaţi în int, flat, long, double sunt ei însuşi
supraîncărcaţi prin moştenirile acestora.
Clasa [Link] defineşte metoda getParameter(String Nume1) prin care întoarce valoarea
pereche a şirului Nume1 din interiorul fişierului HTML (tag-ul parameter). In caz contrar,
înroarce şirul null. Prin wrapper classes (clasele acoperitoare) se pot utiliza şi valori int, boolean,
float dacă sunt apelate metodele de conversie între şiruri şi tipurile primitive.
Orice applet poate pune la dispozitie o "documentatie" referitoare la parametrii pe care îi suporta,
pentru a veni în ajutorul utilizatorilor care doresc sa includa appletul într-o pagina Web. Aceasta se
realizeaza prin supradefinirea metodei getParameterInfo, care returneaza un vector format din
triplete de siruri. Fiecare element al vectorului este de fapt un vector cu trei elemente de tip
String, cele trei siruri reprezentând numele parametrului, tipul sau si o descriere a sa.
Informatiile furnizate de un applet pot fi citite din browserul folosit pentru vizualizare prin metode
specifice acestuia. De exemplu, în Netscape se foloseste optiunea Page info din meniul View.
Exemplu:
public String getAppletInfo() {
return "Exemplu de applet, autor Delia Corches, ver 1.0";
}
63
STARTIMAGE="Numar1" -- numărul cadrului de început (1..n)
ENDIMAGE="Numar2" -- numărul cadrului de sfârşit (1..n)
PAUSE="100" -- millisecunde de pauză între imagini, implicit poate fi suprascris prin
PAUSES)
PAUSES="300|200||400|200||100" -- millisecond întârziere pe cadru
Blank utilizează valoarea implicită a lui PAUSE
REPEAT="true" -- repetă secvenţa?
POSITIONS="100@200||200@100||200@200|100@100|105@105"
posiţiia (X@Y) pentru fiecare cadru
Blank - permite utilizarea poziţia cadrului anterior
IMAGES="3|3|2|1|2|3|17" -- ordine explicită de cadre
SOUNDSOURCE="Director2" -- directorul ce are fişiere audio
SOUNDTRACK="Fişier3" -- fişier audio ce este redat
SOUNDS="[Link]|||||[Link]" -- fişiere audio asociate cadrelor individuale
Cum clasa Applet este o extensie a superclasei Container, înseamnă ca appleturile sunt,
înainte de toate, suprafeţe de afisare. Plasarea componentelor, gestionarea pozitionarii lor şi
tratarea evenimentelor generate se realizează la fel ca şi în cazul aplicaţiilor. Adăugarea
componentelor pe suprafata appletului şi stabilirea obiectelor responsabile cu tratarea
evenimentelor generate sunt operaţiuni ce vor fi realizate în metoda init. Gestionarul de
pozitionare implicit este FlowLayout, care poate fi schimbat prin metoda setLayout.
Exista o categorie întreagă de appleturi ce nu comunica cu utilizatorul prin intermediul
componentelor, ci executia lor se rezuma la diverse operatiuni de desenare executate în metoda
paint. Metoda paint permite definirea aspectului grafic al oricărei componente şi trebuie
supradefinită. In acest caz evenimentele tratate uzual vor fi cele generate de mouse sau tastatură.
Pentru manipularea imaginilor clasa Applet pune la dispoziţia programatorului două metode de
creare obiect de tip imagine:
public Image getImage(URL url)- metodă care crează un obiect imagine (de tipul
Image) având ca şi parametru locaţia absolută WWW (URL-ul) unde se găseşte fişierul
imagine. Fişierul trebuie să fie unul din tipurile suportate de Java (gif, jpg).
public Image getImage(URL url, String name)- returnează un obiect imagine. Are ca
parametrii locaţia relativă WWW şi numele fişierului imagine.
Afisarea imaginilor într-un applet se face fie prin intermediul unei componente ce permite acest
lucru - o suprafaţă de desenare de tip Canvas, fie direct în metoda paint a applet-ului, folosind
metoda drawImage a clasei Graphics. In ambele cazuri, încarcarea imaginii în memorie se va
face cu ajutorul metodei getImage din clasa Applet. Aceasta poate primi ca argument fie adresa
URL absoluta a fisierului ce contine imaginea, fie calea sa relativa la o anumita adresa URL, cum
64
ar fi cea a directorului în care se gaseste documentul HTML ce contine appletul
(getDocumentBase) sau a directorului în care se gaseste clasa appletului (getCodeBase).
Pentru eliminarea problemelor de flashing se poate folosi tehnica double-buffering. Prin această
tehnică se desenează appletul într-o imagine ascunsă după care se afişează această imagine în zona
vizibilă.
Pentru a lucra cu fişiere audio, există în clasa Applet două metode care returnează un obiect Java
de tip AudioClip. Acest obiect poate fi folosit mai apoi pentru execuţia sunetului:
<APPLET CODE=”[Link]”
WIDTH=300
HEIGHT=200>
65
<PARAM NAME=”DISPLAYED_STRING”VALUE=”Bine ati venit pe site-ul meu”>
</APPLET>
Pentru a putea face cunoscută în exterior lista parametrilor, numele, tipul şi scopul acestora,
programatorul poate suprascrie metoda
public String[][] getParameterInfo()
În cazul exemplului de mai sus avem:
66
public void init() {
showStatus("Initializare applet...");
}
e. Comunicarea cu alte applet-uri aflate pe aceeaşi pagină implică de fapt identificarea unui
applet aflat pe aceeasi pagina si apelarea unei metode sau setare unei variabile publice a acestuia.
Identificarea se face prin intermediu numelui pe care orice instanta a unui applet îl poate specifica
prin atributul NAME. Obtinerea unei instante a unui applet al carui nume îl cunoastem sau
obtinerea unei enumerari a tuturor applet-urilor din pagina se fac cu metodele definite de interfata
AppletContext getApplet si getApplets.
f. Contextul de execuţie al unui applet se refera la pagina în care acesta rulează şi este descris de
interfata AppletContext. Crearea unui obiect ce implementează aceasta interfaţă se realizeaza de
catre browser, la apelul metodei getAppletContext a clasei Applet. Prin intermediul acestei
interfete un applet poate "vedea" în jurul sau, putând comunica cu alte applet-uri aflate pe aceeasi
pagina sau cere browser-ului sa deschida diverse documente.
AppletContext env = getAppletContext();
Pentru a împiedica accesul unor appleturi maliţioase la resursele maşinii locale, browserul
implementează o serie de politici de securitate. Astfel unui applet îi sunt interzise o serie de
operaţii (unele descrise mai sus) care pot fi executate în cazul aplicaţiilor Java stand-alone. Politica
de securitate este implementată prin clasa SecurityManager.
67
Fiecare browser are un SecurityManager care implemntează politica de securitate. Când se
încearcă o violare a drepturilor acest SecurityManager aruncă o excepţie de tipul
SecurityException.
JDK oferă o soluţie prin care se pot acorda unor categorii speciale de appleturi anumite drepturi
de acces (altfel interzise) la resursele maşinii client. Pentru aceasta se foloseşte semnătura digitală
a appleturilor.
Observaţii:
Toate numele parametrilor se trec între ghilimele şi sunt necesare când există
spaţii sau caracere de separaţie a căilor.
Nu toate clasele acoperite construite furnizează convesrie facilă în clasa Integer,
când se solicită parametri numerici în appleturi. Astfel, pentru conversie float:
Exemplu:
float f;
String f_string=getParameter("f_par");
float f_acop=[Link](f_string);//conversie
f=f_acop.floatValue();
//valoarea conţinută
[Link]
68
In problema anterioară este necesară existenţa unui applet care execută animaţia în fir separat şi un
altul ce rulează concurent, evitând monopolizarea CPU. Problema centrală este de a crea un fir
responsabil d emanipularea evenimentelor, scopul fiind de a rula animaţia, în timp ce redă
controlul CPU.
Faţă de conceptul tradiţional în are programul execută o serie de instrucţiuni în ordine, firele sunt
în fapt o localizare independentă a controlului unui program. Manipulând mai multe fire de
execuţie, se poate executa o parte a instrucţiunilor din lista unui fir, după care să se execute o altă
succesiune de instrucţiuni din alt fir, dar la momentul revenirii la firul anterior, să se localizeze
exact porţiunea de instrucţiuni din listă (locus of control - localizarea controlului). Programele
multithread au simultan mai multe loc of control deşi unele sisteme utilizează un singur procesor,
simulând în fapt execuţia paralelă sau multifir, în realitate oferind o cuantă de timp în care
utilizează microprocesporul (de ordinul câtorva microsecunde), algoritmii de planificare, ajungând
la un sistem dependent.[Zaha_00]
Implementarea interfeţei Runnable este un mod convenabil de creare a appletului [Link]
[Link] este subclasă a lui [Link], creând un applet ca subclasă a
[Link], contrazicem principiul moştenirii simple. De aceea la implementarea interfeţei
Runnable se cer implementate toate metodele acesteia - adică run() - metoda definită de Runnable
astfel încât appletul presupune:
Includerea clauzei implements Runnable în declaraţia de clasă a appletului;
Estinderea metodei run() a interfeţei Runnable, cu codul principal în appletul propriu;
Metoda start() a appletului propriu crează un fir trecând appletul ca parametru al
constructorului, prin cuvântul cheie this
Metoda stop() a appletului propriu, cu codul acestuia, opreşte execuţia firului.
Pentru exemplificare vom modifica exemplul anterior astfel încât să nu monopilizăm CPU.
Exemplu:
import [Link];
import [Link];
import [Link];
69
}
Rularea appletului
70
BandaDefinlanta are superclasa imediata Applet şi totuşi moşteneşte metoda abstractă run() din
interfaţa Runnable, care trebuie extinsă pentru instanţierea appletului [Link]ă aceasta,
metoda poate fi trecută ca parametru în orice metodă care poate primi un obiect Runnable, de fapt
în metoda start().
Se instanţiază un obiect din [Link] (cum [Link].* este importat automat) iar
constructorul Thread() utilizat ia obiectul Runnable ca parametru şi setează metoda run() a lui
Thread pentru a apela metoda run() transmisă în obiect.
Cu proFir instanţiat apelul [Link]() este motivat deja, iar acesta apelează la rândul lui
[Link]() şi apoi întoarce [Link] justifică de ce nu trebuie aşteptat ca [Link]() să
se execute complet, în modul sincron, în care s-ar executa normal o metodă. Aceasta înseamnă că
se dă controlul lui [Link]() în firul principal, în timp ce metoda run() se execută în
firul paralel, ca fir separat (proFir). Acum [Link]() completează, returnând controlul
asupra sistemului astfel încât se pot asimila ca evenimente manipulate, poate chiar apelate de
propria metodă stop() a appletului.[java_5], [java_6]
Un aspect neobişnuit este faptul că BandaDerulanta şi proFir împart acceaşi metodă run() în timp
ce metodele proprii start() nu sunt echivalente. In fapt metodele run() au doar similitudini de apel,
funcţionalitatea lor fiind distinctă.Realitatea este că BandaDerulanta şi proFir nu împart acceaşi
metodă run() ci Thread este instanţiat într-un asemenea mod încât apelează metoda run() a
appletului.
După instanţierea firului şi apelul lui [Link]() appletul are 2 fire de execuţie: cel principal, care
manipulează evenimentele şi apelează metodele din ciclul de viaţă al appletului şi al doilea care
produce execuţia animaţ[Link]ţia este de fapt o buclă întreruptă când firul este oprit (while
proFir !=null;). Deoarece se utilizează o variabilă locală pentru reprezentarea firului în metoda
run(), când metoda run() se termină firul îşi atinge scopul şi valoarea devine null (sinonim cu
terminarea firului).
Metoda repaint() a appeltului este moştenită din [Link] şi apelează metoda
update() implicită, care redesenează fundalul şi apoi paint().
Pauza a fost implementată printr-o buclă iterativă, care de fapt consumă timpul procesorului fără a
face nimic (buzy-waiting). Apelând [Link]() cu parametru întreg, se indică timpul după care
se eliberează CPU. In interiorul blocului try şi catch se apelează [Link]() şi de fapt nu se
execută efectiv manipularea excepţiilor ci se indică ceea ce clasa nu poate proiecta ca excepţii
manipulate. In mod normal InterruptedException are un simplu return prin care metoda run() se
termină. Metoda stop() se apelează când utilizatorul comută diferite pagini sau monimizează
browserul, caz în care CPU este eliberat, proFir=null şi devine candidat la gerbage collector.
"Omorârea" (kill) nu presupune distrugerea lui (destroy), rămânând starea memorată în varibilele
de instanţă.La apelul lui start() se crează un nou fir, continuând proFir de unde a fost lăsat.[java_7]
Priorităţile firelor sunt valori întregi (1-10) utilizate la schimbarea (switch) a firului [Link]
execută un singur fir la un moment dat deşi un fir poate renunţa voluntar la control prin
determinări explicite, dormind sau blocând prin agăţare I/O sau poate fi pre-empted. In primul caz
sunt examinate firele în funcţie de priorităţi şi cel cu prioritate maximă şi care este gata de rulare
are controlul CPU. In al doilea caz, cumun fir renunţă voluntar, firul cu prioritate maximă care
vrea să ruleze o va face dar situaţia limită apare când 2 fire cu aceeaşi prioritate cer control CPU.
71
[Link] defineşte conceptul de monitorizare. De vreme ce firele introduc comportament
asincron al programului, trebuie să existe o metodă de a forţa sincronizarea necesară. Monitoarele
sunt prescrise pentru a proteja resursele partajabile sa în vederea manipulării acestora de mai multe
ori la un moment dat. In Java monitorul este dat de metoda syncronized. Mesajele schimbate între
2 fire sunt focalizate cu metodele wait şi notify. Un fir poate introduce metoda syncronized pe un
obiect şi să aştepte până când un alt fir notifică explicit ieşirea. Analog, mai multe fire pot
introduce metoda syncronized pe un obiect şi să aştepte până când apare aceeaşi notificare. Firul
curent ce se execută poate fi terminat cu [Link].[java_4]
72
5
4
3
2
1
unde main este numele unui grup de fire cu care se leagă.
Runnable este în fapt o simplă interfaţă ce abstractizează noţiunea de aştepare înaintea execuţiei
asincrone, cum putem observa în exemplul următor.
Exemplu:
class FirCurent implements Runnable {
Thread ct=[Link]();
[Link] ("firul curent"+ct);
Thread t=new Thread (this, "Noul Thread");
[Link] ("firul nou"+t);
[Link]();
try {
[Link]();
}catch(InterruptedException e){
[Link] ("intrerupt");
}
[Link] ("Iesire din firul principal");
}
}
public void run(){
try{
for (int n=5; n>0; n_-){
[Link] (" "+n);
[Link](1000};
} catch(InterruptedException e){
[Link] ("Fir intrerupt");
}
[Link] ("Iesire din firul fiu");
}
public static void main(String args[]){
new FirCurent();
}
}
Rezultatul execuţiei:
Firul curent Thread[main,5,main]
Firul nou Thread[Noul Thread,5,main]
5
4
3
Iesire din firul principal
2
1
73
Iesire din firul fiu
Setarea priorităţii de realizaeză cu metoda setPriority cu 2 nivele faţă de cea normală
reprezentată de Thread.NORM_PRIORITY(HIGH,LOW)
Exemplu:
class ClasaFir implements Runnable {
int click=0;
private Thread t;
private boolean ruleaza=true;
public ClasaFir (int p) {
t= new Thread(this);
[Link](p);
}
public void run(){
while(ruleaza) {
click++;
}
}
public void stop(){
ruleaza=false;
}
Alte sisteme multifir expun conceptul de monitor. Un monitor este obiectul ce foloseşte blocajul
mutual exclusiv 4 şi numai un fir poate deţine monitorul la un moment dat. Când un fir solicită
blocarea se spune că a intrat în monitor. Toate celelate fire care încearcă să intre şi să blocheze
4
Mutual exclusive lock - mutex
74
monitorul sunt suspendate până când este eliberat, deşi un fir ce deţine monitor poate reintra la
acelaşi monitor dacă doreş[Link] este soluţionată prin metoda syncronized.[Naugh_96]
Exemplu:
Clasa apel are o singură metodă - apel, cu parametru msg şi încearcă tipărirea mesajului după care
cheamă [Link]. Constructorul clasei Apelant ia o referinţă către o instanţă a clasei Apel şi un
şir memorat în tinta şi mesajur respectiv msg. Constructorul crează un fir Thread care va apela
metoda run() a acestui obiect. Firul începe imediat şi metoda run a lui Apelant este simplă, apelând
doar instanţa tinta a lui Apel, trecând mesajul. In final, clasa Sync ia lucrurile, pornind de la
crearea unei instanţe Apel şi trei instanţe Apelant, fiecare cu mesajul său. Aceeaşi instanţă este
trimisă la fiecare Apelant.
Codul sursă:
class Apel {
void apel(String msg){
[Link] ("["+msg);
try [Link](1000); catch(InterruptedException e);
[Link] ("]");
}
}
class Apelant implements Runnable {
String msg;
Apel tinta;
public apelant (Apel t, String s){
tinta=t;
msg=s;
new Thread(this).start();
}
public void run(){
[Link](msg);
}
}
class Sync {
public static void main(string args[]);
Apel tinta= new Apel();
new Apelant (tinta, "Bine");
new Apelant (tinta, "sincronizate");
new Apelant (tinta, "firele");
}
}
Rezultat:
[Bine[sincronizate][firele]
inlocuind cu
syncronized void Apel(String msg){
apare ieşirea metodei sincronizate astfel:
[Bine]
[sincronizate]
75
[firele]
Java include un mecanism de cumunicare inter-proces, prin wait, notify şi notifyAll implementate
ca metode finale în Object şi toate clasele acestuia. Cele trei metode pot fi apelate numai din
interiorul unei metode syncronized şi au rolul:
wait- spune firului să lase monitorul şi apoi sa "doarmă" (sleep) până când alt fir intră
în acelaşi monitor şi apelează notify.
notify - trezeşte primul fir ce a chemat wait pe acelaşi obiect.
notifyAll - trezeşte toate firele ce au chemat wait pe acelaşi obiect şi firul cu prioritatea
cea mai mare este rulat primul.
Exemplu:
Construim 4 clase:Q care încearcă sincronizarea accesului, PC care crează simplu
următoarele clase, respectiv Producator- care produce intrări în coadă, Consumator şi obiectul
Threaded care consumă intrările din coadă
class Q{
int n;
syncronized int iau(){
[Link] ("iau:"+n);
return n;
}
syncronized void pun (int n){
this.n=n;
[Link] ("pun"+n);
}
}
class Producator implements Runnable {
Q q;
Producator( Q q) {
this.q=q;
new Thread(this, "producator").start();
}
public void run() {
int i=0;
while(true) {
[Link](i++);
}
}
}
76
}
public void run() {
int i=0;
while(true) {
[Link](i++);
}
}
}
class PC {
public static void main(String args[]){
Q q=new Q();
new producator(q);
new Consumator(q);
}
}
Chiar dacă metodele pun şi iau sunt sincronizate, nu opreşte nimic pe Producător să ruleze
peste Consumator şi nici Consumatorul să consume o valoare d e2 ori astfel:
Rezultat:
Pun 1
Iau 1
Iau 1
Iau 1
Pun 2
Pun 3
Pun 4
Pun 5
Pun 6
Iau 6
Modalitatea polling fixează ceea ce se primeşte setând o variabilă booleană, trecând apoi într-un
loop de evaluare şi aşteptând valoare avariabilei consumate astfel:
class Q{
int n;
boolean valset=false;
int iau(){
while ( !valset){
[Link] ("iau:"+n);
valset=false;
return n;
}
void pun (int n){
while ( !valset){
this.n=n;
valset=true;
[Link] ("pun"+n);
}
}
77
Varianta anterioară consumă enorme resurse CPU şi practic nu face nimic. O altă soluţie
este:
class Q{
int n;
boolean valset=false;
sycronized int iau(){
if ( !valset){
try wait();
catch(Interrupted Exception e);
[Link] ("iau:"+n);
valset=false;
notify();
return n;
}
syncronized void pun (int n){
if (valset){
try wait();
catch(Interrupted Exception e);
this.n=n;
valset=true;
[Link] ("pun"+n);
notify();
}
}
Rezultat:
Pun 1
Iau 1
Pun 2
Iau 2
Pun 3
Iau 3
…
Pun 7
Iau 7
3.2.5. Blocajul
Practic blocajul5 este foarte greu sau nu poate fi depanat deloc când este condiţionat de 2 fire ce au
dependenţă circulară de o pereche de obiecte sincronizate. [An-96],[java_5] Spre exemplu, un fir
intră pe monitor pe obiectul X şi apoi încearcă să apeleze o metodă sincronizată pe y. Dacă y
încearcă să apeleze orice metodă sincronizată cu y aşteaptă întotdeauna până este deblocat de x
pentru că nu se poate elibera de propriul blocaj.
Exemplu:
class A {
syncronized void prima (B b){
String nume=[Link]().getName();
5
deadlock
78
[Link] (nume+"introdus de metoda [Link]);
try Thread sleep(1000); catch (Exception e );
[Link] (nume+"ce incearca apel [Link]"+[Link]);
[Link]();
}
syncronized void last(){
[Link] (" interior [Link]");
}
}
class B{
syncronized void bar (A a){
String nume=[Link]().getName();
[Link] (nume+"introdus de metoda [Link]);
try Thread sleep(1000); catch (Exception e );
[Link] (nume+"ce incearca apel [Link]"+[Link]);
[Link]();
}
syncronized void last(){
[Link] (" interior [Link]");
}
}
Fiecare applet aflat pe o pagina Web se executa într-un fir de executie propriu. Acesta este creat de
catre browser si este responsabil cu desenarea appletului (apelul metodelor update si paint)
precum si cu transmiterea mesajelor generate de catre componentele appletului. In cazul în care
dorim sa realizam si alte operatiuni consumatoare de timp este recomandat sa le realizam într-un
79
alt fir de executie, pentru a nu bloca interactiunea utilizatorului cu appletul sau redesenarea
acestuia.
Structura unui applet care doreste sa lanseze un fir de executie poate avea doua forme. In prima
situatie appletul porneste un fir de executie la initialzarea sa, iar acesta va rula indiferent daca
appletul mai este sau nu vizibil, pâna la oprirea sa naturala (terminarea metodei run).
In cazul în care firul de executie pornit de applet efectueaza operatii ce au sens doar daca appletul
este vizibil, cum ar fi animatie, ar fi de dorit ca acesta sa se opreasca atunci când appletul nu mai
este vizibil (la apelul metodei stop) si sa reporneasca atunci când appletul redevine vizibil (la
apelul metodei start).
Ex: import [Link];
public class StructuraApplet extends Applet implements Runnable {
Thread appletThread = null;
boolean running = false;
public void start() {
//reporneste firul de executie
if (appletThread == null) {
appletThread = new Thread(this);
running = true;
[Link]();
}
}
public void stop() {
//opreste firul de executie
running = false;
appletThread = null;
}
public void run() {
while (running) {
//codul firului de executie
}
}
80
}
Un applet este considerat activ imediat dupa apelul metodei start si devine inactiv la apelul
metodei stop. Pentru a afla daca un applet este activ se foloseste metoda isActive.
Excepţia este o condiţie excepţională, deosebită ce apare în timpul execuţiei unui program.
Excepţională este condiţia a cărei cunoaştere este posibilă dar se aşteaptă să apară rar sau deloc.
Limbajul Java defineşte clasa [Link] pentru încapsularea noţiunii de excepţie, prin
cele două clase ale sale: [Link] şi [Link]. Excepţia poate fi prinsă (caucht)
şi anulată într-o manieră oarecare, chiar permiţând un impact negativ asupra execuţiei unui
program. Eroarea nu poate fi prinsă de utilizator şi în general obligă la terminarea programului 6.
Când apare o excepţie, metoda ce o generează proiecteaza excepţia şi în general se termină
execuţia metodei, trimiţând un mesaj apelantului în forma unui obiect excepţie din clasa
[Link]. Când o metodă cauzează excepţie, aceasta poate fi prinsă (catch) prin
plasarea apelului "periculos" intr-o buclă try/catch sau poate fi ignorată (netratată). Dacă excepţia
care apare nu este controlată se spune că nu este proiectată (trown) sau dacă este tratată (catch)
poate genera la manipulare alte erori sau chiar o nouă excepţie.
Manipularea erorilor se realizează prin blocul try/catch cu sau fără finally cu sintaxa:
try {
//codul ce generează excepţia
…
} catch (ClasădeExcepţii nume) {
// codul ce le manipulează orice subclasă din ClasădeExcepţii
} catch (AltaClasădeExcepţii nume) {
// codul ce le manipulează orice subclasă din AltaClasădeExcepţii
}finally {
// cod ce preia execuţia
}
Blocul try este utilizat pentru excepţii de orice tip şi ieşiri anormale (break, return, continue). La
apariţia unei excepţii, interpreterul analizează primul bloc try/catch întâlnit, în care caută clauza ce
marchează o clasă de excepţii. Din acest motiv se specifică întâi excepţiile frecvente şi apoi în
mod gradula cele [Link] blocul finally se preia execuţia dacă blocul try este completat normal
(fără excepţii), dacă unul din blocurile catch manipulează excepţii respectiv dacă in blocurile catch
nu este tratată excepţia respectivă. Acestea sunt aşa numitele excepţii trigger, caz în care fiecare
catch va avea asociat un bloc finally. Pentru a defini comportamentul în toate cazurile, indiferent
dacă excepţia apare sau nu, se specifică bloul finally, executat ori de câte ori se termină un bloc try
(normal sau nu) şi după execuţia unui bloc catch.
Excepţiile nemanipulate (unhandled exceptions) apar când blocul try/catch este inexistent sau nu
are clauză pentru excepţia apărută, caz în care interpreterul caută în cel mai apropiat bloc închis.
Dacă nici o metodă nu tratează excepţia, ea se propagă înapoi în metoda main() şi interpreterul va
6
De obicei de foloseşte termenul de excepţie la ambii descendenţi (Exception şi Error)
81
ieşi, tipărind eroarea, un mesaj şi stack trace (urma stivei).[Chan_95] Dacă se decide ignorarea
unei excepţii, metoda trebuie să aibă precizată în declaraţie faptul că proiectează o clasă
particulară de excepţii, cu menţiunea că o metodă poate proiecta oricâte clase de excepţii, separate
prin virgulă în declaraţie. Metodele extinse nu pot proiecta excepţii.
Spre deosebire de excepţiile normale, apar excepţiile Runtime (anormale) subclasate în
[Link], care pot fi generate de o serie de acţiuni în timpul execuţiei (acces
nepermis la tablouri, operaţii aritmetice, etc.). Dacă metodele nu includ catch pentru aceste
excepţii nu este necesară includerea clauzei throws în declaraţia metodei. Spre exemplu, se omite
throws la apariţia ArrayIndexOutOfBounds xceptions sau ArithmeticExceptions.
Este deja cunoscut un principiu de bază în programerea OO şi anume reutilizarea codului, motiv
pentru care la extinderea unui applet care foloseşte clase din pachetul [Link]. se au în vedere
metodele proprii apletului şi cele extinse ale claselor [Link], [Link],
[Link], etc. Clasa [Link] foloseşte culori încapsulate, declarând 13 culori
constante care pot fi nuanţate, specificând valori numerice din gama RGB (red,green,blue).
Appletul îşi poate seta fundalul şi primplanul prin setForeground() şi setBackground(), la fel
cum poate utiliza getForeground() şi getBackground() pentru a regăsi culorile de primplan şi
fundal. Cele 4 metode sunt moştenite din [Link]. Clasa [Link] foloseşte la
rândul ei fonturi încapsulate, declarând 3 constante pentru reprezentarea stilului de font
[Link], [Link] şi [Link], care pot fi folosite în combinaţie, iar appletul îşi poate
seta fontull prin setFont() şi poate declara fontul dorit prin getFont() [java_4], [Lema_96]
Exemplu:
import [Link];
public class TipFont extends [Link] {
String fontLista[ ];
public void init() {
fontLista=[Link]();
}
Deoarece s-au definit în paragrafele anterioare variante de înglobare a fişierelor grafice, imagini,
executabile din alte medii, este necesară structurarea lor în pachete şi clase pentru a asigura
accesul şi modificarea facilă, paralel cu reutilizarea codului pentru unele clase şi metode definite.
Recomandăm astfel ca appletul să aibă acces direct la directorul principal, creând astfel o
structură arborescentă, prezentată schematic în figura 4.1.:
82
Directorul
principal
Alte
clase
[Link] [Link]
Rădăcina structurii se denumeşte director principal (main) în care se plasează de obicei fişierele
HTML (opţional într-un subdirector al lui main şi un director numit classes (care poate fi opţional
o legătură simbolică cu directorul claselor centrale, oriunde în altă parte pe server).Toate
fişierele .class sunt memorate în acest director, sau în subdirectoare ale acestora, pentru a facilita
utilizarea pachetelor şi claselor în proiectele viitoare, referându-se şi extinzându-se ori de câte ori
este necesar.
In fişierele .HTML este necesară prezenţa atributului CODEBASE="classes" sau alte convenţii
corespunzătoare structurii de de directoare ( spre exemplu: CODEBASE="../classes"), calea
completă fiind specificată în [Link] şi fişierele audio sunt memorate în
subdirectoare distincte (figura 7)corespunzător directorului main şi pot avea legături opţionale.
Structura prezentată are avantajele organizării serverului, mentenabilităţii facile şi posibilităţii
reutilizării codului. In plus, dezvoltarea ulterioară a appletului pe o altă maşină sau un alt server,
nu implică reîncărcarea appleturilor completate şi a paginilor Web spre directoare potrivite
serverului deoarece toate legăturile funcţionează şi oferă portabilitate maximă de la o maşină la
alta. Pentru o aplicaţie complexă se recomandă crearea unui pachet propriu. Proiectarea acestui
pachet este realizată astfel încât să fie memorat în locul unde poate fi accesat pentru necesităţile de
utilizare. Unele pachete sunt create cu uz local, iar altele necesate pentru paginile Web, sunt create
în directoare de unde clientul le poate încărca.
La momentul la care sistemul java trebuie să încarce o clasă, caută pentru fiecare locaţie
specificată în CLASSPATH directorul în care numele este identic cu numele pachetului clasei.
Găsindu-l, utilizează numele pachetului pentru a reconstitui calea potrivită pentru fişierul .class, în
caz contrar, caută în locaţia specificată în CODEBASE, în care se află fişierele .class ale
[Link] mai simplă cale de a face pachetul disponibil clienţilor pentru execuţia appletului
este de a asigura acelaşi director pachetului şi appletului din care face parte.
Exemplu:
public class BandaSimplaextends toolBox ParamP implements Runnable{
int width;
83
int heigh;
Este deja cunoscut faptul că, la alocare dinamică a unui tablou Java, el nu are valoare. Dacă tabloul
este de tip obiect (opus tipurilor primitive) la instanţierea tabloului nu are loc şi alocarea memoriei
pentru obiectele comprimate în tablou. In fapt, instanţierea tabloului este realizată ca o colecţie de
manipulatori null.
Exemplu:
Se declară tabloul de imagini din clasa [Link]:
Image cadruAnim[ ];
Apare manipulatorul null denumit cadruAnim care nu are valoare şi nici dimensiune
cadruAnim
= null
= = = null
Figura 4.3. Tabloul de imagini instanţiat
cadruAnim
0 1 2 3 4 5 6
= = = null
84
Figura 4.4. Schema de alocare dinamică a cadrelor în tablouri
Java utilizează schema de alocare dinamică pentru toate obiectele care sunt alocate static, nu şi
pentru tipuri primitive (int, float, long, char). Pentru manipularea tablourilor de cadrelor în
animaţie se utilizează clasa abstract [Link] folosind:import [Link]. Cum nu
se poate instanţia direct un obiect din clasa abstractă, se subclasează şi apoi se instanţiază:
Image cadruAnim[ ] ;
Când se instanţiază un tablou de manipulatori ai clasei Image nu se vor instanţia niciodată
elementele individuale ale tabloului ci se apelează [Link]() care construieşte un
obiect independent de platformă, subclasă a lui [Link] şi întoarce manipulator al
acestui obiect. Deoarece obiectul este subclasă a lui [Link], este compatibil cu aceasta
şi poate fi astfel atribuit unui element de tablou.
85
4.1.3. Efectele speciale
Pîlpîirea sau vibraţia (flinker) este o metodă des utilizată în animaţie. La apelul metodei
repaint() sistemul invocă metoda update() a appletului, care este moştenită din clasa
[Link] iar codul sursă al versiunii implicite este:
Exemplu:
public void update(Graphics g){
[Link](getBackground());
[Link](0,0,width,height);
[Link](getForeground());
paint (g);
}
Metoda şterge porţiunea appletului pe ecran şi apoi apelează metoda paint(). Din acest
motiv, când se desenează o imagine, apare fundalul blank un timp scurt înainte ca imaginea să
fie desenată şi este parţial responsabil pentru vibraţiile (flinker) din animaţie.
Când se redesenează imaginea peste ea însuşi nu este nesară redesenarea fundalului de
fiecare dată, motiv pentru care se extinde metoda update care reduce pîlpîirea:
Exemplu:
public void update(Graphics g) {
paint (g);
}
Acest "truc" nu se aplică la desenarea textului în mişcare pentu că ştergerea fundalului este
necesară de această dată, permitând o afişare inteligibilă a informaţiei din text.
Whiteboard (hârtia albă) este reprezentarea analogică a contextului grafic, structura de
date pe care le utilizează sistemul şi interfeţele acestuia pentru a desena pe ecran. Utilizând
tehnica "double-buffering" se ţine invizibil contextul grafic din jur şi se desenează textul in
acest context. După finalizarea metodei paint() se face vizibil contextul grafic, ceea ce ai mai
puţin timp faţă de operaţiile actuale de desenare care au loc în spatele ecranului.
In GUI la nivelul cel mai înalt apar două tipuri de componente: componente de bază:
Canavas,Scroolbar, Button,Checkbox,etc şi conteinere sau componente ce conţin alte componente
ca şi Window şi subclasele Frame, Panel (cel mai familiară subclasă Applet) (figura 4.6.).
Containerele sunt subclasate în [Link] (figura 4.5.).
Este util de precizat că ierahia componentelor este diferită de ierarhia de clasă. Structura
ierarhiilor (figura 4.6.) nu are legătură cu moştenirea, de accea componentele ce aparţin
conteinerelor sunt cele cu săgeată ar cele reprezentate cu linie simplă sunt clauze extends.
Clasa [Link] (figura 4.5.) include metoda add() ce adaugă componente în
conteiner, utilizată la secţiunea Panel prin:
[Link](CheckboxPanel);
86
Pentru aşezarea pe ecran, AWT utilizează un obiect ce implementează interfaţa
LayoutManager, care controlează regulile prin care un Conteiner dat îşi va aşeza propriile
componente constituente. Se instanţiază un obiect din LayoutManager pentru fiecare Conteiner
creat, utilizând metoda conteinerului getLayout() pentru a specifica ceea ce utilizează
LayoutManager.[java_7]
[Link]
[Link] [Link]
[Link]
[Link]
[Link]
[Link]
Figura 4.5. Gruparea componentelor Java
Exemplu:
[Link](new BorderLayout());
87
Applet
Button
Checkbox Checkbox
FlowLayout
Cel mai simplu LayoutManager este FlowLayout care aranjează componentele în Conteiner de la
stânga la dreapta. Când se umple un rând, FlowLayout crează un nou rând, punând componentele
în aceeaşi ordine. Dacă nu se specifică LayoutManager pentru Panel sau Applet, este folosit
implicit.
BorderLayout
BorderLayout divide în 5 regiuni spaţiul alocat, aranjând componentele în Conteiner în regiunile
specificate (figura 4.7.).
North
South
88
CardLayout
Intr-un conteiner setat CardLayout, numai un component constituent este vizibil la un moment dat.
CardLayout furnizează metode first(), last(), next(), previous() şi show() pentru a selecta
componenta vizibilă. Tipic fiecare component adăugat în CardLayout va fi un Conteiner, ce
conţine alte componente. Acest mod este util pentru proiectarea ecranelor tabbed (tabulate) unde
fiecar ecran prezintă un set de controale legate în relaţie şi utilizatorul poate traversa ecranele în
ordine prin click pe un anume tip de control, de obicei simulând index tab la începutul
directoarelor de fişier.
GridLayout
Acest standard subdivide componentele într-un număr de linii şi coloane (specificate de
constructor). Componentele sunt plasate în celule divizate în ordinea adăugării lor.în Conteiner.
Celulele se extind sau se contractă cât este necesar pentru a se potrivi cu dimensiunea preferată de
componente.
GridBagLayout
Cea ma mare flexibilitate şi control al programatorului îl oferă "regina" LayoutManager-
GridBagLayout, deşi este cel mai complex de utilizat. La fel ca şi GridLayout se subdivide în
celule. Fiecare Component manipulat poate lua una sau mai multe celule, paote fi alungit pentru a
ocupa spaţiu mai mare relativ la alte componente şi poate dispune de o arie de aşezare ce permite
spaţiu liber între el şi alte componente. Pentru fiecare Component, GridBagLayout menţine o
instanţă a lui GridbagConstraints, care conţine constrângeri specifice, informaţii despre modul în
care va fi aşezat acest Component particular. Setarea acestor informaţii se face prin construcţia
unui obiect din clasa GridbagConstraints, setând câmpurile apropiate şi apoi trecând în metoda
setConstraints, pentu a referi componenta ce utilizează constrângerile setate.
Exemplu:
Gb= new GridBagLayout();
//referinta la gb apoi apelam metoda lui
c= new GridBagConstraints();
[Link](gb);
[Link]=20;
//lugime orizontala relativa 2
[Link](my Component, c);
[Link](myComponent);
[Link] este un program simplu de desenare, ce permite desenarea unui obiect de tip
Rectangle umplut sau nu cu o culoare. Prin acest exemplu se ilustrează diferenţa între desenarea
7
Detalii se află în API Documentation
89
bitmap şi cea OOP8 . Fiecare dreptunghi este vizibil utilizatorului ca un obiect, modelat ca atare şi
tratat ca o colecţie de biţi, fără a face distincţie între obiectele individuale ce compun imaginea.
Extinzând moştenirea, se poate desena orice obiect.[Ramb_96]
Exemplu:
import [Link];
import [Link].*;
import [Link];
// clasa ce extinde Rectangle
class DrawableRect extends Rectangle{
Color color=[Link];
Boolean filled=false;
//construcţia dreptunghiului
DrawableRect (int x, int y, int width, int heigh, Color, color, boolean filled) {
Super(x,y,width, heigh);
[Link]=Color;
[Link]=filled;
}
90
// intoarce starea grupului CheckBox
boolean isFilled(){
return [Link]==filledBox);
}
}
//colectia d edreptunghiuri
int numRects=0;
Vector rects= new Vector(100,10);
//numai pentru convenienta
DrawableRect currentRect;
// crează un dreptunghi desenabil si il adauga in lista
DrawableRect addRect ( int x,int y ; int width, int height){
DrawableRect r = new DrawableRect (x,y,width;height, rectColor, filled);
[Link] ( r );
NumRects++;
return r;
}
91
//raspuns la eveniment mouseDrawn
//apelat de handleEvent mostenit
public boolean mouseDown (Event evt, int x, int y) {
//seteaza punct mouse down
orig_x=x;
orig_y=y;
//incepe un nou dreptunghi
current Rect=addRect(orig_x+offset_x,orig_y+offset_y,0,0);
return true;
}
92
}
public GUIExample extends Applet {
//varful paletei si sub-itemii ei
//selectia culorilor
[Link]("Black");
[Link]("Blue");
[Link]("Red");
[Link]("Green");
[Link]("Yelow");
[Link]("Cyan");
[Link]("Black");
// mijlocul Panel
[Link](new BorderLayout ( r )) ;
93
//setarea la mijlocul paletei a RectCanavas
[Link]([Link]());
[Link](getSelectedColor());
[Link]([Link]);
//adaugarea tuturor itemilor la mijlocul paletei
[Link]("South", x_scroll);
[Link]("Est", y_scroll);
[Link]("Center", rCanavas);
//sfarsitul paletei
[Link](clearButton);
//suprascrie [Link]()
public boolean handleEvent(Event evt){
if ([Link]==colorChoice){
[Link](getSelectedColor());
}else { if ([Link] instance of Checkbox){
[Link]([Link]());
94
//[Link] tin valorile cu care bara este deplasata
rCanavas.offset_x=((Integer)[Link]).intValue();
break;
}
else if ([Link]==y_scroll){
switch (evt_id) {
case Event.SCROLL_LINE_UP:
case Event.SCROLL_LINE_DOWN:
case Event.SCROLL_PAGE_UP:
case Event.SCROLL_PAGE_DOWN:
case Event.SCROLL_ABSOLUTE:
//suprascrie [Link]()
//apelata la redimensionarea appletului
public void reshape(int x, int y, int width, int height){
[Link](x,y,width,height);
[Link]();
}
}
Explicaţia codului
95
Exemplul de mai sus are 4 clase, una dintre ele fiind chiar appletul GUIExample.
DrawableRectangle este o extensie a lui [Link] deoarece [Link] are rol de
a modela o cutie dreptunghiulară în general, iar obiectul appletului este modelarea unei clase de
dreptunghiri care să se deseneze şi în care să se poată include starea informaţiilor despre umplerea
dreptunghiurilor şi culoarea de umplere.
Celelalte 2 clase sunt extensii ale [Link] din categoria widgets9 şi anume
RectCanavas este o colecţie de DrawableRectangles iar CheckBoxPanel dă un mod convenabil de
încapsulare a grupului de elemente Checkbox Group.
Un mare avantaj al funcţionalităţii appletului le dau widgets utilizate şi subclasate în (scrollbar,
buttons, checkbox, etc) avantaje ale OoP demonstrate prin proiectarea GUI.
OOP permite "mascarea" acestor widgets în ierarhii de clasă şi prezintă o interfaţă simplă şi relativ
abstractă a acestora. API reduce complexitatea dezvoltării programelor şi furnizează abstractizarea
necesară.
Componenta Checkbox Grup are capacitatea de a grupa în ea, folosind selecţii mutual exclusive de
Checkbox. Checkbox însuşi răspunde imediat la mouse-click selectându-se grafic pe el însuşi, şi
dacă programatorul a alocat un grup pentru el, deselectează celelalte checkbox din grup10 .
Elementul Choice automat oferă meniul de selecţie iar odată selectată opţiunea se poate transporta
cu metoda getSelectedChoice(). In aceste componente nu trebuie să răspundem de evenimentul
mouse-click pentru că este proiectată metoda handleEvent() în fiecare. In general, componentele
ce răspund în mod normal la evenimente mouse-click sau alte evenimente de la tastatură,
suprascriu handleEvent() şi gestionează click-mouse, generând alte evenimente, d eobicei de tip
ACTION_EVENT.
Când apare un eveniment, sistemul crează un obiect din clasa [Link], determinat de
componentă şi acesta ia evenimentul apelat de metoda handleEvent() a componentei, trecând
obiectul Event ca [Link] manipularea evenimentelor trebuie să se ţină cont de iararhia
componentelro. Spre exemplu, ce se întâmplă dacă apare evenimentul mouse-click pe Canavas,
conţinut d ePanel, conţinut la rândul lui de Applet? Sistemul respectă următoarea regulă; începe cu
cel mai mic component din ierarhie şi îl tratează urmâd ca apoi să examineze alte evenimente din
ierarhie. Ierarhia de componente este cea stabilită de Components (figura 4.6.) şi Conteir-ele lor şi
nu este ierarhia moş[Link]ă handleEvent() a componentei întoarce true, însemnă că
evenimentul este manipulat de acel component şi nu se întreprinde nici o acţiune. Dacă returnează
true, sistemul apelează metoda handleEvent() a următorului component din ierarhie:conteinerul
componentului. Evenimentul continuă să se propage în sus pe ierarhie, până câd un component
întoarce true din handleEvent() sau nu au rămas componente cărora să le aparţină evenimentul.
Unele componente ca şi Checkbox, Button, Choice, ce nu au nivel cert al funcţionalităţii
moştenite, răspund la evenimente, generând evenimente adiţionale, cel mai frecvent
Event.ACTION_EVENT. Barele de defilare generează variate tipuri de evenimente. Listele de
selecţie generează Event.LIST_SELECT şi Event.LIST_DESELECT în plus faţă de
Event.ACTION_EVENT.
[Link]()
9
putem asimila widgets ca elemente grafice prefabricate
10
respectând selecţii mutual exclusive
96
Câteva tipuri de evenimete ca şi Event.MOUSE_DOWN, Event.MOUSE_DRAG şi
Event.ACTION_EVENT sunt manipulate de [Link]() ce răspunde de
ele, apelând mouseDown(), mouseDrag() şi action(). In componentele generice (în particular
Applet, Panel şi Canavas) aceste metode sunt void. Dacă se doreşte ca un component să răspundă
într-un anume mod la aceste evenimente, se vor subclasa şi prin simpla suprascriere a metodelor
mouseDown(), mouseDrag() şi action() se va adăuga acţiunea dorită. Versiunea implicită a lui
handleEvent() nu răspunde la toate tipurile de Event definite în [Link]. Dacă este necesar
un răspuns la evenimente ce n-au fost prinse în handleEvent(), implicit se suprascrie handleEvent()
ca şi clasa applet . Se poate utiliza o versiune proprie a lui handleEvent() , care răspunde la aceste
tipuri de evenimente şi care nu sunt prinse în versiunea implicită. Odată terminată verificarea
acestora, se apelează [Link], pentru a lăsa versiunea implicită să manipuleze
evenimente ce sunt deja programate pentru a fi manipulate ca şi ACTION_EVENT.
Codul [Link]()11 este:
public boolean handleEvent(Event evt){
switch (evt.id0 {
case Event.MOUSE_ENTER:
return mouseEnter(evt, evt.x,evt.y);
case Event.MOUSE_EXIT:
return mouseExit(evt, evt.x,evt.y);
case Event.MOUSE_MOVE:
return mouseMove(evt, evt.x,evt.y);
case Event.MOUSE_DOWN:
return mouseDown(evt, evt.x,evt.y);
case Event.MOUSE_DRAG:
return mouseDrag(evt, evt.x,evt.y);
case Event.MOUSE_UP:
return mouseUp(evt, evt.x,evt.y);
case Event.KEY_PRESS:
case Event.KEY_ACTION:
return keyDown(evt, [Link]);
case Event.KEY_RELEASE:
return keyUp(evt, [Link]);
case Event.ACTION_EVENT:
return keyDown(evt, [Link]);
case Event.GOT_FOCUS:
return gotFocus(evt, [Link]);
case Event.LOST_FOCUS:
return lostFocus(evt, [Link]);
}
return false;
}
Obiectul Event are o serie de câmpuri dar facem referire doar la cele mai importante folosite în
programare:
• id - conţinut de tipul Event ca şi Event.ACTION_EVENT sau Event.MOUSE_DOWN;
• target - conţinând widgets ce generează evenimetul;
11
[java_4] Java Soft INC., Java Advanced API Specification, [Link]
97
• when- caracteristica de timp indicată când evenimentul apare (utilizat numai pentru mouse şi
tastatură);
• x,y, coordonatele evenimentului (utilizat numai pentru mouse şi tastatură şi
WINDOW_MOVED);
• key -cod ASCII pentru cheia apăsată în evenimentul de la tastatură;
• modificatori- indicaţii asupra cheilor (SHIFT,CTRL) care sunt jos când evenimentul keyboard
sau mouse apare. Ele nu sunt utilizate la MOUSE_ENTER sau MOUSE_EXIT. Cheile
modificatoare nu generează ele însele evenimente. Fiecare este reprezentată de un set de biti
neacoperibili astfel încât se pot utiliza constante mască furnizate de clasa Event, pentru a
determina câd un modificator dat a fost jos în timpul evenimentului de la tastatură sau mouse.
• arg conţin un Object ce variază pentru tipurile particulare de evenimente. Pentru
ACTION_EVENT este String cu eticheta elementului selectat, generat când Button este apăsat
sau Choice, Checkbox sau MenuItem sunt selectate, ListItem sau double-click sau utilizatorul
apasă cheia Return din textField. Pentru evenimente din Scrollbar, fiecare dintre acestea conţine
un int ce indică poziţia cu care Scrollbar a fost mutată. In final, când utilizatorul dă single-click în
List, se generează unul din evenimentele LIST_SELECT sau LIST_DESELECTpentru acre
câmpul arg este int şi indică aloare indexului elementului pe care s-a acţionat click.[java_5]
Pentru a redimensiona componentele apelăm la metoda supascrisă a lui
[Link]() deoarece appletul conţine Scroolbar şi sunt necesare modificări
de dimensiune pentru a asigura dimensiuni "vizibile" în conţinutul virtual dat de Canavas. In cazul
în care se suprascrie reshape(0 se apelează apoi [Link]() dat fiind faptul că metoda
implicită face o serie de reamenajări care în cazul în care nu sunt realizate, conduc la apariţia unor
efecte nedorite pe ecran.
Orice animaţie are ca obiective specifice în realizarea acestor "filme" sau secvenţe animate,
care pot constitui parametri utilizator în funcţie de care se realizează diferite variante de "film" 12.
Acestea presupun:[java_7]
• specificarea ordinii cadrelor în scopul reutilizării lor;
• specificarea punctului de unde se repetă animaţia;
• specificarea soundtrack-ului;
• specificarea sunetelor ce pot fi dispuse în cadre individuale;
• specificarea cuantei de timp pentru pauza dintre cadre (atât pentru întreaga animaţie cât şi
pentru cadrele individuale);
• specificarea unei imagini de început afişată la momentul încărcării;
• specificarea background-ului de imagine peste care se afişează animaţia propriu-zisă;
• specificarea poziţiei de la care se afişează fiecare cadru13.
Animaţia simplă presupune afişarea unei imagini statice (cadru) la un moment dat, într-o buclă
şi ideea centrală este de a afişa un cadru de secvenţe, făcând transfer de la cadru la cadru, atât de
repede încât percepţia naturală este realizată ca întreg, simulând o imagine în mişcare14
12
Pentru detalii consultaţi site-ul java@[Link]
13
Conform Herb Jellinek | jellinek@[Link]
14
durata cu care se schimbă cadrele este egală cu durata persistenţei imaginii pe retina ochiului
98
Respectând principiile de proiectare a directoarelor anterior expuse, cadrele se înmagazinează
într-un director de imagini iar appleturile şi fişierele HTMl au în general direcor comun sau două
subdirectoare de acelaşi nivel.
//desenul
public void paint(Graphics g){
[Link] ('desenarea ");
[Link](x_coord, y_coord,5);
}
public void stop(){
// definim metoda stop
[Link] ('oprirea appletului");
}
public void destroy(){
// definim metoda destroy
[Link] ('distrugerea appletului");
}
}
Codul fişierului HTML conţine:
99
<applet code=[Link] width=450, height=450>
</applet>
Observaţie: Dacă se rulează cu Netscape, se setează Show Java Console care permite afişarea
mesajelor.
Rularea appletului:
Este deja cunoscut faptul că utilizarea opţiunii Reload din Netscape reîncarcă pagina ce conţine
appletul, dar browserul nu încarcă appletul în sine. Dacă se doreşte cel mai recent vizitat applet, cu
comportamentele noi ale acestuia, se selectează Network Preferences din meniul Options ştergând
disk cache astfel încât sistemul utilizează memoria cache. Când appletul se încarcă se va afişa cea
mai recentă versiune a lui.
Pentru a exemplifica acţiunile specifice ciclului de viaţă se recomandă următoarele experimente:
Se lasă pagina şi apoi se reîntoarce la ea;
Se încearcă minimizarea ferestrei browser;
Se readuce fereastra la dimensiune normală;
Se mută fereastra consolei in faţa appletului pentru a-l umbri;
Se readuce fereastra appletului în primplan şi se defilează prin applet.
Cele trei instrucţiuni importă clasele Graphics, Color şi Applet care nu devin parte integrată a
codului appletului şi nu afectează dimensiunea [Link]ă import ele se referă conform
convenţiei sintactice:
public class Desen extends Applet {
Fiecare applet este o nouă clasă ce extinde clasa Applet şi moşteneşte variabilele şi metodele din
[Link]. Desen este clasă declarată public pentru că se utilizează de o aplicaţie din
exterior iar în caz contrar browserul nu poate avea acces la Desen şi nu il poate rula.
Cele două declaraţii de tablou:
int x_coord[ ]={120,250,50,230,70,170};
int y_coord[ ]={20,250,150,130,170,20};
permit alocarea spaţiului automat.
In momentul apelului [Link]() se afişează un mesaj şi apoi se apelează cele două metode
moştenite din [Link] ([Link] şi [Link]) care sunt variabile [Link] final
redimensionează appletul la (400,400). La Netscape se remarcă un scurt flash de la dimensiunea
din HTML (450,450) la cea a appletului. Toate metodele sunt publice pentru a avea acelaşi tip de
acces cu clasa din care fac parte. Dacă se doreşte în jurul appletului se poate completa cu text.
Spre deosebire de appletviewer, în Netscape pagina rămâne statică iar resize() nu are efect. La
apelul resize() (redesenare) se specifică aria pe care appletul o recunoaşte ca proprie iar la
redesenare se actualizează doar aria respectivă. Acest lucru este des utilizat în animaţie pentru a
optimiza zona efectiv actualizată.[java_5]
Browserul trece metoda paint() unui obiect din clasa Graphics. Obiectul însuşi este referit în
context grafic, creat, menţinut şi posedat de sistem. După ce anunţă consola că paint() este apelat,
metoda trimite mesaj către obiectul Graphics, cerându-I să execute drawPolygon(), metodă din
[Link] care ia 3 parametri: (x,y) din zonă şi numărul de laturi-n. Poligonul poate fi
(0,0) y
închis (când n=numărul de laturi, sau deschis n> numărul de laturi). In Java, originea sistemului de
coordonate este stânga-sus şi coordonatele cresc în jos pe ecran (figura 3.2.).
100
x (120,150)
Figura 3.2. Coordonatele grafice în Java
Prezentăm un exemplu imperfect dat de o buclă infinită ce redă controlul CPU. Appletul are rolul
de a demonstra ce se întâmplă când un applet animat nu-şi crează un fir propriu independent
pentru a rula animaţia. Executat pe sistem multitasking la sfârşit se poate forţa terminarea
appletului.[java_6]
Exemplu:
import [Link];
import [Link];
import [Link];
101
String msg; // mesaj defilant
int x, y // coordonatele desenului
int orizPas;//dimensiune pas în pixeli
int pause;// numar de iteratii in bucla pauza
int msgWidth; dimesiunea mesajului în font curent
Rularea appletului
Metoda [Link]() trimite un mesaj către obiectul grafic g, contextul grafic îl trece ca parametru
lui paint(), comunicând şi setul de culori al "peniţei" pentru a umple sau desena figuri geometrice
102
sau şiruri. Prin apelul lui [Link](getBackground()) se ia fundalul curent. Dacă se utilizează un
dreptunghi pentru fundal, acesta umple zona appletului, ştregând aria pe ecran. Se setează culoarea
de primplan a appletului pentru a putea desena mesajul pe ecran. Metoda size() moştenită din
[Link] dă înălţimea şi lăţimea appletului şi întoarce un obiect de tip
[Link] (clasă care conţie 2 variabile width şi height). Aceşti 2 membri ai obiectului
pot fi accesaţi direct, fără a declara un obiect din clasa Dimension. Dacă se intenţionează
utilizarea succesivă a variabilelor width şi height, este de preferat memorarea lor într-un obiect,
pentru a nu permite apelurile redundante ale lui size(). Datorită faptului că dimensiunea appletului
se schimbă, cel mai simplu mod de a garanta valoarea recentă este de a apela size() direct. In
exemplu se foloseşte o metodă atipică de a plasa bucla de animaţie loop în interiorul metodei
paint(). In plus, fundalul se redesenează de fiecare dată când se redesenează şirul dar utilizând
update() se poate desena numai fundalul. Obiectul FontMetrics este util pentru a calcula lingimea
şirului din mesaj, dat fiind faptul că multe fonturi sunt proporţionale, înafară de monospaţii şi este
de dorit ca fonturile să fie cât mai aspectuase deşi sunt dependente de sistemele pe care se rulează
appletul.[java_7]
103