Java
Java
"Petru Maior"
Teorie
1. Introducere. Dezvoltarea aplicatiilor in stil OO. Limbajul Java.
2. Conceptele programarii orientate obiect.
3. Modelare cu obiecte
4. Vizibilitatea membrilor clasei si protectia acestora
5. Crearea interfetelor grafice.Pachetul java.awt.
6. Fire de executie
7. Tratarea evenimentelor
8. Facilitati de I/E. Streamuri.
9. Programare in retea. Socluri.
10. Accesul bazelor de date din Java. JDBC.
11. Java Webserver si servleturi.
12. Apleturi
13. Pachetul swing
14. Clase de baza
15. Serializare
16. Mecanismul de reflectie
17. Mecanismul de securitate
18. Programarea distribuita
19. Internationalizare
20. Colectii
Introducere
1. Limbaje orientate obiect - Dezvoltarea aplicatiilor in stil OO
2. Limbajul Java
2.1. Generalitati
2.1.1. Caracteristici
2.1.2. Scrierea aplicatiilor Java
2.1.3. Pachete Java
2.2. Elementele limbajului
2.2.1. Variablie
2.2.1.1. Tipuri primitive
2.2.1.2. Tipul referinta
2.2.1.3. Tablouri
2.2.1.3.1. Alocarea memoriei pentru tablouri
2.2.1.3.2. Lungimea tablourilor
2.2.1.3.3. Initializarea tablourilor
2.2.1.3.4. Eliberarea memoriei alocate dinamic
2.2.2. Expresii
2.2.3. Exceptii
2.2.3.1. Exceptii si tratarea acestora
2.2.3.2. Aruncarea exceptiilor
2.2.3.3. Aspecte legate de performanta utilizarii exceptiilor
2.3. Tipuri de programe Java
1. Limbaje OO
Limbaj
Dezvoltare
Anul de
aparitie
C++
inceputul
anilor 1980
Java
inceputul
anilor 1990
inceputul
anilor 1970
inceputul
anilor 1980
Bertrand Meyer
Pascal
1986
Variante
Borland C++; Microsoft C++; Watcom
C++;
GNU C++
Sun JDK; Symantec Visual Cafe;
Microsoft Visual Java; Borland JBuilder
Smalltalk V.; Smalltalk-80; IBM
Smalltalk
analiza
proiectarea
implementarea
testarea.
Dupa aceea apare si o faza de intretinere a produsului, prin care se intelege corectarea
unor mici erori care apar cu timpul si adaugarea de noi facilitati (mai mici)
produsului. Cateodata la produse neproiectate in mod corespunzator faza de
intretinere poate fi mai costisitoare decat faza realizarii produsului. De aceea este
foarte important ca aplicatia sa fie proiectata modular astfel incat modulele
independente sa se poata intretine si separat.
Analiza: Este facuta de catre un analist, care colaborand cu beneficiarul produsului
identifica obiectele principale ale aplicatiei. De exemplu in cazul unui sistem
informatic pentru banci, obiectele principale ar fi: Client, Factura, Tranzactie,
Angajat_Bancar etc. Rezultatul acestei faze se va concretiza intr-un model realizat de
catre analist. In aceasta faza se determina CE trebuie facut, dar nu si CUM trebuie
facut. Detaliile de implementare apartin altor faze. Se vor identifica subsistemele
principale ale produsului si se va realiza un dictionar de date continand descrierea
principalelor obiecte. In ultima faza a analizei se identifica resursele necesare pentru
sistem (hardver si software).
Proiectarea: Sarcina acestei faze este de a detalia modelul obiect rezultat din faza de
analiza. Proiectantul va determina sarcina exacta a obiectelor si structurile de date
respectiv algoritmii necesari pentru faza de implementare. Tot in aceasta faza se
construiesc diagrame de clase si de obiecte precum si diagrame de colaborare intre
obiecte.
Implementare, testare: Se implementeaza clasele pe baza diagramelor de clase. Daca
proiectul este bine pus la punct atunci munca din aceasta faza este doar munca de
rutina. Tot in acesta faza se incearca utilizarea componentelor gata facute astfel
reutilizand codul existent. Prima data se testeaza componente mai mici, dupa aceea
modulele si in ultima faza se testeaza produsul intreg.
Metode si instrumente de dezvoltare
Metode:
In faza de proiectare a produsului ( si nu numai in aceasta ) ne ajuta produsele CASE
(Computer Aided Systems Engineering ). Unele dintre aceste produse CASE stiu sa
genereze si cod intr-un anumit limbaj sau in mai multe limbaje.
OMT (Object Modeling Technique) 1991, James Rumbaugh
Metoda Booch, 1991, Grady Booch
OOSE (Object Oriented Systems Engineering) 1992, Ivar Jacobson
UML (Unified Modeling Language ) 1997, Rational Corporation, Santa Clara
California. Grady Booch, James Rumbaugh, Ivar Jacobson
UML este un standard, versiunile se gasesc la adresa http://www.rational.rose
Instrumente:
Denumire
Rational Rose (Rational Corporation)
OMTolol (General Electric Research and
Development Center )
Objectory (Objective Systems)
With Class (MicroGold Software Inc. )
Metode
OMT, Booch,
OOSE, UML
Generare cod
C++, Smalltalk, Visual Basic,
Java, Modula
OMT
C++
OOSE
OMT, Booch,
OOSE, UML
2. Limbajul Java
Limbajul Java are radacinile in C. Java este asemanator cu C++, dar este mai flexibil,
mai portabil si mai simplu de invatat. Parintele limbajului a fost James Gosling,
autorul celebrului editor de text emacs. Java incearca sa ramana un limbaj simplu, s-a
preluat partea buna a limbajului C++ si au fost eliminate partile derutante cum ar fi
supraincarcarea operatorilor si mostenirea multipla. Limbajul este independent de
arhitectura calculatorului pe care lucreaza (portabil). Nu genereaza cod nativ pentru o
platforma sau alta ci genereaza o secventa de instructiuni pentru o masina virtuala,
numita si Masina Virtuala Java (JVM). Aplicatiile Java vor fi interpretate. Deci Java
este un limbaj compilat si interpretat. Dezavantajul principal al limbajelor interpretate
este viteza de executie.
2.1.1. Caracteristici:
orientat obiect
Faza de compilare:
javac Aplicatie.java
-------> Aplicatie.class
Faza de interpretare:
java Aplicatie argument1 argument2 argument3 ...
date si cod. Clasele sunt incarcate in mod dinamic de catre o aplicatie Java. Ele sunt
incarcate in momentul in care sunt efectiv utilizate. Java contine si cateva clase
fundamentale care contin metode dependente de arhitectura. Aceste metode native
sunt implementate intr-un limbaj nativ platformei si permit accesul la sistemul de
fisiere, sistemul de ferestre si retea. Restul limbajului este scris in Java si este portabil.
Aici sunt incluse aplicatiile ca: compilatorul Java, browserul HotJava de la Sun etc.
2.1.3. Pachete Java
Pachetele Java sunt grupe formate din clase si interfete Java. Principalele pachete sunt:
Toate variabilelel Java sunt initializate. Fiecare tip are o valoare implicita cu care se
initializeaza variabilele de tipul respectiv.
Declaratie: tip nume_variabila [ = expresie ];
Tipul boolean are ca valori true si false. Variabilele boolean neinitializate explicit vor
avea valorarea implicita false.
Tipul caracter are ca valori coduri UNICODE reprezentate pe doi octeti, astfel
permitand reprezentarea tuturor caracterelor limbilor existente. Valoarea implicita este
caracterul null cu codul '\u0000'.
Tipul byte este un tip intreg cu semn avand valorile intre -128 ..127. Valoarea
implicita pentru variabilele de tip intreg este 0. Celelalte tipuri intregi sunt
reprezentate pe 16, 32 respectiv 64 biti.
Tipurile flotante sunt reprezentate pe 32 de biti, respectiv 64 de biti. Valoarea
implicita pentru variabilele flotante este 0.0f.
Reali speciali definiti de standardul IEEE
NaN - Not a Number. Este rezultatul unei impartiri cu 0. Ex. 0.0/0.0
Clasa java.lang.Float defineste aceasta constanta precum si altele cum ar
fi: POSITIVE_INFINITY, NEGATIVE_INFINITY
2.2.1.2. Tipul referinta
In C standard se pot defini tipuri noi, complexe cu ajutorul structurilor. In Java sau
alte limbaje OO se utilizeaza clase in locul structurilor. Clasa defineste un tip nou.
Referinta este similara cu notiunea de pointer din C cu exceptia ca referinta este un
pointer sigur ("safe-pointer"). Referinta este un fel de alias, un alt nume pentru un
obiect. Se utilizeaza in definitia claselor pentru a referi un obiect din interiorul unui alt
obiect.
Exemplu:
String s1 = "Un sir"; // Se aloca memorie pentru referinta s1 si pentru sirul constant
"Un sir". Se initializeaza referinta s1 cu adresa sirului constant
String s2 = s1; // Se aloca memorie pentru referinta s2 care este initializat
cu referinta s1
Tablourile sunt referinte speciale. Numele tabloului este o referinta cu ajutorul careia
ne putem referi la elementele tabloului.
Exemplu de referinta la un tablou de intregi:
int ti[];
In Java tablourile sunt alocate dinamic, ele isi pot schimba dimensiunile pe parcurul
executiei. Practic la alocarea unui tablou se creaza un nou obiect instantiat dintr-o
clasa ce permite stocarea a mai multor elemente de acelasi tip. Astfel avem la
dispozitie variabila de clasa length ce ne furnizeaza lungimea tabloului. Pentru
exemplul precedent obtinem urmatoarele valori:
int dim_ti = ti.length; // se va obtine 5
int dim_ti_0 = ti[0].length; // se va obtine 2
int dim_ti_1 = ti[1].length; // se va obtine 3
Varianta 1. Se initializeaza un tablou cu doua linii, fiecare linie avand acelasi numar
de elemente.
int t[][] = new int[2][3];
int i,j;
for( i =0; i<t.length; i++)
{
for( j=0; j<t[i].length; j++){
t[i][j] = i*3+j;
System.out.print(t[i][j]);
System.out.print(" ");
}
System.out.println();
}
Rezultatul executiei:
0 1 2
3 4 5
2.2.2. Expresii
Expresia are un tip si o valoare. Valoarea se obtine prin evaluarea expresiei. Tipul
expresiei se cunoaste inca din faza de compilare. Valoarea expresiei poate fi de un
anumit tip primitiv (rezultatul unei expresii numerice 20+3-6) sau poate fi o referinta (
new OClasa() ) sau poate fi tipul void, ca rezultatul unei metode (functii) ce
returneaza acest tip.
Operatori - Diferente fata de C standard
Java nu suporta operatorii de adresare directa & si cel de adresare indirecta *.
Operatorul de secventiere "," nu este suportat de Java. Nici sizeof nu este suportat.
In schimb avem operatori noi cum ar fiinstanceofsi operatorul + se poate utiliza si la
obiecte de tip String.
String s1 = new String("Un sir de caractere");
String s2 = "Un alt sir de caractere";
boolean b1= (s1 instanceof String);// true
b1 = ( s2 instanceof Object);// true
b1 = ( s1 instanceof Integer );// false
Toate clasele deriva din clasa Object. Aceasta este superclasa tuturor claselor Java.
Operatorul instanceof verifica daca un obiect apartine unei clase. Orice obiect din
subclasa unei clase apartine si superclasei. (Clasa String este subclasa clasei Object,
1.1.1. Exception
1.1.1.1. ClassNotFoundException
1.1.1.2. CloneNotSupportedException
1.1.1.3. IllegalAccessException
1.1.1.4. InstantiationException
1.1.1.5. InterruptedException
1.1.1.6. NoSuchMethodException
1.1.1.7. RuntimeException
1.1.1.7.1. ArithmeticException
1.1.1.7.2. ArrayStoreException
1.1.1.7.3. ClassCastException
1.1.1.7.4. IllegalArgumentException
1.1.1.7.4.1. IllegalThreadStateException
1.1.1.7.4.2. NumberFormatException
1.1.1.7.5. IllegalMonitorStateException
1.1.1.7.6. IllegalStateException
1.1.1.7.7. IndexOutOfBoundsException
1.1.1.7.7.1. ArrayIndexOutOfBoundsException
1.1.1.7.7.2. StringIndexOutOfBoundsException
1.1.1.7.8. NegativeArraySizeException
1.1.1.7.9. NullPointerException
1.1.1.7.10. SecurityException
java.lang.Error
1. Object
1.1. Throwable
1.1.1 Error
1.1.1.1. LinkageError
1.1.1.1.1. ClassCircularityError
1.1.1.1.2. ClassFormatError
1.1.1.1.3. ExceptionInitializerError
1.1.1.1.4. IncompatibleClassChangeError
1.1.1.1.4.1. AbstractMethodError
1.1.1.1.4.2. IllegalAccessError
1.1.1.1.4.3. InstantiationError
1.1.1.1.4.4. NoSuchFieldError
1.1.1.1.4.5. NoSuchMethodError
1.1.1.1.5. NoClassDefFoundError
1.1.1.1.6. UnsatisfiedLinkError
1.1.1.1.7. VerifyError
1.1.1.2. ThreadDeath
1.1.1.3. VirtulaMachineError
Sintaxa instructiunii:
try{
//bloc de instructiuni care pot cauza exceptii
}
catch( TipExceptie1 obiect1 ){
// codul de tratare a exceptiei TipExceptie1
}
catch( TipExceptie2 obiect2 ){
// codul de tratare a exceptiei TipExceptie2
}
finally{
//bloc de instructiuni care se executa intotdeauna
}
Exemplu:
2.java fin 4
5
Daca exceptia generata nu este prinsa de catre program atunci aceasta va fi prinsa de
catre mediul de executie Java care de obicei suspenda executia programului afisand
exceptia din cauza caruia s-a oprit programul. Daca se trateaza exceptia atunci
controlul executiei programului se transfera la codul de tratare dupa care daca exista
si clauza finally se executa instructiunile de aici, dupa care se continua cu prima
instructiune de dupa blocul try-catch-finally. Daca intr-un bloc try avem mai multe
clauze catch atunci se va cauta secvential intre aceste clauze si numai primul potrivit
va fi executat.
Exemplu:
try{
//cod sursa exceptie de tip IOException
}
catch( Exception e1 ){
// cod de tratare 1
}
catch( IOException e1 ){
// cod de tratare 2
}
fara a crea o clasa noua de exceptii: prin constructia throw new Exception("S-a
intamplat ceva rau"); Se creaza un obiect de tip Exception si controlul se
transfera blocului de tratate a exceptiei cel mai apropiat.
prin extinderea clasei Exception
class MyException extends Exception{
MyException(){
super(); // Apel constructor superclasa
}
MyException( String text ){
super( text ); // Apel constructor superclasa
}
}
Utilizarea exceptiei:
try{
// operatii ce pot genera MyException
}
catch( MyException e ){
// tratare
}
catch( IOException e ){
//cod de tratare
}
Exemplu de aplicatie Java: Un program care isi afiseaza argumentele primite la linia
de comanda
public class OAplicatie{
public static void main( String args[] ){
int i;
for( i=0; i<args.length; i++)
System.out.println(args[i]);
}
}
Caracterizarea obiectului
Starea obiectului
Identificarea obiectului
Clasa, instanta
Starile unui obiect
Proprietatea de incapsulare;Ascunderea informatiei
Exemplu: Stiva deintregi
1. Caracterizarea obiectului
Obiect=Date+Cod
Metodele de fapt sunt rutine care lucreaza cu datele obiectului. Siacum sa consideram
obiectul Om. Un om poate fi caracterizat de nume, dedata nasterii, de inaltime, adresa.
Sunt si alte caracteristici ale omului,dar pentru a rezolva problema noastra e de ajuns
sa le consideram doarpe acestea. Acum discutam cateva metode prin care se manifesta
obiectul nostru. De exemplu oamenii se muta din cand in cand. Odata cu mutarea seva
schimba si adresa omului. Omul poate sa creasca in inaltime pana lao anumita varsta.
Deci obiectul om poate fi caracterizat prin:
2. Starea obiectului
Este formata din valorile actuale ale datelor. Dupa apelul anumitor metode (ale celor
care modifica campurile de date) starea obiectului se poatemodifica. Doua obiecte se
afla in aceeasi stare daca valorile campurilorde date coincid.
Exemplu:
Om Om("Ioan",32) si
3. Identificarea obiectului
Doua obiecte pot fi in aceeasi stare, dar ele nu pot fi identice, deoarece adresa lor in
memorie difera. Obiectele sunt identificate prin referinte. Doua referinte pot referi
acelasi obiect.
Exemple:
String s1 ="Un sir de caractere";
String s2 = s1;
// Doua referinte la un singur obiect
Om o1 = new Om("Pop Ioan",1960,182,"Tg-Mures");
Om o2 = o1;
Obiectul "Un sir de caractere" exista intr-un singur exemplar si avemdoua referinte s1
si s2 prin care obiectul poate fi accesat.
4. Clasa, instanta
Clasa unui obiect este un tip de data pe baza caruia se pot crea instante din clasa
respectiva. Aceste instante sunt obiecte.
Daca doua obiecte sunt in aceaasi stare atunci la aceaasi cerere reactioneaza la fel.
Cererile se realizeaza prin trimiterea anumitor mesaje obiectului. Mesajele au forma
urmatoare:
referinta_obiect.nume_metoda()
Pentru fiecare obiect se aloca memorie pentru datele obiectului, darmetodele sunt
utilizeaza in comun de catre diferite instante.
Un obiect poate sa ceara de la un alt obiect realizarea unei sarcini.Mesajele sunt de
fapt apeluri de metode publice ale claselor. Metodelepublice sunt metode accesibile de
catre celelalte obiecte. Un obiect poatesa contina si metode private, metode care nu
sunt accesibile din afara.In cazul clasei Fereastra metodele afiseaza() si sterge()
trebuie sa fiemetode publice, iar daca am dori desenarea unui chenar in jurul
ferestreiaceasta am putea-o defini ca o metoda privata.
Obiectele comunica prin mesaje si rolurile sunt distribuite in modulurmator:
client: cel care cere realizarea unei sarcini ( cel care trimitemesajul )
server: cel care executa sarcina (cel care receptioneaza mesajul)
Acelasi obiect poate fi odata client, iar dupa aceea server. Existatotusi obiecte tipice
client cum ar fi obiectele de tip control si obiectetipice server, obiecte de tip baza de
date. In literatura de specialitateputem sa intalnim si denumirile:
ACTOR: care cere numai
AGENT: care cere si executa
Mesajele au rolul de a activa obiecte si realizeaza schimb de informatieintre
obiecte. Raspunsul la un anumit mesaj se obtine prin valoareareturnata de catre
metoda sau prin parametrii transmisi ca referint
Pentru fiecare clasa utilizata in aplicatia noastra se creaza un obiectde
tip Class(java.lang.Class) care tine evidenta obiectelor instantiate din clasele
respective. Un obiect poate sa spuna din ce clasa este instantiata. Exemplu:
String s="Un sir de caractere";
Class c=s.getClass();
//getClass() - Returneazaun obiect de tip Class
System.out.println( c.getName()); //getName() - Returneaza un obiectde tip
String
Aceasta metoda este apelata de runtime system inainte ca memoria alocata obiectului
respectiv sa fie dezalocata de Garbage Colector. Colectorul de gunoi de ruleaza pe un
fir de executie demon si nu se stie de dinainte cand va fi planificat pentru executie. Se
stie ca metoda finalize se apeleaza inainte ca zona de memorie sa fie reutilizata.
Clasa System insa are o metoda gc() care forteaza executia Garbage Collector si se
foloseste impreuna cu runFinalization(). Aceasta metoda forteaza executia metodelor
finalize() a obiectelor care nu mai sunt referintiate, dar inca n-au fost finalizate. Cu
ajutorul unei alte metode runFinalizerOnExit() putem seta flag-ul care indica masinii
virtuale daca sa execute sau nu metodele finalize la exit, adica la terminarea executiei
masinii virtuale.
public static void gc()
public static void runFinalization()
public static void runFinalizerOnExit()
7. Exemplu
Sa se scrie o aplicatie care defineste o clasa stiva si instantieaza obiecte din aceasta
clasa.
Diagrama de obiecte:
Diagrama de clase:
Sursa Java:
public class TControl{
public TControl(){
TStiva s1, s2;
int i;
s1 = new TStiva( 10 );
s2 = new TStiva( );
for( i=0; i<10; i++)
s1.push( i );
while( ! s1.empty() )
System.out.println( Integer.toString( s1.pop()));
for( i=10;i<15;i++){
s2.push( i );
System.out.println( Integer.toString( s2.top()));
}
}
public static void main(String args[] ){
TControl contro = new TControl();
}
}
class TStiva{
int st[];
int sp;
int dim;
public TStiva( int pdim){
dim = pdim;
st = new int[ dim ];
sp = -1;
}
public TStiva( ){
dim = 100;
st = new int[ dim ];
sp = -1;
}
public void push( inte ){
sp++;
st[ sp ] = e;
}
public int pop(){
sp--;
return st[ sp+1 ];
}
public int top(){
return st[ sp ];
}
public boolean empty(){
return sp==-1;
}
}
Modelare cu obiecte
1.
2.
3.
4.
Doua obiecte sunt in legatura de cunoastere, daca existaindependent si cel putin unul
cunoaste pe celalalt.
Doua obiecte sunt in legatura de continere, daca unul dintreele contine fizic pe
celalalt. (intreg+parte)
Exemple de legaturi de cunoastere:
Relatia de continere:
Daca se distruge obiectul container atunci automat se distrug si obiectele continute.
Relatia de continere este o relatie mai puternica decat relatia de cunoastere. Relatia de
continere poate fi o relatie de continere slaba sau una puternica. In cazul relatiei de
continere slaba, intregul isi cunoaste partile, dar poate exista independent de partea
continuta. Ca exemplu vom considera un obiect Cutie, care poate sa contina un cadou.
Cutia existasi fara cadou. Pentru acest tip de relatie se utilizeaza un romb neumplutpe
partea intregului.
2. Diagrame de clase
Exemplele de mai sus au fost din prima categorie, adica legaturi unu launu.
Exemple de legaturi unu la mai multe:
TServer server;
...
}
class TServer
...
}
Proiectare:
o
Diagrame de obiecte
o
Diagrame de clase
Implementare:
Mostenire
Prima data definim doua concepte: specializarea si generalizarea.
Specializarea este procesul prin care se adauga noi caracteristiciunui obiect existent.
Generalizarea este procesul prin care din descrierea mai multorobiecte scoatem in
evidenta cele comune.
Prin mostenire se adauga noi proprietati unei clase existente si se potredefini anumite
caracteristici ai clasei existente.
Notatia UML pentru mostenire:
In exemplul de mai sus clasa TOm are doua campuri de date, numele si anul nasterii,
respectiv doua metode invata() si vorbeste(). Din aceasta clasa de baza derivam doua
alte clase noi, clasa TStudent respectiv clasa TProfesor. Aceste clase noi adauga alte
campuri de date si metode respectiv specializeaza anumite metode ale clasei de baza.
Astfel clasa TStudent va avea cinci campuri de date: nume, anul nasterii, numar
matricol, an de studii, medie si doua metode inavata() si vorbeste(). Metoda invata() a
fost specializata (redefinita) deoarece un student invata altfel decat un om obisnuit.
Probabil ca invata mai mult si invata in anumite perioade ale anului. In cazul clasei
TProfesor apar doua date in plus fata de clasa parinte. Apare catedra la care apartine si
salariul pe care primeste pentru activitatea desfasurata. Clasa defineste o noua metoda
preda(),care caracterizeaza numai obiectele de tip TProfesor si redefineste
Observatie: Daca se adauga campuri de date noi, atunci trebuie adaugatesi metode noi
care realizeaza accesul la aceste date.
Exista limbaje de programare care permit si mostenirea multipla cumar fi C++, iar
altele care permit doar derivarea de la o singura clasaparinte: Java, Smalltalk, Delphi.
}
}
public class p4{
public static void main( String args[] )
{
B b = new B();
}
}
Legare statica
Legare statica inseamna ca adresa metodei se cunoaste inca din timpul compilarii.
Deci in cazul unei constructii nume_obiect.metoda() compilatorul stie exact care
metoda va fi executata. Daca clasa careia apartine obiectul nu areo asemenea metoda
atunci compilatorul cauta metoda in ierarhia declase. Se va apela metoda din clasa
cea mai apropiata cu acelasi nume Aceasta cautare este facuta in faza compilarii si
acest tip de legare senumeste legare statica.
Exemplu 1: Sa se scrie o aplicatie care afiseaza pe ecran treiferestre cu titlurile: Unu,
Doi, Trei si cu dimensiunile 100x100.
Diagrama de clase:
Diagrama de colaborare:
}
public static void main(String[] args)
{
Aplicatie a = new Aplicatie();
}
}
Sursa Java:
import java.awt.Frame;
import java.awt.Button;
import java.awt.Label;
public class MyFrame extends Frame
{
private Button buttons[];
private Label label;
public MyFrame()
{
// Crearea butoanelor si adaugarea lor la container
buttons = new Button[ 2 ];
buttons[ 0 ]= new Button("Buton 1");
add( buttons[ 0 ], "North" );
buttons[ 1 ]= new Button("Buton 2");
add( buttons[ 1 ],"South" );
// Crearea etichetei si adaugarea ei la container
Exemplu 3: Sa se scrie o aplicatie care afiseaza cinci ferestrede tip MyFrame astfel
incat sa nu se suprapuna.
Sursa Java:
//Source file: MyFrames.java
Frames[ i ].setBounds(i*100,i*100,50,50);
Frames[ i ].setVisible( true );
}
}
1. Interfete, pachete
O interfata este o declaratie de tip care defineste de obicei un comportament. Este
formata dintr-o serie de constante si metode pentru care nu se specifica nici un fel de
implementare. In Java se utilizeazainterfete pentru a suplini lipsa mostenirii multiple.
Si interfetele potavea modificatori. Din punctul de vedere al accesului la ele pot fi
publice(publicinterface .. ), accesibile si din alte pachete decat din cel care odefineste.
Pot avea atasat si modificatorul de tip abstract ( abstractinterface... ).
interface Scalabil{
static final MARE = 2, MEDIU = 1, MIC =0;
void scalare( int marime );
}
class Cutie implements Scalabil{
public void scalare( int marime ){
switch ( marime ){
case MARE :{ ...; break; }.
case MEDIU:{ ...; break; }
case MIC
:{ ...; break; }
}
}
}
Deoarece interfata defineste un tip nou de aceea oriunde se pot utiliza clase se pot
utiliza si interfte. De exemplu in cazul exemplului de maisus putem avea urmatorul
cod:
Scalabil s; // s-a declarat o referinta la interfata Scalabil
s = new Cutie(); // s-a instantiat un obiect din clasa Cutiecu care s-a initializat
referinta s
Exemplu 1. Declaraea unei interfete si utilizarea acestuia
interface Scalabil{
static final int MARE =
static final int MEDIU =
static final int MIC
=
void scalare( int marime
}
2;
1;
0;
);
List l = Arrays.asList(args);
Collections.shuffle(l);
System.out.println(l);
}
}
Crearea pachetelor
Un pachet este format dintr-un grup de clase si interfete. Clasele pe care le utilizam in
aplicatiile noastre trebuie sa fie cunoscute si de catrecompilator, respectiv de catre
interpretor.
Codul sursa al unei clase Java se numeste unitate de compilare.O unitate de
compilare in mod normal este format dintr-un singur fisiercontinand definitia unei
singure clase (poate fi formata si din mai multeclase dar numai una singura poate fi
publica) si fisierul poarta numeleclasei. Clasa MyClass se defineste in
fisierul MyClass.java.Fiecare clasa Java apartine unui pachet. Daca nu se declara carui
pachetii apartine clasa, atunci va apartine pachetului implicit, altfel
pachetuluispecificat.
Variabila mediului de executie CLASSPATH este utilizat atat de compilator cat si de
interpretor pentru localizarea unei resurse. Contine caile incare se afla pachetele Java.
O cale poate specifica un catalog sau un fisierdintr-un catalog dat. Pachetele pot fi
arhivate si incarcatorul de claseva extrage din arhive clasele necesare. Formatele de
arhivare suportatede catre mediul de executie Java sunt JAR (Java Archive)
si ZIP.Fisierele JAR sunt create cu utilitarul jar care face partedin JDK. Intr-o arhiva
JAR se poate pune absolut orice tip de fisier. Decitoate clasele apartinand unei
aplicatii pot fi impachetate intr-un singurfisier JAR, care se adauga pe urma la
CLASSPATH.
Utilizarea utilitarului jar (Similar cu utilitarul tar de sub UNIX):
Comanda
Semnificatie
jar -tvf
<nume_arhiva>
Curs4.jar Curs4
added manifest
adding: Curs4/ (in=0) (out=0) (stored 0%)
adding:
adding:
adding:
adding:
adding:
adding:
40%)
adding:
adding:
adding:
adding:
adding:
adding:
$jar -xvf
created:
extracted:
created:
extracted:
extracted:
created:
created:
extracted:
extracted:
extracted:
extracted:
extracted:
extracted:
extracted:
extracted:
Curs4.jar
META-INF/
META-INF/MANIFEST.MF
Curs4/
Curs4/Person.class
Curs4/ppelda.java
Curs4/classes/
Curs4/classes/MyPackage/
Curs4/classes/MyPackage/Person.class
Curs4/classes/MyPackage/Student.class
Curs4/classes/Test.class
Curs4/Person.java
Curs4/Test.java
Curs4/Test.class
Curs4/Curs4.jar
Curs4/Student.java
Exemplu:
Fisierul: MyBaseClass.java
package MyPackage;
public class MyBaseClass{
..
}
Fisierul: MyDerivedClass.java
package MyPackage;
public class MyDerivedClass extends MyBaseClass{
..
}
Exemplul precedent este format din doua unitati de compilare care apartin aceluiasi
pachet. Pentru compilarea acestor fisiere se vor utiliza liniile de comanda:
1. mkdir classes
//Se creaza catalogulclasses pentru fisierele .class
2. javac -d .\classes MyBaseClass.java
//Se compileaza unitatea
//MyBaseClass.java, fisierul
//rezultat se va pune in directorul
//specificat dupa
//optiunea -d
Rezultatul: ---classes----MyPackage----MyBaseClass.class
3. javac -d .\classes -classpath .\classes;c:\jdk1.2\lib MyDerivedClass.java
//Se compileaza unitatea MyDerivedClass.java, rezultatul se stocheaza tot
//in directorul classes, iar pentru incarcarea claselor se utilizeaza
caile
//specificate
//dupa optiunea -classpath. Aici s-au specificat doua cai de cautare:
//subdirectorul classes al directorului curent si subdirectorul lib al
//catalogului in
//care s-a instalat JDK
Rezultatul: ---classes----MyPackage--------MyBaseClass.class
|
|-------MyDerivedClass.class
Utilizarea pachetelor
Pentru a utiliza clase dintr-un pachet putem sa alegem din 3 variante:
1. Se prefixeaza numele clasei cu numele pachetului
Exemple:
java.awt.Button b;
MyPackage.MyBaseClass ob;
MyPackage.MyDerivedClass od;
Exemplu complet:
package MyPackage;
public class Person{
protected String name;
protected int age;
public Person( Stringname, int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public void setName(String name ){
this.name = name;
}
public void setAge( intage ){
this.age = age;
}
}
}
public String getFaculty(){
return faculty;
}
public void setFaculty(String faculty ){
this.faculty = faculty;
}
}
}
}
Clase incuibate
Incepand cu versiunea 1.1 se pot declara clase in interiorull altorclase. In acest caz,
obiecte din clasa incuibata se pot declara doar inclasa care le contine. Se pot declara
chiar si clase incuibate anonime.
Clase incuibate anonieme si instantierea acestora:
{
...
addWindowListener( new WindowAdapter(){
public void windowClosing( WindowEvent e ){
{
System.exit( 0 );
}
}
);
...
}
class A{
A(){}
static class B{
B(){}
public static void doIt(){
System.out.println("Hello");
}
};
}
public class p3{
public static void main( String args[] )
{
A.B.doIt();
}
}
Observatii:
1. Clasele incuibate nu pot contine metode statice, exceptie formand clasele incuibate
statice
2. Clasele incuibate nestatice apartin claselor exterioare, de aceea instantierea
obiectelor din aceste clase este precedata de instantierea obiectelor din clasele
exterioare.
In exemplul urmator vom utiliza interfata Enumeration:
//Interfata java.util.Enumeration
public interface Enumeration{
boolean hasMoreElements();
Object nextElement();
}
2. Modificatori de acces
O clasa gata facuta se poate utiliza in doua moduri:
Accesul datelor din afara obiectului nu trebuie permis. De obicei clasatrebuia sa puna
la dispozitia celor care o utilizeaza o serie de metodepublice care permit manipularea
acestor date. Exista si metode care suntmetode ajutatoare si nu trebuie sa fie accesibile
din afara. Pentru a putearealiza protectia membrilor clasei vom utiliza asa zisele
modificatoride acces. Modificatorii pot fi atasati atat claselor cat si membrilor
private -private
public -publice
protected -protejate
prietenosi
Membrii privati ai clasei nu sunt accesibili din afara clasei. Ei pot fiutilizati doar de
catre celelalte metode ale clasei.
Membrii publici sunt accesibili din afara clasei. Ei pot fi utilizatisi in clasele derivate.
Nu exista nici o restrictie in utilizarea acestora.
Membrii protejati sunt accesibili doar prin metodele clasei si ei vorfi accesibili si in
clasele derivate.
Membrii prietenosi sunt declarate fara nici un fel de cuvant cheiesi ei vor fi accesibili
din toate clasele din pachetul caruia apartineclasa.
In continuare vizibilitatea datelor va fi notata in modul urmator:
+ ----> membru public
- ----> membru privat
# ----> membru protejat
In cazul mostenirii membrii privati ai clasei vor exista si in clasa derivata, dar acestia
nu vor fi accesibili.
Din punctul de vedere al accesului la clasa avem doar doua tipuri declase:
clase publice
clase nepublice.
Clasele publice sunt accesibile pentru toate celelalte clase, iar celenepublice doar
pentru clasele care fac parte din acelasi pachet. Cele nepublicese declara normal fara
vreun modificator, iar cele publice se declara cumodificatorul public. (public class ...).
3. Polimorfism
Supraincarcarea metodelor (Methods overloading) inseamnadefinirea a doua sau a
mai multe metode in cadrul unei clase care diferaprin lista parametrilor si eventual
prin tipul returnat. De exemplu inJava putem avea oricati constructori pentru o clasa.
Toti constructorii poarta numele clasei (au acelasi nume) ei difera doar prin parametrii
lor (Constructorii nu returneaza nici o valoare). Pentru exemplificare consideram clasa
String din pachetul java.lang si cativa din constructorii clasei:
String()- creaza un obiect de tip string vid
String( String) - creaza un obiect de tip string initializand cu un alt obiectde
tip string (se copiaza continutul parametrului)
String( char []) - creaza un obiect de tip string initializand cu un tablou
decaractere
String( char s[],int indice_start, int numar_caractere
) -creaza un obiect de tipstring initializand acesta cu un subtablou
In afara de constructor putem defini si alte metode cu acelasi nume.De exemplu:
int max( int, int);
float max( float,float );
Compilatorul poate decide despre care metoda este vorba din tipul sinumarul
parametrilor. Deci adresa acestor metode se cunoaste inca din fazade compilare.
Redefinirea metodelor (Methods overriding) inseamna caclasele derivate pot redefini
metodele claselor parinte utilizand aceasisintaxa ( tip returnat nume_metoda( lista
parametrilor)). Un exemplu:
Metodele supraincarcate sunt legate in mod static, adica adresa lor secunoaste inca din
faza compilarii. Metodele redefinite sunt legate in moddinamic in timpul executiei.
Acest lucru duce imediat la scaderea vitezeide executie a programelor. In Java toate
metodele pot fi redefinite, iardaca dorim interzicerea redefinirii atunci putem utiliza
modificatorulfinal (modificator de tip). Modificatorul final face ca un membru sa
fieprivit constant. Modificatorul se mai poate utiliza pentru campuri de date si pentru
clase. Dintr-o clasa definita cu modificatorul final nu putemderiva alte subclase.
4. Modificatori de tip
Acesti modificatori se pot defini pentru clase, metode si variabilele clasei.
Modificatori pentru clase:
final
abstract
O clasa se poate declara abstract sau final. Clasele finale nu potfi superclase pentru
alte clase. Clasele abstracte sunt clase care servescca superclase pentru clasele
concrete care se vor deriva din aceasta. Dintr-o clasa abstracta nu se pot crea instante.
Modificatori pentru metode:
static
abstract
final
native
synchronized
}
}
}
Metodele abstracte in Java sunt metode fara corp de implementare.Ele sunt declarate
pentru a forta subclasele care vor sa aiba instantesa implementeze metodele
respective. Metodele abstracte se declara doarin clase abstracte. Clasele derivate din
clase abstracte care nu sunt declarateabstracte trebuie sa implementeze metodele
abstracte ale superclaselor.Metodele statice nu pot fi declarate si abstracte, deoarece o
metoda staticaeste si implicit metoda finala si nu poate fi rescrisa.
Metodele finale sunt metode care nu pot fi redefinite in subclaseleclasei in care au fost
declarate. Declararea metodelor cu clauza finaleste utila in primul rand pentru
compilator, care poate sa faca legarestatica in cazul acestor metode astfel crescand
viteza de executie a programelorJava.
Metodele native sunt metode implementate intr-un alt limbaj deprogramare de obicei
intr-un limaj nativ al platformei (C, C++ sau asamblare).Metodele native nu au corp
de implementare, ele fiind implementate intr-unalt limbaj de programare. Aceste
metode se comporta la fel ca toate celelaltemetode Java, pot fi mostenite, redefinite
etc.
Metodele sincronizate sunt utilizate pentru accesul unor resursecritice. In momentul
apelarii unei asemenea metode, resursei i se alocaun monitor, care blocheaza accesul
altor metode la aceea resursa. Dupaterminarea apelului se elibereaza monitorul acesta
putand fi ocupat dealte metode sincronizate.
Modificatori pentru variabile
static
final
transient
volatile
1.
2.
3.
4.
5.
6.
7.
Introducere
Componente grafice
Ierarhia claselor pentru componente
Obiecte peer
Conceptul Model/View/Controller (MVC)
Afisarea componentelor
Organizarea componentelor
Introducere
Acest pachet ne ofera o coletie de clase pentru crearea interfetelor grafice. Aceste
clase permit lucrul cu ferestre, desenari, lucrul cu imagini si utilizarea componentelor
ca butoane, liste, meniuri intr-un mod independent de platforma. Pachetul java.awt
contine clasele AWT (Abstract Window Toolkit) GUI iar java.awt.image ne ofera
niste facilitati in plus pentru lucrul cu imagini. Dupa cum numele sugereaza AWT este
o abstractie. Clasele si functionalitatile oferite sunt aceleasi pentru orice implementare
Java. Pentru a obtine independenta de platforma AWT utilizeaza toolkituri
interschimbabile care actioneaza cu sistemul de ferestre pe care se ruleaza aplicatia.
De exemplu sa presupunem ca aplicatia noastra creaza un buton. Cand se ruleaza
aplicatia, toolkitul specific platformei afiseaza butonul conform platformei. Daca
aplicatia se ruleaza sub Windows vom obtine un buton de tip Windows, iar daca se
ruleaza sub Unix se va afisa un buton de tip X Windows.
Utilizarea componentelor din acest pachet este relativ usoara, pe cand toolkiturile
GUI sunt foarte complexe, dar aceasta este treaba celor care vor sa implementeze
AWT-ul pe o noua platforma.
Realitatea este ca cele mai multe probleme despre Java se ridica la folosirea acestui
pachet. Implementarea toolkiturilor pentru acest pachet contin cele mai multe buguri
Java. Tocmai din aceasta cauza JavaSoft a introdus Swing care reprezinta noua
generatie de componentele grafice si fac parte din JFC (Java Foundation Classes).
Componente grafice
Componentele sunt elementele care se utilizeaza la crearea unei interfete grafice.
Componentele sunt incluse in containere, care la randul lor sunt componente speciale.
Anumite componente pot fi containere pentru alte componente: de exemplu o
fereastra cu doua panouri. In acest caz fereastra este containerul, iar panelele sunt
componentele continute. Daca adaugam elemente ca butoane, liste, etichete, casete
text etc. in cele doua panouri atunci panoul va fi containerul iar elementele adaugate
vor fi componentele.
Este important sa intelegem aceasta arhitectura deoarece astfel putem intelege cam
ce putem realiza cu componentele. In figura preceedenta se poate vedea ce se intampla
la crearea unui buton. Toolkitul este de fapt o "fabrica de componente" native. Java
utilizeaza aceasta fabrica pentru a separa funtionalitatea componentelor de
modalitatea de implementare pe un sistem de afisare nativ. Obiectul Toolkit contine
metode pentru crearea tuturor tipurilor de componente grafice. Daca nu ne place acest
Toolkit oferit de mediul Java, putem sa scriem toolkitul nostru propriu.
Pachetul java.awt.peer contine o interfata pentru fiecare tip de componenta grafica.
In acest pachet clasa de baza este ComponentPeer de la care se deriva aproape toate
celelalte clase. De exemplu clasei Button ii corespunde clasa ButtonPeer. Apelul
metodei setLabel() determina apelul metodei corespunzatoare al obiectului nativ.
Fire de executie
Ce sunt firele de excutie si de ce avem nevoie de fire de
executie?
Utilizarea firelor de executie in Java
1. Creare si lansare
2. Legarea firelor de executie
3.
4.
5.
6.
7.
8.
9.
Aplicatiile care utilizeaza mai multe fire de executie pot executa in paralel mai multe
sarcini. De exemplu o aplicatie care realizeaza o animatie intr-o fereastra, iar intr-o
alta fereastra afiseaza rezultatul unei interogari de baza de date.
Un program de navigare realizeaza cel putin doua lucruri in paralel: aduce date din
retea si paralel afiseaza aceste date. Firele de executie faciliteaza ca programarea sa
fie mai apropiata de gandirea umana. Omul de obicei se ocupa de mai multe lucruri in
acelasi timp. Un profesor in timp ce preda trebuie sa fie atent si la studentii care il
asculta.
Firele de executie Java ofera o serie de facilitati programatorilor, dar exista si o serie
de diferente fata de alte pachete pentru fire de executie. Comparand cu aceste pachete
putem considera ca ne ofera mai putin, dar au si un avantaj, simplitatea. Exista si un
standard POSIX P10033.4a un pachet de fire de excutie, care poate fi implementat in
orice sistem de operare.
Orice pachet Java (de la Sun) este "Thread safe", adica este asigurat ca metodele
continute in pachet pot fi apelate simultan de mai multe fire de executie.
Clasa Thread este o clasa care are ca si superclasa clasa Object si implementeaza
interfata Runnable. Interfata Runnable declara o singura metoda run() si clasa Thread
implementeaza aceasta. Masina virtuala Java permite unei aplicatii sa ruleze mai
multe fire de executie in paralel. Fiecare fir de executie are o prioritate si fiecare fir
poate fi marcat ca si fir demon. In momentul crearii unui fir de executie se seteaza si
proprietatile acestea, adica firul nou creat va avea aceasi prioritate ca si firul parinte si
va fi de tip demon numai daca firul parinte este demon.
Cand se interpreteaza codul octeti al unei aplicatii, masina virtuala Java creaza un
prim fir de executie care ruleaza metoda main. Masina virtuala Java continua sa
execute acest fir sau alte fire noi create pana cand toate firele de executie nedemon
sunt distruse.
Thread
start()
run()
sleep()
interrupt()
join()
getName()
setName()
destroy()
isinterrupted()
Metoda start() este utilizata pentru lansarea in executie a unui fir nou creat. Metoda
start() se utilizeaza o singura data in ciclul de viata al unui fir . Firul se distruge cu
metoda destroy(), si aceasta putand fi apelat o singura data. Metoda sleep() se
apeleaza cu un argument care reprezinta timpul in milisecunde in care firul de
executie asteapta(adoarme). sleep() este o metoda statica se apeleaza prefixat cu
numele clasei. In caz ca firul este intrerupt se genereaza
exceptia InterruptedException. Deci apelul metodei trebuie facut intr-un context de
tratarea acestei exceptii.
try{
Thread.sleep( 1000 )
}
catch ( InterruptedException e ){
//Codul de tratarea a exceptiei
}
Firul poate fi scos din starea de adormire prin apelul metodei interrupt(). Metoda se
mai apeleaza pentru a intrerupe executia unui fir care este blocat in asteptarea unei
operatii lungi de intrare/iesire. Metodajoin() se utilizeza pentru legarea firelor de
executie. Prin getName() si setName() putem obtine sau sa setam numele firului.
Diagrama de clase:
Diagrama de colaborare:
Figura precedenta prezinta proiectul unei aplicatii, care creaza doua fire de executie si
le starteaza, neasteptand terminarea acestora. Firele vor afisa numele lor pana cand
sunt oprite. Firele pot fi oprite cu combinatia de taste Ctrl-C.
Crearea unui obiect din clasa MyThread nu inseamna si inceperea executiei firului
creat. Firul poate fi lansat in executie prin apelul metodei start().
Metoda start() apeleaza metoda run(), care executa instructiunile proprii firului.
Sursa Java pentru exemplul precedent:
//Source file: MyThread.java
public class MyThread extends Thread
{
public MyThread()
{
}
public void run()
{
while( true )
try{
A doua modalitate de crearea unui fir de executie se utilizeaza cand clasa noua creata
trebuie sa mosteneasca de la doua clase. Deoarece Java nu permite mostenire multipla,
se incearca simularea acestuia prin interfete. Interfata este o declaratie care contine o
serie de metode abstracte care trebuie implementate de catre clasa care implementeaza
interfata.
Interfata Runnable este:
public interface Runnable{
public abstract void run();
}
In acest caz, clasa noua nu mosteneste metodele clasei Thread (start(), stop() etc. )
deci crearea firului se va face prin crearea unui obiect de tip Thread care primeste ca
parametru un obiect de tip Runnable. (Clasa Thread are si un asemenea constructor).
Diagrama de clase:
Diagrama de colaborare:
Sursa Java:
//Source file: Control.java
public class Control
{
public MyRunnable objects[];
public Thread threads[];
public Control()
{
objects = new MyRunnable[ 2 ];
objects[ 0 ] = new MyRunnable();
objects[ 1 ] = new MyRunnable();
threads = new Thread[ 2 ];
threads[ 0 ] = new Thread(objects[ 0 ]);
threads[ 1 ] = new Thread(objects[ 1 ]);
threads[ 0 ].start( );
threads[ 1 ].start( );
}
Exemplul urmator creaza doua fire de excutie. Unul dintre fire afiseaza un text si
asteapta 500 de milisecunde de cinci ori. Celalalt fir isi afiseaza numele dupa care
asteapta pe celalalt fir ca acesta sa-si termine executia.
Diagrama de secventiere:
Sursa Java:
//Source file: MyThread1.java
public class MyThread1 extends Thread
{
public MyThread1(String name)
{
super( name);
}
public void run()
{
System.out.println(getName() + "is running");
for(int i=0;i<5;i++){
try{
sleep( 500 )
}
catch( InterruptedException e ){}
System.out.println(getName()+" writes "+Integer.toString(i));
}
}
}
//Source file: MyThread2.java
public class MyThread2 extends Thread
{
public MyThread1 waitedThread;
}
catch( InterruptedException e ){}
System.out.println(getName() + "se ruleaza");
}
}
}
public class Control{
public static void main( String args[] )
{
MyThread t1,t2;
t1 = new MyThread("Normal", false );
t2 = new MyThread("Demon ", true
);
t1.start();
t2.start();
}
}
Fir "rulabil" (Runnable): se ajunge in aceasta stare prin apelul metodei start(). Firul
trece in stare de "nerulabil" (Not Runnable) prin apelul metodei sleep() , wait() sau
daca firul se blocheaza intr-o operatie de citire. Dupa terminarea asteptarii firul revine
in starea "rulabil".
Firul ajunge in starea "mort", dupa ce se termina executia metodei run() sau daca se
apeleaza metoda destroy().
Firele sunt planificate pentru executie la fel ca si procesele, utilizand un algoritm
adecvat pentru planificarea lor. Daca masina virtuala se ruleaza pe un sistem de oprare
care lucreaza cu fire de executie, atunci s-ar putea ca fiecare fir de executie creat de
catre masina virtuala Java sa fie executat pe un fir nativ.
6. Prioritatea firelor de executie
Masina virtuala Java utilizeaza prioritatile firelor in planificarea firelor pentru
executie. In Java sunt 10 niveluri de prioritate. Avem si trei constante in clasa Thread
ce pot fi utilizate:
Thread.MIN_PRIORITY avand valoarea 1
Thread.MAX_PRIORITY avand valoarea 10
Thread.NORM_PRIORITY avand valoarea 5
Prioritatea firului se seteaza cu metoda setPriority()
7. Sincronizarea firelor de executie.
Fiecare fir de executie are o viata proprie si nu este interesat de ceea ce fac celelalte
fire de executie. Daca calculatorul este dotat cu mai multe procesoare, atunci diferitele
fire de executie ale aceluiasi proces pot fi planificate pentru executie pe diferite
procesoare. Pentru cel care proiecteaza aplicatia, acest lucru este nesemnificativ,
deoarece toate aceste lucruri cad in sarcina masinii virtuale si nu in sarcina
programatorului. Totusi apare o problema in cazul aplicatiilor care se ruleaza pe mai
multe fire si anume accesul resurselor comune. Ca sa nu apara probleme, accesul la
resursele utilizate in comun trebuie sincronizat. Sincronizarea se bazeaza pe conceptul
de monitor introdus de catre C.A. Hoare. Un monitor este de fapt un lacat atasat unei
resurse pentru a preveni utilizarea resursei in paralel.
Un fir de executie ocupa un monitor daca apeleaza o metoda sincronizata. Daca un
fir ocupa un monitor, un alt fir care incearca ocuparea aceluiasi monitor, este blocat si
asteapta pana la eliberarea monitorului.
Oricare obiect, care contine unul sau mai multe metode sincronizate, are si un monitor
atasat. Metodele sincronizate se definesc in modul urmator:
public synchronized void my_method() {...}
Orice clasa Java are un monitor atasat. Acest monitor se deosebeste de monitoarele
atasate obiectelor, se utilizeaza cand se apeleaza metodele statice sincronizate ale
clasei.
public static synchronized void my_static_method() {...}
wait() si notify()
Cu ajutorul cuvantului-cheie synchronized putem serializa executia anumitor
metode. Metodele wait() si notify() ale clasei Object extind aceasta
capabilitate. Utilizand wait() si notify(), un fir de executie poate elibera
monitorul ocupat, asteptand un semnal pentru reocuparea acestuia. Metodele pot fi
utilizate doar in metode sincronizate sau in blocuri de instructiuni sincronizate.
Executandwait() intr-un bloc sincronizat, firul elibereaza monitorul si adoarme. De
obicei firul recurge la aceasta posibilitate cand trebuie sa astepte aparitia unui
eveniment intr-o alta parte a aplicatiei. Mai tarziu, cand apare evenimentul, firul, in
care a aparut evenimentul, apeleaza notify() pentru a trezi firul adormit. Firul
trezit ocupa din nou monitorul si isi continua activitatea din punctul de intrerupere.
class MyClass{
public synchronized void method1(){}
public synchronized void method2(){}
public static synchronized void method3(){}
}
...
MyClass object1 = new MyClass(); // Se ataseaza un monitor obiect pentru
sincronizarea accesului la metodele method1() si method2() pentru firele de
executie al obiectului object1
MyClass object2 = new MyClass(); // Se ataseaza un monitor obiect pentru
sincronizarea accesului la metodele method1() si method2() pentru firele de
executie al obiectului object2
Pentru exemplul precedent se vor crea trei monitoare. Un monitor de clasa, care este
responsabil pentru sincronizarea accesului la metoda statica ( metoda clasei)
method3() si doua monitoare obiect, cate unul pentru fiecare obiect declarat pentru
sincronizarea accesului la method1(0 si method2()
Metoda notify() anunta intotdeauna un singur fir de executie care asteapta pentru a
accesa monitorul. Exista si o alta metoda notifyAll() care se utilizeaza atunci cand mai
multe fire de executie concureaza pentru acelasi monitor. In acest caz fiecare fir este
instiintat si ele vor concura pentru obtinerea monitorului.
Metodele wait(), notify() si notifyAll() se utilizeaza doar in metode sincronizate, altfel
Producer (Functionar)
Consumer (Imprimanta)
Pentru a simula paralelismul vom lucra cu fire de executie, adica fiecare functionar si
imprimanta va fi implementat ca un fir de
executie. Evident apare si problema sincronizarii la cozile de asteptare atasate
imprimantelor.
Clasa Consumer
Clasa va avea un constructor care initializeaza numele firului de executie (atribut
mostenit de la clasa parinte Thread) si atributul
theBuffer creat in urma asocierii cu clasa Buffer. Acest atribut este un atribut simplu,
dar ca sa-l putem initializa, trebuie sa avem
create in prealabil obiectele de tip Buffer si atunci fiecarui obiect Buffer ii corespunde
un obiect de tip Consumer.
Introducem si o clasa Product pentru identificarea documentelor produse. Fiecare
document va avea un nume, deci clasa
trebuie sa aiba un atribut tip sir de caractere reprezentand numele produsului. Acest
atribut va fi initializat cu constructorul clasei
si adaugam o metoda de tip query pentru returnarea acestui atribut.
Pentru numerotarea documentelor vom introduce si o clasa Counter. La pornirea
aplicatiei se creaza o singura instanta din
aceasta clasa si toti producatorii o vor folosi. Clasa va avea un atribut value de tip
intreg lung si o operatie next, pentru
returnarea urmatoarei valori a numaratorului.
Perspectiva de implementare
La diagrama din sectiunea precedenta vom adauga inca o clasa Control. Aceasta clasa
va avea cate o asociere cu calsele
Producer, Consumer si Buffer. Multiplicitatea acestor asocieri se vede pe diagrama
alaturata. Constructorul clasei face
instantierile obiectelor Buffer, Producer, Consumer. Fiecare asociere are
multiplicitatea 1:n, un singur obiect de tip control si
mai multi bufferi, producatori si consumatori. Trebuie sa vaem grija ca numarul
bufferelor sa corespunda cu numarul
imprimantelor.
Codul final:
//Source file: Control.java
}
}
catch( InterruptedException e ){}
}
}
}
//Source file: C:\Manyi\TempRose\Buffer.java
import java.util.Vector;
public class Buffer
{
private int maxBuffer;
private Vector buffer = new Vector();
public Buffer()
{
}
public synchronized void put(Product p) throws InterruptedException
{
while( buffer.size() == maxBuffer )
wait();
buffer.addElement( p );
notify();
}
= (Product) buffer.firstElement();
buffer.removeElement( p );
notify();
return p;
}
public Buffer(int maxBuffer)
{
this.maxBuffer = maxBuffer;
}
}
9. Exemple
9.1. Specificatie problema:
Intr-o gara sunt 3 case de bilete. Calatorii se aseaza la coada la una dintre cozi ( de
ex: la care e mai scurta ), dar casieritele nu elibereaza biletele in acelasi ritm. Simulati
functionarea caselor de bilete.
Diagrama de clase
Sursa Java:
Calator.java
package Gara;
import java.util.*;
public class Calator{
= tsosire;
this.tplecare = tplecare;
}
public long getCID(){
return cID;
}
public Date getTsosire(){
return tsosire;
}
public Date getTplecare(){
return tplecare;
}
public String toString(){
return ( Long.toString(cID)+" "+tsosire.toString()+"
"+tplecare.toString());
}
}
Casa.java
package Gara;
import java.util.*;
public class Casa extends Thread{
private Vector calatori=new Vector();
public Casa( String name ){
setName( name );
}
public void run(){
try{
while( true ){
sterge_calator();
sleep( (int) (Math.random()*4000) );
}
}
catch( InterruptedException e ){
System.out.println("Intrerupere");
System.out.println( e.toString());
}
}
public synchronized void adauga_calator( Calator c ) throws
InterruptedException
{
calatori.addElement(c);
notifyAll();
}
public synchronized void sterge_calator() throws InterruptedException
{
while( calatori.size() == 0 )
wait();
Calator c = ( Calator )calatori.elementAt(0);
calatori.removeElementAt(0);
System.out.println(Long.toString( c.getCID())+" a fost deservit de
casa "+getName());
notifyAll();
}
public synchronized long lungime_coada() throws InterruptedException{
notifyAll();
long size = calatori.size();
return size;
}
}
Producator.java
package Gara;
import java.util.*;
public class Producator extends Thread{
){
setName( name );
this.nr_case = nr_case;
this.casa = new Casa[ nr_case ];
this.nr_clienti = nr_clienti;
for( int i=0; i<nr_case; i++){
this.casa[ i ] =casa[ i ] ;
}
}
private int min_index (){
int index = 0;
try
{
long min
= casa[0].lungime_coada();
int m = min_index();
System.out.println("Calator :" +Long.toString( ID )+" adaugat la
Integer.toString(m));
CASA "+
casa[ m ].adauga_calator( c );
sleep( (int) (Math.random()*1000) );
}
}
catch( InterruptedException e ){
System.out.println( e.toString());
}
}
}
TestGara.java
import Gara.*;
public class TestGara{
public static void main( String args[] ){
int i;
int nr = 4;
Casa c[] = new Casa[ nr ];
for( i=0; i<nr; i++){
c[ i ] = new Casa("Casa "+Integer.toString( i ));
c[ i ].start();
}
Producator p = new Producator( nr , c, "Producator",30);
p.start();
}
}
Tratarea evenimentelor
1. Evenimente
2.
3.
4.
5.
6.
7.
8.
1. Evenimente
Daca dorim sa scriem aplicatii bazate pe evenimente in Java trebuie sa utilizam
mecanismul de evenimente al limbajul. In Java componentele GUI comunica intre ele
cu ajutorul evenimentelor. Un eveniment este trimiterea unui mesaj. De exemplu un
buton informeaza aplicatia ca utilizatorul l-a apasat. Aceasta informare se realizeaza
cu ajutorul unui eveniment. Mesajele sosesc de la surse de evenimente iar destinatarii
acestor evenimente sunt receptionarii evenimentelor. La receptia evenimentului, in
obiectul receptor se executa o metoda. Evenimentul insusi este un obiect care contine
informatii in legatura cu evenimentul produs. De exemplu daca dorim sa cream
evenimente noi atunci va trebui sa extindem clasa java.util.EventObject. Toate tipurile
de evenimente create de catre utilizatori trebuie sa fie subclasele acestei clase.
public class KeyboardEvent extends java.util.EventObject{
private char key;
KeyboardEvent ( java.awt.Component source, char key){
super( source );
this.key = key;
}
}
Pentru fiecare tip de eveniment exista o interfata care trebuie implementata de catre
toti cei care doresc sa primeasca acel tip de eveniment. Orice obiect care doreste sa
primeasca evenimente de tip ActionEvent trebuie sa implementeze interfata
ActionListener.
public interface ActionListener extends java.util.EventListener{
public void actionPerformed( ActionEvent e );
}
3. Sursele evenimentelor
In sectiunea precedenta am descris mecanismul de primire a evenimentelor in partea
receptorului. In aceasta sectiune vom descrie cum atentioneaza receptorul sursele de
evenimente ca acestia sa porneasca trimiterea evenimentelor daca acestia apar. Pentru
a primi un eveniment un obiect receptor trebuie sa se inregistreze la sursa de
evenimente transmitand acestuia o referinta catre el. De exemplu clasa AWT Button
este o sursa de evenimente ActionEvent. Pentru a fi recptor al acestui eveniment codul
trebuie sa arate in modul urmator:
//sursa de eveniment de tip ActionEvent
Button buton = new Button("Ok");
//receptor de ActionEvenet
class Receptor implements ActionListener{
setupReceiver(){
...
buton.addActionLisener( this );
}
public void actionPerformed( ActionEvent e ){
// Ce sa se faca la apasarea butonului
}
}
4. Livrarea evenimentelor
Evenimentele AWT sunt difuzate, adica evenimentul are o singura sursa dar poate sa
aiba mai multi receptori. Evenimentele sunt difuzate utilizand modelul
observator/observabil. In momentul inregistrarii unui receptor la o sursa de
evenimente, sursa adauga referinta primita la o lista. Cand apare un eveniment
obiectul generat va fi livrat tuturor obiectelor din lista.
5. Evenimente AWT
Toate evenimentele utilizate de componentele GUI al paachetului AWT sunt subclase
ale clasei java.awt.AWTEvent. Ierarhia acestor evenimente se prezinta in figura
urmatoare:
Eveniment
Cine produce?
Interfete Listener
ComponentEvent
Toate componentele
ComponentListener
Metode de tratare
componentResized()
componentMoved()
componentShown()
componentHidden()
FocusEvent
Toate componentele
FocusListener
KeyEvent
Toate componentele
KeyListener
MouseListener
MouseEvent
Toate componentele
MouseMotionListener
ContainerEvent
Toti containerii
ContainerListener
focusGained()
focusLost()
keyTyped()
keyPressed()
keyReleased()
mouseClicked()
mousePressed()
mouseReleased()
mouseEntered()
mouseExited()
mouseDragged()
mouseMoved()
componentAdded()
componentRemoved()
Eveniment
ActionEvent
ItemEvent
AdjustmentEvent
TextEvent
WindowEvent
Cine produce?
TextField
MenuItem
List
Button
List
CheckBox
Choice
CheckboxMenuItem
ScrollPane
Scrollbar
TextArea
TextField
Frame
Dialog
Interfete Listener
Metode de tratare
ActionListener
actionPerformed()
ItemListener
itemStateChanged()
AdjustmentListener
adjustmentValueChanged()
TextListener
textValueChanged()
WindowListener
windowOpened()
windowClosing()
windowClosed()
windowIconified()
windowDeiconified()
windowActivated()
windowDeactivated()
6. java.awt.event.InputEvent
MouseEvent si Keyevent sunt evenimente de tip InputEvent. Daca utilizatorul misca
mouseul sau apasa o tasta se genereaza evenimente de acest tip avand ca sursa
7. Clase Adapter
b;
}
public void actionPerformed( ActionEvent e ){
b.Bautura_Cafea();
}
}
Bauturi b = ...;
Button buton_ceai, buton_cafea, buton_suc;
...
buton_ceai.addActionListener( new BauturiAdapter1(b));
buton_cafea.addActionListener( new BauturiAdapter2(b));
buton_suc.addActionListener( new BauturiAdapter3(b));
Multe din interfetele de tip Listener contin mai multe metode de tratarea
evenimentelor. Din nefericire acesta inseamna ca, clasa care este interesata in aceste
tipuri de evenimente trebuie sa implementeze toate metodele declarate in interfata.
Spre ajutorul programatorilor au fost create niste clase de tip Adapter care
implementeaza aceste metode. Deci daca avem nevoie de o anumita interfata, vom
deriva din aceasta clasa de tip Adapter implementat special pentru interfata dorita de
tip Listener. DE exemplu pentru evenimentele cu mouseul exista
clasa MouseAdapter care implementeza interfata MouseListener.
public void mouseClicked( MouseEvent e ) {};
public void mousePressed( MouseEvent e ){};
public void mouseReleased( MouseEvent e ) {};
public void mouseEntered( MouseEvent e ){};
public void mouseExited( MouseEvent e ) {};
Exemplu de utilizare:
oComponenta.addMouseListener( new MouseAdapter(){
public void MousePressed( MouseEvent e
){
obiect.show();
...
}
}
);
8. Exemple
Exemplu 1. Sa se scrie o aplicatie care afiseaza o fereastra avand o caseta text si trei
butoane avand etichetele 1,2,3. La apasarea butoanelor in caseta text sa apara eticheta
butonului apasat.
Diagrama de clasa:
import
import
import
import
import
java.awt.Frame;
java.awt.event.ActionListener;
java.awt.Button;
java.awt.TextField;
java.awt.event.ActionEvent;
}
});
}
public void actionPerformed(ActionEvent arg0)
{
String s = arg0.getActionCommand();
tf.setText( s );
}
public static void main(String[] args)
{
MyFrame f = new MyFrame();
f.setBounds(1,1,200,100);
f.setVisible( true );
}
}
Sursa Java:
import java.awt.Frame;
import java.awt.Label;
public class MyFrame extends Frame
{
private Label label;
public MyFrame()
{
setLayout( new java.awt.FlowLayout() );
label = new Label(" ");
add( label );
// Inregistrarea ferestrei ca si receptor pentru evenimentele cu
mouse-ul
addMouseListener( new java.awt.event.MouseAdapter(){
public void mouseClicked( java.awt.event.MouseEvent e )
{
label.setText("("+Integer.toString(e.getX())+","+Integer.toSt
ring(e.getY())+")");
}
});
// Inregistrarea ferestrei ca si receptor pentru evenimnetele cu
fereastra
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
setVisible( false );
System.exit( 0 );
}
});
}
public static void main(String[] args)
{
MyFrame f = new MyFrame();
f.setBounds(1,1,300,300);
f.setVisible( true );
}
}
Sursa Java:
Facilitati I/E
1.
2.
3.
4.
Generalitati
I/E pe terminal
Filtre
Fisiere
o Implementarea comenzii cat din UNIX
o Copiere de fisiere
1. Conducte
1. Generalitati
In vederea tratarii unitare a interfetelor de comunicare intre entitatile unui sistem
informatic( entitati software+entitati hardware) se introduce conceptul de stream.
Autorul acestui concept este Dennis Ritchie care in 1984 implementeaza primul
sistem I/O pe baza de stream in cadrul s.o. Unix. Ideea de stream are la baza creara
unui canal de comunicatie intre doua entitati. Una dintre entitati este sursa, iar cealalta
destinatia. Sursa scrie informatii in canal, iar destinatia poata sa le citeasca aceste
date.Canalul permite trecerea unui flux de date intr-o singura directie.Datorita faptului
ca exista doua directii de comunicare, exista doua tipuri mari de streamuri pentru orice
nod de comunicatie: input stream si output stream. Tastatura ar fi un exemplu de
input stream, iar monitorul un output stream. Sursa si destinatia nu trebuie sa fie
neaparat periferice, ele pot fi si module soft. Un alt mare avantaj al streamurilor este
posibilitatea conectarii acestora, obtinand astfel un mecanism pipe-line de comunicare
interprocese.
Fluxurile de date sunt de doua tipuri fluxuri de octeti si fluxuri de caractere. Fluxurile
de caractere au fost introduse de versiunea 1.1. . Java API defineste o ierarhie intreaga
de clase si interfete pentru fluxuri.
InputStream/OutputStream
Sunt clase abstracte care definesc functionalitatile de baza pentru citirea respectiv
scrierea unui bloc de octeti. Toate celelalte tipuri de streamuri pentru octeti se deriva
din aceste doua.
Reader/Writer
Sunt clase abstracte care definesc functionalitatile de baza pentru citirea respectiv
scrierea unui bloc de caractere. Toate celelalte tipuri de streamuri pentru caractere se
deriva din aceste doua. Au fost introduse de Java 1.1
InputStreamReader/InputStreamWriter
Sunt clase de tip filtre care se pun peste clasele InputStream/OutputStream si permit
citirea/scrierea a diferitelor tipuri de date (logice, intregi, reale, siruri de caractere etc.
).
ObjectInputStream/ObjectOutputStream
Clase care realizeaza operatiile de citire scriere cu zone tampon pentru a mari
eficienta acestor operatii.
PrintWriter
Un stream special de caractere care permite scrierea textelor. System.out este de acest
tip.
PipedInputStream/PipedOutputStream/PipedReader/PipedWriter
Clase care ofera facilitati pentru accesul fisierelor din sistemul local de fisiere.
2. I/E pe terminal
Asemanator cu C standard si Java ne ofera facilitati pentru a lucra cu intrarea/iesirea
respectiv eroarea standard. Clasa Systemdin pachetul java.lang contine trei
referinte statice de urmatoarele tipuri:
InputStream
in
PrintWriter
PrintWriter
out
err
Aceste trei streamuri nu trebuie deschise, ele se deschid automat inaintea executiei
aplicatiei. Celelalte streamuri se deschid in momentul crearii lor prin apelul
constructorului clasei corespunzatoare. Streamurile se inchid cu apelul metodei
close(). Streamurile in, out si err nu trebuie inchise.
Citirea si scrierea din si in aceste streamuri se realizeaza cu ajutorul metodelor read()
si write() care au mai multe forme supraincarcate. In cazul streamurilor de octeti
metoda read() are urmatoarele trei forme:
int read() throws IOException;
int read( byte b[])throws IOException;
int read( byte b[], int offset, int length ) throws IOException;
Prima forma citeste un octet dar returneaza rezultatul sub forma unui intreg. In caz de
eroare se genereaza exceptia IOException, deci orice apel de metoda read obligatoriu
Prin a doua si a treia forma se pot citi deodata un bloc intreg de octeti. Octetii cititi
vor fi stocati intr-un tablou de octeti primit ca parametru. Aceste doua metode
returneaza numarul octetilor efectiv cititi.
byte b[1024];
try{
int bytesread=System.in.read( b );
}
catch( IOException e ){...}
Functia skip( int ) se utilizeaza pentru a muta pozitia citirii peste un numar de
octeti specificat prin parametru. Toate metodele de citire blocheaza firul de executie
care doreste sa faca operatiile I/O pana cand toate datele sunt disponibile, s-a ajuns la
sfarsitul fluxului de date sau a aparut o exceptie.
Metodele mark() si reset() se folosesc impreuna oferind posibilitatea reluarii citirii
din stream. Prin metoda mark( int readLimit ) se memoreaza pozitia curenta in
stream si se creaza o zona tampon de dimensiunea specificata prin readLimit.
Prin reset() se repozitioneaza indicatorul in stream la pozitia marcata prin mark().
Aceste doua metode pot fi folosite doar in cazul in care streamul suporta marcare.
Verificarea acestui lucru se poate face prin markSupported().
3. Filtre
Exista clase in pachetul java.io care nu sunt utilizate pentru operatiile efective de
citire si scriere, ci ne ofera o serie de metode pentru a scrie si citi diferite tipuri de
date. Aceste clase alcatuiesc un nivel superior si intotdeauna se combina cu cate o
clasa care creaza canalul de comunicatie . Clasele DataInputStream respectiv
DataOutputStream sunt clase care definesc o serie de astfel de metode. De exemplu
clasa DataInputStream contine si urmatoarele metode:
short readShort();
int readInt();
long
readLong();
float readFloat();
double readDouble();
4. Fisiere
Clasele FileInputStream, FileOutputStream, FileReader, FileWriter
La capetele unui canal de comunicatie putem sa avem si fisiere. In acest caz operatiile
I/E vor afecta fisierele. Daca dorim sa citim din fisiere atunci in functie de tipul
fisierului vom utiliza clasele FileInputStream respectiv FileReader (fisier binar sau
fisier text). Pentru scriere se vor utiliza clasele FileOutputStream respectiv
FileWriter. Pentru a deschide un fisier pentru scriere sau citire se creaza un nou obiect
din clasele amintite mai in sus. La crearea obiectului se va apela unul din constructorii
clasei corespunzatoare. Acest constructor poate sa primeasca ca parametru numele
fisierului sau un obiect de tip File sau unul de tip FileDescriptor.
Exemplul urmator afiseaza continutul unui fisier text pe terminal. utilizand un obiect
de tip FileReader. Numele fisiereului de listat se primeste de la linia de comanda.
import java.io.*;
public class Cat{
public static void main( String args[]){
FileReader fr = null;
int b = 0;
if( args.length !=1 ){
System.out.println("Utilizare: java Cat <nume_fisier_text>");
System.exit(1);
}
try{
fr = new FileReader( args[0] );
while( ( b =fr.read()) != -1 )
System.out.print( (char) b );
}
catch( FileNotFoundException e ){
System.out.println("Fisier inexistent");
System.exit(2);
}
catch( IOException e ){
System.out.println("Eroare de citire");
System.exit(3);
}
}
}
Daca dorim sa citim linii intregi din fisier in loc de caractere va trebui sa utilizam
clasa BufferedReader care defineste metoda readLine(). Constructorul clasei
BufferedReader primeste ca parametru un obiect de tip FileReader, care in prealabil
trebuie creat.
try{
fr = new FileReader( args[0] );
BufferedReader br = new BufferedReader( fr );
String line;
while( ( line =br.readLine()) != null )
System.out.println( line );
}
catch( FileNotFoundException e ){
System.out.println("Fisier inexistent");
System.exit(2);
}
catch( IOException e ){
System.out.println("Eroare de ccitire");
System.exit(3);
}
}
}
Generalizare:
Modificam exemplul precedent a.i. daca nu primeste nici un argument de la linia de
comanda atunci copieaza intrarea standard la iesirea standard, iar daca primeste mai
multe argumente, le afiseaza pe toate.
import java.io.*;
Forme de utilizare:
1. java cat
2. java cat fisier1 fisier2 ...
Copiere de fisiere:
import java.io.*;
public class CopiereFisiere{
static FileInputStream fis;
static FileOutputStream fos;
public static void copiere ( InputStream sin, OutputStream sout) throws
IOException{
byte b[]= new byte[1024];
int bytesRead;
while(( bytesRead =sin.read(b)) >0) sout.write(b);
sout.flush();
}
Clasa File
Clasa File contine informatii despre fisiere si directoare si defineste o serie de metode
pentru a obtine respectiv a modifica aceste informatii.. Principalele metode sunt
urmatoarele:
Metoda
Tipul returnat
Descriere
canRead()
boolean
Are permisiunea de citire?
canWrite()
boolean
Are permisiunea de scriere?
delete()
boolean
Stergere
exists()
boolean
Exista fisierul?
getAbsolutePath() String
Calea completa spre fisier
getCanonicalPath() String
Calea completa spre fisier
getName()
String
Numele fisierului
getParent()
String
Numele catalogului parinte
getPath()
String
Calea spre fisier
isAbsolute()
boolean
Este un nume absolut?
isDirectory()
isFile()
lastModified()
length()
list()
mkdir()
mkdirs()
boolean
boolean
long
long
String[]
booolean
boolean
Este un director?
Este un fisier ordinar?
Data ultimei modificari
Lungimea fisierului
Lista fisierelor din director
Crearea de director
Crearea tuturor directoarelor
Clasa RandomAccessFile
Aceasta clasa implementeaza atat interfata DataInput cat si interfata DataOutput astfel
permitand citirea si scrierea datelor primitive Java cat si a sirurilor de caractere. Clasa
permite accesul direct al fisierului. Clasele cu care am lucrat pana acum au permis
doar accesul secvential. Crearea unui obiect de tip RandomAccessFile se face in
modul urmator:
try{
RandomaccessFile file = new randomAccessFile("unfisier","rw");
...
}
catch( IOException e){
}
name;
dim;
= dim;
}
catch( IOException e ){
System.out.println("Eroare IO ");
}
}
}
5. Conducte
In mod normal aplicatia utilizeaza un stream de scriere sau una de citire la un moment
dat. Clasele PipedInputStream si PipedOutputStream (respectiv PipedReader si
PipedWriter) ne ajuta la crearea mecanismului de conducta care se poate utiliza de
catre o aplicatie care se ruleaza pe mai multe fire de executie. Firele de executie
comunica intre ele cu ajutorul acestui mecanism. Exemplul urmator va fi o aplicatie
care se ruleaza pe doua fire de executie. Primul fir produce mesaje pe care le scrie
intr-o conducta, in cazul nostru mesajul va fi format din data si ora curenta a
sau invers
PipedOutputStream pout = new PipedOutputStream();
PipedInputStream pin = new PipedInputStream( pout );
Exemplu pentru utilizarea conductelor:
Diagrama de colaborare:
Diagrama de clase:
Sursa Java:
//Source file: Control.java
import java.io.PipedWriter;
import java.io.PipedReader;
public class ThreadA extends Thread
{
public PipedWriter pipewrite;
public PipedReader piperead;
}
catch( java.io.IOException e ) {}
}
public void run()
{
java.io.PrintWriter ptw = new java.io.PrintWriter( pipewrite );
while( true ){
String s = ( new java.util.Date().toString());
ptw.println( s );
System.out.println(getName()+" "+s+": has been written in
pipe");
try{
sleep(1000);
}
catch( InterruptedException e ){}
}
}
}
//Source file: ThreadB.java
import java.io.PipedReader;
public class ThreadB extends Thread
{
public PipedReader piperead;
adresa server
portul server utilizat pentru comunicare
protocolul de comunicatie utilizat de server
parte server care primeste cererile si raspunde la acestea. Clientul intotdeauna creaza
un soclu pentru a initia conversatia si trebuie sa cunoasca serverul caruia adreseaza
cererea, iar serverul trebuie sa fie pregatit pentru a receptiona aceste cereri. In
momentul receptionarii mesajului creaza un soclu pe partea serverului, soclu care va
facilita deservirea clientului. Atat pe partea de client cat si pe partea de server se
utilizeaza cate un obiect de tip Socketpentru comunicare. Pe partea de server mai
trebuie sa cream un obiect de tip ServerSocket, care are sarcina primirii conexiunilor
si acceptarea acestora.
Clientul trebuie sa cunoasca doua lucruri despre server: numele serverului (utilizat
pentru determinarea adresei IP al serverului) si numarul portului la care acesta asculta
cererile clientilor. Acelasi calculator gazda poate oferi mai multe servicii, deci poate
gazdui mai multe procese de tip server. De exemplu poate fi server Mail, server FTP,
server HTTP, dar aceste aplicatii lucreaza cu diferite porturi, deci cererile adresate
acestor serveri vor fi receptionate pe diferite porturi.
Privind modalitatea de deservire a clientilor serverul prin constructie poate fi server
paralel (concurent) si server secvential.
ServerSocket(int port)
Creaza un soclu server pe portul specificat.
ServerSocket(int port, int backlog)
Creaza un soclu server pe portul specificat. Al doilea parametru indica
lungimea cozii de asteptare.
Metode principale:
Socket accept()
Asculta conexiunile si le accepta.
void close()
Inchide soclul.
InetAddress getInetAddress()
Returneaza adresa locala al soclului server.
int getLocalPort()
Returneaza portul la care serverul asteapta conexiunile.
Exemplu 1.
Urmatoarea aplicatie este formata dintr-o parte client si una server. Clientul va trimite
un sir de caractere serverului, iar serverul il va trimite inapoi convertit in majuscule.
Pentru rezolvarea acestei probleme construim doua pachete:
{
System.out.println( "Server error ");
}
}
}
//Source file: c:\Rose\ClientServer\ServerPackage\ClientHandle.java
package ServerPackage;
import java.net.Socket;
import java.net.SocketException;
public class ClientHandle extends Thread
{
Socket client;
public ClientHandle(Socket client) throws SocketException
{
this.client = client;
}
public void run()
{
try{
java.io.InputStream
in
= client.getInputStream();
= new java.io.BufferedReader(
new java.io.InputStreamReader( in));
java.io.PrintWriter
}
}
Partea de client:
java.io.InputStreamReader(s.getInputStream()));
java.io.PrintWriter
out = new java.io.PrintWriter(
s.getOutputStream() );
out.println( message ); out.flush();
System.out.println("Answer from the server: "+in.readLine() );
s.close();
}
catch( java.io.IOException
e )
{
System.out.println( "I/O error "+e );
}
}
= args[ 2 ];
try{
hostport =Integer.parseInt( args[ 1 ] );
}
catch( NumberFormatException e )
{
hostport = 1024;
}
Client c = new Client( hostname, hostport, message );
}
}
Exemplu 2
Urmatoarea aplicatie va fi un server web. Aplicatia se va rula pe un fir de executie cu
prioritatea mai mica decat cea normala si va rezolva cererile HTTP. Vom proiecta
aplicatia a.i. sa aiba o arhitectura paralela si sa rezolve cererile de tip GET
nume_fisier.Arhitectura paralela permite deservirea concomitenta a mai multor
clienti.
import java.io.*;
import java.net.*;
import java.util.*;
out.write(data);
out.flush();
}
catch( FileNotFoundException e ){
pout.println(e.toString());
}
}
else{
pout.println("400 Bad request");
}
client.close();
}
catch( IOException e )
{
System.out.println(e.toString());
}
}
}
Utilizarea aplicatiei:
Aplicatia de mai sus se utilizeaza in modul urmator. Prima data se compileaza si dupa
aceea se executa cu comanda:
java TinyHttpd 1234.
Numarul 1234 reprezinta portul la care serverul asteapta cererile. Dupa ce serverul
este lansat in executie, dintr-un program de navigare (browser) se formuleaza o cerere
de forma:http://127.0.0.1:1234/Index.html, daca exista in catalogul aplicatiei
TyniHttpd fisierul Index.html si daca clientul si serverul se ruleaza pe acelasi
calculator. 127.0.0.1 este adresa IP al localhost-ului. Daca aplicatia se ruleaza pe un
calculator cu numele unu.doi.com atunci in locul adresei 127.0.0.1 se pune
unu.doi.com.
Descrierea aplicatiei:
Aplicatia defineste doua clase. O clasa care rezolva o cerere pe un fir de executie,
TinyHttpdConnection si o clasa TinyHttpd care creaza soclul server si intra in
asteptarea clientilor. In momentul aparitiei unui client ( accept()) se creaza un nou fir
de executie caruia se transmite referinta la soclul returnat de catre accept(). Aceasta
referinta la soclu permite firului de executie sa extraga de aici fluxurile de intrare si de
iesire prin care se realizeaza comunicarea efectiva. Firul de executie extrage din flux
cu ajurorul unor operatii pe siruri de caractere, numele fisierului cerut. Daca exista
fisierul, acesta se deschide pentru citire si datele citite vor fi scrise in soclu pentru
a putea fi extrase si de catre client.
Seteaza adresa.
setData(byte[] buf)
Seteaza bufferul pentru pachet
setData(byte[] buf, int offset, int length)
Seteaza bufferyl pentru pachet
setLength(int length)
Seteaza lungimea pachetului.
setPort(int iport)
Seteaza portul..
Clasa DatagramSocket
Constructori:
DatagramSocket()
Construieste un soclu si leaga la un port liber pe calculatorul local.
DatagramSocket(int port)
Construieste un soclu si leaga la un portul specificat pe calculatorul local.
Aplicatia este formata dintr-o parte client si una server. Clientul este un aplet, iar
serverul o aplicatie.
Partea de client:
Fisierul HTML:
<applet HEIGHT=10 WIDTH=10 CODE=MessageApplet.class>
<param NAME="PORT" VALUE="1234"></applet>
Dupa ce avem pachetul gata, pregatit pentru trimitere, mai trebuie sa cream un soclu
prin care sa se trimita si putem expedia pachetul cu metoda send(). Dupa epedierea
pachetului se va inchide soclul.
DatagramSocket ds = new DatagramSocket();
//Crearea soclu
ds.send( packet );
//Trimitere pachet
ds. close();
//Inchidere soclu
Partea server:
import java.net.*;
import java.io.*;
Partea de server:
4. URL
URL (Uniform Resource Locator) identifica o resursa(obiect) pe Internet. In mod
uzual este format din trei sau patru parti:
protocol://hostname/nume_resursa sau
protocol://hostname:port/nume_resursa
Exemplu de utilizare:
try{
URL url = new URL("http","www.uttgm.ro",3128, "index.html");
System.out.println( url.toString());
}
catch( MalformedException e ){
//Se trateaza exceptia
}
Un aplet poate comunica doar cu calculatorul pe care este stocat codul lui. Cu
ajutorul metodei getDocumentBase() a clasei Applet putem afla numele acestui
calculator si dupa acea putem cere accesul la o resursa de pe acel calculator:
try{
URL url = new URL("http",getDocumentBase(),"index.html");
System.out.println( url.toString());
}
catch( MalformedException e ){
//Se trateaza exceptia
}
Daca dorim sa aducem datele asociate unui URL trebuie sa cerem obiectului URL
referinta la un stream atasat acestuia. Referinta se obtine prin apelul
metodei openStream(). Exemplul urmator afiseaza pe terminal continutul unui fisier
HTML.
try{
URL url = new URL("http://www.uttgm.ro/index.html");
BufferedReader bin = new BufferedReader( new
InputStreamReader(url.openStream()));
String line;
while( ( line = bin.readLine()) != null )
System.out.println( line );
}
catch (Exception e ){}
Exemplu cu URL:
Sa se scrie un aplet care permite utilizatorilor vizualizarea produselor unei firme. Din
cauza ca preturile sunt in continua schimbare acestea se stocheaza intr-un
fisier "preturi.dat", aflat in acelasi catalog cu codul apletului, precum si cu fisierul
HTML. In caz ca se schimba preturile produselor, apletul ramane neschimat, doar
fisierul "preturi.dat" se va modifica.
Cand clientul viziteaza pagina Web, browserul incarca prima data fisierul HTML, pe
urma codul apletului. Apletul este rulat pe calculatorul clientului, acesta incarcand
fisierul "preturi.dat". Pentru a incarca fisierul "preturi.dat", apletul creaza un URL:
try{
URL url = new URL( getDocumentBase(),"preturi.dat");
}
catch( Exception e ){}
Lista de preturi este formatat a.i sa fie ptrivit pentru a fi incarcat intr-un
obiect Properties:
Mere=7000
Pere=10000
Struguri=25000
Basnana=27000
Interfata apletului:
Diagrama de clasa:
Diagrama de secventiere:
Codul sursa:
//Source file: Linie_de_comanda.java
public class Linie_de_comanda
{
private String nume;
private int cantitate;
private double pretunitar;
public Linie_de_comanda(String nume, int cantitate, double pretunitar)
{
this.nume= nume;
this.cantitate = cantitate;
this.pretunitar = pretunitar;
}
public String toString()
{
String s2 = Integer.toString( cantitate );
String s3 = Double.toString( pretunitar );
return nume+" : "+s2+" : "+s3;
}
}
//Source file: CanvasComanda.java
import java.awt.Canvas;
import java.util.Vector;
import java.awt.Graphics;
public class CanvasComanda extends Canvas
{
private Vector a;
public void redraw(java.util.Vector a)
{
this.a =a;
repaint();
}
public void paint(Graphics g)
{
int i;
int x=80, y=0;
java.awt.Font f = new java.awt.Font("Monospaced",java.awt.Font.PLAIN, 12
);
g.setFont( f );
java.awt.FontMetrics fm = g.getFontMetrics( f );
int height = fm.getHeight();
y+=height;
g.drawString("Your order: ",x,y);
for( i = 0; i<a.size(); i++ )
{
y+=height;
g.drawString( a.elementAt(i).toString(), x, y );
}
}
}
//Source file: ApletComanda.java
import java.applet.Applet;
import java.awt.event.ActionListener;
import java.awt.Choice;
import java.awt.TextField;
import java.awt.Button;
import java.util.Properties;
import java.util.Vector;
import java.awt.event.ActionEvent;
JDBC este bazat pe doua standarde: SQL (Structured Query Language) si CLI
(X/Open Call Level Interface). CLI este implementat in interfata Microsoft ODBC.
ODBC a fost implementat in limbajul C, deci nu se putea utiliza direct din Java
deoarece s-ar fi stricat portabilitatea acestor aplicatii. O alta problema cu ODBC era
ca fiind scris intr-un limbaj procedural in care caramida de constructie este functia era
mai greu atasarea la Java, care este un limbaj obiectual. Multe functii C din
ODBC returneaza si pointeri void care violeaza caracteristica fundamentala a
limbajului Java, siguranta tipului.
2. Arhitectura JDBC
Interfetele si clasele pentru JDBC se gasesc in pachetul java.sql. Clasele si interfetele
utilizate intr-o aplicatie ce utilizeaza JDBC se gasesc pe figura urmatoare:
O aplicatie JDBC utilizeaza unul sau mai multe drivere din pachetul java.sql care sunt
utilizate de catre clasa DriverManager. Driverele sunt specifice bazelor de date, deci
pentru fiecare tip de baza de date se utilizeaza un driver special. In aceeasi aplicatie
putem lucra cu baze de date diferite, deci implicit si cu mai multe drivere. Putem avea
4. Utilizare JDBC-Exemple
Sursa Java:
import java.sql.*;
public class SimpleJDBC{
public static void main( String args[]){
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String databaseName = "jdbc:odbc:Inventory";
Connection
con
=DriverManager.getConnection(databaseName,"username","password");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from
Inventory");
while( rs.next()){
System.out.println(rs.getString(1)+":"+rs.get
Float(2));
}
}
catch( Exception e ){
e.printStackTrace();
}
}
}
accesul la baze de date utilizate sub s.o. Windows. In exemplul precedent aplicatia
noastra acceseaza direct baza de date. Asemenea aplicatii se numesc aplicatii cu doua
nivele. Intr-o abordare eleganta aplicatiile sunt proiectate pe trei nivele. In cazul
acestor aplicatii clientul lucreaza cu un server care reprezinta un nivel intermediar
intre client si baza de date.
Urmatorul exemplu va lucra cu o baza de date Access continand doua tabele.
Nume baza de date: Universitate.mdb
Nume tabel 1: Catedre
Structura:
CODCATEDRA
Long
DENUMIRE
Text
Indexari: CODCATEDRA
(cheie primara)
Long
NUME
Text
CODCATEDRA
Long
Indexari: CODPROFESOR
import java.sql.*;
public class SimpleJDBC{
public static void main( String args[]){
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String databaseName = "jdbc:odbc:Universitate";
Connection con =
DriverManager.getConnection(databaseName,"username","password");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select
Profesori.codprofesor,Profesori.nume,Profesori.codcatedra,Catedre.nume from
Catedre,Profesori where Catedre.codcatedra=Profesori.codcatedra order by
catedre.nume");
while( rs.next()){
System.out.println(rs.getLong(1)+":"+rs.getSt
ring(2)+":"+rs.getLong(3)+":"+rs.getString(4));
}
}
catch( Exception e ){
e.printStackTrace();
}
}
}
Prin apelul acestor metode se va incarca un driver JDBC. In clasa specifica driverului
esista o metoda statica care va inregistra existenta sa cu DriverManager. Dupa
incarcarea driverului trebuie creata legatura cu baza de date. Se ridica o serie de
probleme:
d. Prelucrarea rezultatelor
ResultSet este tot o interfata. Obiectul ResultSet contine rezultatul interogarii bazei de
date, insa pointerul atasat acestei tabele puncteaza inaintea primului rand din tabela.
Acest lucru ne este comod fiindca cu un singur ciclu while putem parcurge rezultatele
obtinute:
while( rs.next()){
System.out.println( rs.getString(1)+":"+rs.getFloat(2));
}
Daca rezultatul interogarii este vid atunci constructia de mai sus va genera
exceptie SQLException.
ResultSet contine metode pentru accesul datelor din rezultat. Astfel
metodele getXXX(int) si getXXX(String) returneaza valoarea dintr-o coloana
specificata prin parametru si linia curenta. In locul XXX se pune un tip predfinit Java
(tip primitiv-ex. int sau clasa de baza-ex. String).
Tip SQL
CHAR
VARCHAR
LONGVARCHAR
NUMERIC
DECIMAL
BIT
TINYINT
SMALLINT
INTEGER
BIGINT
REAL
DOUBLE
BINARY
VARBINARY
LONGVARBINARY
DATE
TIME
TIMESTAMP
Tip JAVA
String
String
String
java.math.BigDecimal
java.math.BigDecimal
boolean
byte
short
int
lonng
float
double
byte[]
byte[]
byte[]
java.sql.Date
java.sql.Time
java.sql.Timestamp
Metoda
getString()
getString()
getString()
getBigDecimal()
getBigDecimal()
getBoolean()
getByte()
getShort()
getInt()
getLong()
getFloat()
getDouble()
getBytes()
getBytes()
getBytes()
getDate()
getTime()
getTimestamp()
} catch (Exception e) {
e.printStackTrace();
}
}
}
8. Instructiuni preparate
In cazul aplicatiilor care lucreaza cu baze de date este foarte frecventa utilizarea
aceluiasi cod SQL de mai multe ori. RDBMS-urile faciliteaza crearea instructiunilor
preparate, care trebuie create, analizte si optimizate o singura data in baza de date si
dupa aceea pot fi utilizate in aplicatii. JDBC faciliteaza utilizarea instructiunilor
preparate prin clasa PreparedStatement. Aceasta clasa este subclasa clasei
Statement. Clasa PreparedStatement are un constructor care primeste ca parametru un
string reprezentand instructiunea SQL.
PreparedStatement pstmt = con.preparedStatement("SELECT
quantity FROM Inventory WHERE ingredient=?";
Se poate observa ca instructiunea SQL contine si semne de intrebare. Aceste semne de
intrebari reprezinta parametrii interogarii. Inainte de executia propriu-zisa a codului
acesti parametrii pot fi setati. In exemplul precedent am utilizat o
metoda checkInventory( Vector ingredients ) pentru a afla daca din fiecare materie
prima avem cantitatile dorite.
Enumeration e =ingredients.elements();
while( e.hasMoreElements()){
InventoryItem i = (InventoryItem) e.nextElement();
ResultSet rs = stmt.executeQuery( "SELECT quantity FROM Inventory WHERE
ingredient =' " + i.item+" ' ");
rs.next();
if( rs.getFloat(1) < i.amount )
return false;
}
return true;
In acest exemplu pentru fiecare materie prima din vectorul ingredients s-a executat
cate o instructiune SQL, timpul de executie astfel devenind foarte mare. Vom rescrie
aceasta metoda utilizand un obiect de tip PreparedStatement facand ca aplicatia sa
devina mai eficienta.
PreparedStatement pStmt = con.prepareStatement("SELECT Quantity FROM
Inventory WHERE Ingredient =?");
Enumeration e =ingredients.elements();
while( e.hasMoreElements()){
InventoryItem i = (InventoryItem) e.nextElement();
pStmt.setString(1,i.item);
ResultSet rs = stmt.executeQuery();
rs.next();
if( rs.getFloat(1) < i.amount )
return false;
}
return true;
Astfel codul SQL se compileaza o singura data pe partea de baza de date si la fiecare
apel executeQuery() se va executa acel cod precompilat cu parametrii
inlocuiti.Parametrii interogarii sunt setati de catre metodele setXXX() ale
clasei ResultSet. Primul parametru al acestor metode este numarul de ordine al
parametrului din secventa SQL care se inlocuieste, iar al doilea parametru este
valoarea cu care se inlocuieste.
9. Conversie SQL-Java
Tip Java
Java.math.BigDecimal
boolean
byte
short
int
long
float
double
byte[]
java.sql.Date
java.sql.Time
java.sql.Timestamp
String
Tip SQL
NUMERIC
BIT
TINYINT
SMALLINT
INTEGER
BIGINT
REAL
DOUBLE
VARBINARY sau LONGVARBINARY
DATE
TIME
TIMESTAMP
VARCHAR sau LONGVARCHAR
Metoda
setBigDecimal()
setBoolean()
setByte()
setShort()
setInt()
setLong()
setFloat()
setDouble()
setBytes()
setDate()
setTime()
setTIMESTAMP()
setString()
camp de date intr-o baza de date, iar dupa aceea va citi un alt camp de date salvand
rezultatul intr-un fisier. Exemplul nostru va stoca imagini de tip .gif. Ca prim pas vom
crea cu Microsoft Access o baza de date cu urnatoarea structura:
Imagini.mdb cu tabela imagini:
Nume_Camp
COD
NUME
IMAGINE
Tip_Camp
Numeric(10)
Text(30)
OLE Object
Dupa crearea bazei de date sursa de date trebuie sa fie facuta public prin intermediul
ODBC.
Datele in aceasta tabela vor fi introduse de catre program.
Nume clasa: JDBCImages
Date:
-databaseName: String
-con: Connection
-pictures: String[5]
-pStmt1, pStmt2: PreparedStatement
Metode:
+JDBCImages()
+writeRecord( int cod )
+readRecord( int cod, String fileName)
Sursa Java:
import java.io.*;
import java.sql.*;
public class JDBCImages{
String databaseName = "jdbc:odbc:Imagini";
Connection con = null;
String pictures[]={"curs2_fig1.gif","curs2_fig2.gif",
"curs2_fig3.gif","curs2_fig4.gif", "curs2_fig5.gif"};
PreparedStatement pStmt1 = null;
PreparedStatement pStmt2 = null;
public JDBCImages(){
// Incarcare driver - Creare conexiune
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con = DriverManager.getConnection(databaseName,"","");
pStmt1 = con.prepareStatement("INSERT INTO imagini
(cod,nume,imagine) VALUES
(?,?,?)");
pStmt2 = con.prepareStatement("SELECT
imagini WHERE cod=?");
imagine
FROM
}
catch( Exception e ){
System.out.println("Eroare constructor");
e.printStackTrace();
}
}
public void writeRecord( int cod )
{
try{
File inFile = new File( pictures[ cod ] );
int flength = (int) inFile.length();
FileInputStream in = new FileInputStream( inFile );
pStmt1.setInt(1,cod);
pStmt1.setString(2,pictures[cod]);
pStmt1.setBinaryStream(3,in,flength);
pStmt1.executeUpdate();
}
catch( Exception e ){
System.out.println("Eroare INSERT");
e.printStackTrace();
}
}
public void readRecord( int cod, String fileName )
{
byte [] picture = new byte[ 1024 ];
try{
pStmt2.setInt(1,cod);
File outFile = new File(fileName);
FileOutputStream out = new FileOutputStream( outFile );
ResultSet rs = pStmt2.executeQuery();
rs.next();
ResultSet-uri derulabile
Metoda
boolean
boolean
boolean
boolean
boolean
boolean
)
Rezultat
first()
Pozitionarea indicatorului pe prima linie
previous()
Pozitionarea indicatorului pe linia precedenta
next()
Pozitionarea indicatorului pe prima urmatoare
last()
Pozitionarea indicatorului pe ultima linie
absolute( int poz )
Pozitionarea indicatorului pe poztia indicata
relative ( int pozitie_relativa Pozitionarea indicatorului relativ la pozitia
curenta
Tipuri de date SQL 3.0. Obiectele Java pot fi stocate in baze de date.
11. Exemple:
1. Sa scrie o aplicatie care sa permita interogarea oricarei baze de date. Rezultatele
selectiei se vor afisa intr-un element de control TextArea. Interfata aplicatiei sa aiba
urmatoarea forma:
Sursa Java:
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
= null;
TextField tfDriver;
TextField tfDataBase;
TextField tfUserName;
TextField tfPassword;
TextField tfSQL;
Button b;
TextArea
ta;
=new TextField(60);
add(tfSQL);
b= new Button( "Executa");
add(b);
b.addActionListener( this);
ta= new TextArea( 10,60);
add(ta);
addWindowListener( new MyWindowAdapter());
}
//Prelucrarea datelor din formularul prezentat in interfata
aplicatiei
private void processData(){
Driver = tfDriver.getText();
if( Driver.equals(""))
Driver="sun.jdbc.odbc.JdbcOdbcDriver";
DataBase =tfDataBase.getText();
if( DataBase.equals(""))
DataBase="jdbc:odbc:Demo";
UserName = tfUserName.getText();
Password = tfPassword.getText();
SQL = tfSQL.getText();
if ( SQL.equals(""))
SQL="Select * From Catedre";
}
stmt= con.createStatement();
rs = stmt.executeQuery( SQL );
case Types.TIME:
java.sql.Time time = rs.getTime(col);
return time.toString();
case Types.TIMESTAMP:
java.sql.Timestamp timestamp = rs.getTimestamp(col);
return timestamp.toString();
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
String str = rs.getString(col);
return str;
case Types.NUMERIC:
case Types.DECIMAL:
java.math.BigDecimal numeric = rs.getBigDecimal(col, 10);
return numeric.toString();
case Types.BIT:
boolean bit = rs.getBoolean(col);
return (new Boolean(bit)).toString();
case Types.TINYINT:
byte tinyint = rs.getByte(col);
return (new Integer(tinyint)).toString();
case Types.SMALLINT:
short smallint = rs.getShort(col);
return (new Integer(smallint)).toString();
case Types.INTEGER:
int integer = rs.getInt(col);
return (new Integer(integer)).toString();
case Types.BIGINT:
long bigint = rs.getLong(col);
return (new Long(bigint)).toString();
case Types.REAL:
float real = rs.getFloat(col);
return (new Float(real)).toString();
case Types.FLOAT:
case Types.DOUBLE:
1.
2.
3.
4.
5.
Introducere
Anatomia unui servlet HTTP
Instalarea servletului in WebServer
Arhitectura pachetelor javax.servlet si javax.servlet.http
Exemple
1. Introducere
Webul a trecut printr-o transformare rapida. Paginile statice HTML au fost schimbate
cu pagini generate in mod dinamic. Avantajul acestor pagini este ca informatia
continuta in ele poate reflecta de exemplu continutul unei magazii cu stocul in
continua schimbare. Crearea acestor pagini necesita insa multa munca de programare.
Java cu ajutorul apleturilor ajuta la crearea aplicatiilor pe partea clientilor. Pe partea
serverelor s-au introdus servleturile. Servletul este un mecanism de generarea acestor
pagini dinamice HTML, oferind deservirea rapida si eficienta a clientilor.
Inaintea servleturilor partea de server a aplicatiilor client/server era ajutata de
scripturi CGI (Common Gateway Interface). CGI permitea si evaluarea formularelor
trimise de catre clienti.
Comparatie CGI - Servlet
Scripturile CGI sunt mai putin eficiente decat servleturile. In cazul utilizarii CGI
pentru deservirea unui client se creaza un proces nou in care se executa scriptul CGI.
Scriptul genereaza pagina HTML si trimite clientului. Crearea unui proces nou este o
operatie costisitoare din punctul de vedere al sistemului de opearare.
Servletul face acelasi lucru ca un script CGI, insa servletul se ruleaza pe un fir de
executie separat al procesului webserver. Crearea unui fir de executie este mult mai
eficienta decat crearea unui proces nou. Pe langa eficienta servleturile mai au o
caracteristica impotantanta, securitatea. Firele de executie sunt create de catre masina
virtuala Java si poseda toate facilitatiile oferite de aceasta din punctul de vedere al
securitatii.
Exemplul urmator de servlet:genereaza in mod dinamic o pagina HTML care contine
data si ora serverului si un text aleator.
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.Date;
import java.lang.Math;
public class PhraseServlet extends HttpServlet {
String [] adjective = {"fericit",
"nefericit",
"suparat",
"nervos",
"indurerat"};
String [] adverbe = {"foarte",
"usor",
"putin",
"total"};
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
Date now = new Date();
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<HTML><HEAD><TITLE>Phrase Servlet</TITLE></HEAD>");
out.println("<BODY BGCOLOR=#FFFFFF><CENTER><P>");
out.println("Astazi ");
out.println(now.toString());
");
Aici vom introduce atat la nume cat si la parola cuvantul "admin". Dupa logare apare
urmatoarea pagina:
Din lista se alege "Web Service" si se apasa butonul "Manage". Dupa alegerea acestui
buton apare urmatoarea pagina:
In aceasta pagina se completeaza casetele Description si Class Name asa cum se vede
pe figura de dinainte. Alegand optiunea Load at Startup servletul se va incarca la
fiecare pornire al webserverului. Dupa completarea casetelor se alege butonul Save
pentru a salva optiunile selectate. Dupa aceste reglaje servletul nostru poate accesat la
adresa: http://<nume_calculator>:<port>/servlet/PhraseServlet.
Putem atasa si aliasuri servletului nostru. Aliasul se ataseaza prin alegerea
butonului Setup din bara de instrumente. Apare pagina urmatoare:
Completand casetele Alias si Servlet Invoked si salvand optiunile vom putea accesa
servletul nostru la adresa: http://<nume_calculator>:<port>/PhraseServlet.html.
Daca serverul rezolva concomitent doua cereri de acelasi tip, atunci trebuie apelat
acelasi servlet. Servleturile sunt rulate pe fire de executie diferite, fiecare avand cate o
copie de ServletRequest si ServletResponse, astfel neputand amesteca parametrii I/E.
Serverele pot avea o arhitectura secventiala sau una paralela. Daca dorim sa
implementam una cu arhitectura secventiala atunci servletul trebuie definit a.i. sa
implementeze interfata SingleThreadModel.
public class MyServlet extends HttpServlet implements SingleThreadModel{
}
Java Webserver este un server de capacitate medie, deci se poate utiliza in cazul
serverelor care nu sunt prea frecvent utilizate. Exista si alte webservere care lucreaza
cu servleturi: Netscape Enterprise Server, Microsoft IIS, Apache Web Server
Interfata ServletResponse declara metode prin care servletul poate trimite raspunsuri
la cererile clientilor.
Interactiuni cu clientii
Un servlet HTTP trateaza cererile clientilor cu ajutorul metodei service(). Metoda
service() este cea care apeleaza metoda doGet() pentru prelucrarea cererii.
Cereri si raspunsuri
Tratarea cererilor GET si POST se face cu ajutorul urmatoarelor metode:
doGet, pentru tratarea cererilor GET, GET conditionat si HEAD
doPost, pentru tratarea cererilor POST
doPut, pentru tratarea cererilor PUT
doDelete, pentru tratarea cererilor DELETE
Implicit aceste metode returneaza eroarea BAD_REQUEST (400) afisata de catre
aplicatia client (programul de navigare).
Deservirea clientilor
Servleturile sunt capabile pentru deservirea clientilor in mod concurent. Daca
deservirea clientilor necesita accesul unor resurse partajate atunci accesul acestor
resurse trebuie sincronizate.
Daca dorim deservirea unui singur client la un moment dat, atunci servletul nostru
trebuie sa implementeze interfata SingleThreadModel pe langa extinderea
clasei HttpServlet. Implementarea acestei interfete nu necesita scrierea unor metode
suplimentare, asigura deservirea unui singur client la un moment dat.
public class MyServlet extends HttpServlet
implements SingleThreadModel {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
...
}
...
}
Prelucrarea cererii
Metode clasei HttpServletRequest
Enumeration getParameterNames(),
continute in pagina
Exemplu:
void doGet (HttpServletRequest req, HttpServletResponse res){
String nume, valoare;
String[] params = req.getParameterNames();
while (params.hasMoreElements()) {
nume
= (String) params.nextElement();
valoare = req.getParameter(nume);
//Prelucrarea parametrului
}
//
}
numele specificat
Exemplu:
<INPUT NAME="Nume" SIZE=30></INPUT>, defineste un camp text care
permite introducerea unui text de lungime maxima 30. Obtinerea valorii introduse in
acest camp text se poate obtine prin req.getParameter("Nume").
.
nume),
BufferedReader getReader(),
ServletInputStream getInputStream(),
Observatie:
In prelucrarea unei cereri nu se poate utiliza concomitent metodele de tip
getParameter si metodele getReader si getInputStream.
Trimiterea raspunsului
Un obiect HttpServletResponse pune la dispozitie doua cai pentru trimiterea
datelor catre client:
Writer getWriter()
ServletOutputStream getOutputStream()
Servleturi de baza
Java Webserver este implementat cu ajutorul servleturilor de baza. In primul
exemplu fara sa stim am utilizat deja servletul de baza invoker la incaracarea
servletului PhraseServlet. Un alt servlet de baza este ssinclude. Acest tip de servlet se
utilizeaza pentru pagini HTML cu includeri pe partea serverului (.shtml).
Urmatorul exemplu servlet primeste intrarea dintr-o pagina HTML care contine
si un formular si utlizeaza aceste date pentru generarea raspunsului. Raspunsul va fi
tot o pagina HTML.
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class FormServlet extends HttpServlet
{
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException
{
PrintWriter out = null;
try {
res.setContentType("text/html");
out = res.getWriter();
out.println(
"<HTML><HEAD><TITLE>FormServlet output</TITLE></HEAD>");
out.println("<BODY BGCOLOR=#FFFFFF><P>");
Exemplul precedent trebuie facut public in Java Webserver, iar dupa aceea vom scrie
un mic fisier HTML care sa contina formularul si la apasarea butonului sa trimita
rezultatele din formular servletului.
<HEAD>
<TITLE>sURVEY</TITLE>
</HEAD>
<BODY>
<FORM method=POST ACTION="/servlet/FormServlet" >
<BR><BR>Cum va simtiti astazi?<BR>
<BR><input type=text name=emotion>
<BR><BR>In care dintre urmatoarele zile sunteti fericit?<BR>
<BR>Luni<INPUT TYPE=checkbox NAME=days VALUE=Luni>
<BR>Marti<INPUT TYPE=checkbox NAME=days VALUE=Marti>
<BR>Miercuri<INPUT TYPE=checkbox NAME=days VALUE=Miercuri>
<BR>Joi<INPUT TYPE=checkbox NAME=days VALUE=Joi>
<BR>Vineri<INPUT TYPE=checkbox NAME=days VALUE=Vineri>
<BR>Sambata<INPUT TYPE=checkbox NAME=days VALUE=Sambata>
<BR>Duminica<INPUT TYPE=checkbox NAME=days VALUE=Duminica>
<BR><BR><INPUT TYPE=submit><INPUT TYPE=reset>
</FORM>
</BODY>
</HTML>
Apleturi
1.
2.
3.
4.
5.
1. Creare si executie
Un apleteste un program mic care nu se executa sinestatator ci este nevoie de o
altaaplicatie pentru a-l executa. In general apleturile sunt executatede
catrenavigatoare. Clasa Applet este definita in pachetul java.applet impreuna
cualte interfete necesare pentru a realiza comunicatia intre aplet simediul sau de
executie. Un aplet este de fapt o fereastra cu o serie de metodeutilizate de catre
contextul apletului pentru a initializa,a starta respectiva opri apletul.
Contextul(cadrul) apletului este o aplicatie responsabila pentru a incarca si a rula
apletul. De exemplu un navigator poate fi un cadru de executie pentruun
aplet. Ierarhia de clase din care face parte clasaApplet este redatain figura urmatoare.
Totodata pe figura apare si clasa pentru primul nostruaplet, HelloWeb:
2. Structura claseiApplet
void
destroy()
-Se apeleaza de catre programul care executa apletul pentru a distruge toate resursele
alocate pentru executia acestuia.
AppletContext getAppletContext()
getAppletInfo()
getCodeBase()
getDocumentBase()
-Returneaza adresa la care se gaseste fisierul HTML in care este inclus codul
apletului
String
getParameter(String name)
init()
resize(Dimension d)
void
showStatus(String msg)
start()
-Este apelat de catre navigator imediat dupa init() pentru startarea apletului, respectiv
ori de cate ori se revine la pagina in navigator.Metoda este folosita si pentru pornirea
firului de executie propriu apletului.
void
stop()
-Este apelat de catre browser pentru oprirea executiei apletului. Se apeleaza ori de cate
ori se trece la o alta pagina HTML in navigator sause iconifica fereastra navigatorului.
Pe langa atributele CODE, WIDTH si HEIGHT tag-ul APPLET poate sacontina o
serie de alte atribute:
< APPLET
[ CODEBASE = codebaseURL ]
CODE = appletFile
[ ARCHIVE = archivesList ]
[ ALT = alternateText
[ NAME = appletInstanceName ]
WIDTH = pixels
HEIGHT = pixels
[ ALIGN = alignment ]
[ VSPACE = pixels ]
[ HSPACE =pixels ]
>
[<PARAM NAME = appletParameter1 VALUE = value >]
[<PARAM NAME = appletParameter1 VALUE = value >]
...
</APPLET>
CODEBASE: permite includerea unui aplet aflat intr-un alt catalog decatcel in care se
afla fisierul HTML respectiv a unui aplet aflat pe un althost
ARCHIVE: Permite utilizrea fisierelor comprimate. Inainte de executia apletului,
navigatorul aduce codul apletului. Daca pe parcursul executiei apletului este nevoie si
de alte clase de pe server, atunci se vor incarca si acestea astfel incetinind executia
apletului. Pentru a evita acest lucru se poate utiliza un singur fisier comprimat care sa
contina toate clasele de care este nevoie. In acest caz inaintea incarcarii apletului JVM
aduce arhiva si numai dupa aceea se trece la executia programului. Pentru arhivarea
claselor se poate utiliza utilitarul jar
ALT: Prin acest atribut se poate specifica un text pe care browserul sa-l afiseze in
cazul in care navigatorul nu este compatibil Java
NAME: Prin acest atribut se poate atribui un nume apletului
ALIGN, VSPACE, HSPACE: Sunt atribute pentru dispunerea apletului inpagina
HTML
PARAM: Se utilizeaza pentru transmiterea argumentelor apletului. Sunt similare cu
argumentele liniei de comanda.
Exemple:
<PARAM NAME=nume VALUE=valoare>
<PARAM NAME="dimensiune" VALUE="10">
name )
Metoda showDocument( URL url ) cere browserului incarcarea unei noi pagini
in pagina curenta, iar metoda showDocument( URL url,Stringname ) specifica si
cadrul de afisaj. Parametrul name poate aveaunadin urmatoarele valori:
"self":
"_parent":
"_top":
"_blank":
getAppletContext().showDocument("http://www.uttgm.ro","_blank")
Primul exemplu afiseaza o pagina HTML specificat printr-un URL absolut, al doilea
afiseaza un document HTML aflat in acelasi catalog cu sursa apletului, iar al treilea
exemplu incearca afisarea unei pagini HTML aflat in acelasi catalog cu pagina care
contine apletul
Urmatoarele doua metode se utilizeaza pentru comunicarea intre apleturile unei
aceleasi pagini HTML. Comunicarea intre apleturi se realizeaza la fel ca si
comunicarea intre oricare tipuri de obiecte. Dupa ce un aplet obtine referinta unui alt
aplet, poate sa trimita mesaje acelui aplet.
Diagrama de clasa:
Sursa Java:
//Source file: Applet1.java
import java.applet.Applet;
import java.awt.event.ActionListener;
import java.awt.TextField;
import java.awt.Button;
import java.awt.event.ActionEvent;
public class Applet1 extends Applet implements ActionListener
{
public TextField tf;
public Applet2 a;
public Button b;
public Applet1()
{
}
public void init()
{
tf = new TextField( 30 );
add( tf );
b = new Button("Send");
add( b );
b.addActionListener( this );
a = (Applet2)getAppletContext().getApplet("APPLET2");
}
public void actionPerformed(ActionEvent arg0)
{
a.write( tf.getText());
}
}
//Source file: Applet2.java
import java.applet.Applet;
import java.awt.Graphics;
public class Applet2 extends Applet
{
private String string = null;
public Applet2()
{
}
public void paint(Graphics g)
{
if( string != null )
g.drawString(string, 10, 10 );
}
public void write(String s)
{
string = s;
repaint();
}
}
3.
4.
5.
6.
Returneaza un obiect de tip imagine. Parametrul url trebuie sa reprezinte unul absolut.
public Image getImage(URL url, String name);
Returneaza un obiect de tip imagine specificat printr-un URL absolut si numele unei
resurse realativ la url-ul specificat.
Exemplu demonstrativ:
In exemplul urmator veti putea utiliza la urmatoarele:
Sursa Java:
//Source file:DrawPad.java
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Image;
public class DrawPad extends Canvas
{
private int xpos;
private int ypos;
private int oxpos;
private int oypos;
private Graphics drawGr;
private Image drawImg;
public DrawPad()
{
setBackground( java.awt.Color.green );
}
import java.awt.TextField;
import java.awt.Button;
import java.awt.Panel;
import java.awt.event.ActionEvent;
public class DemoApplet extends Applet implements ActionListener
{
public Choice operation;
public TextField parameter;
public Button doIt;
public Button audioButton;
public Panel panel;
public Button clearButton;
public Panel p;
public DrawPad dp;
= operation.getSelectedItem();
sound.play();
}
else
if( command.equalsIgnoreCase("Clear") )
dp.clear();
}
}
Introducere
Daca ati incercat sa creati componente proprii in AWT, probabil ca ati extins clasa
Canvas sau Panel. Aceasta metoda functioneaza insa ridica cateva probleme si anume
atat Canvas cat si Panel sunt componente netransparente si daca o componenta contine
prea multe componente native atat scade viteza de executie a programului. De
exemplu sa consideram un checkbox, ori de cate ori modificam starea acestuia, acest
obiect comunica cu un obiect checkbox nativ si cele doua obiecte trebuie sa fie
ibtotdeauna in aceasi stare, adica starile lor se modifica in mod sincron. Acesasta
soncronizare incetineste viteza de executie a aplicatiei. O alta problema cu
componentele AWT este ca modul de afisare a acestora depinde de platforma pe care
se ruleaza aplicatia. Deci cum arata ele nu depinde de programator ci de componentele
native. Pentru aceste neajunsuri JavaSoft introduce componentele "lightweight".
Aceste componente sunt scrise 100% in Java si modul de afisare astfel depinde doar
124, 124, 124, 124, 124, 125, 129, 135, 135, 138, 139, 137, 138, 139,
140,
140, 140, 142, 143, 147};
static int Y[] = {
98, 98, 98, 97, 96, 96, 95, 94, 91, 90,
89, 89, 88, 86, 86, 85, 82, 81, 79, 78, 77, 76, 76, 75, 74,
74, 73, 71, 69, 68, 56, 49, 48, 49, 49, 48,
48, 48, 47, 47, 44, 45, 45, 45, 45, 45, 45, 46, 46, 47, 46, 46, 45, 45,
45,
46, 46, 45, 44, 44, 45, 46, 47, 47, 46, 45, 45, 45, 46, 46, 44, 44, 45,
45,
44, 43, 42, 42, 42, 42, 42, 41, 41, 41, 41, 41, 40, 40, 39, 39, 38, 37,
38,
38, 38, 36, 36, 35, 11, 9, 9, 66, 63, 63, 63, 64, 64, 65, 66, 67, 68, 70,
71,
78, 82, 83, 84, 85, 86, 87, 91, 93, 96, 101, 104, 105, 104, 103, 102, 97,
95,
95, 95, 95, 95, 94, 94, 95, 95, 96, 96, 96, 97, 98, 99, 99, 99, 100, 102,
104,
105, 106, 114, 116, 120, 121, 123, 124, 125, 126, 128, 129, 132, 133,
138,
140, 140, 141, 142, 144, 145, 145, 147, 147, 146, 146, 146, 145, 144,
144,
143, 137, 134, 131, 130, 129, 129, 129, 129, 129, 128, 124, 124, 122,
121,
122, 121, 119, 118, 118, 118, 118, 117, 118, 118, 118, 117, 116, 115,
115,
115, 116, 115, 115, 114, 114, 113, 113, 112, 111, 111, 111, 112, 112,
112,
112, 111, 107, 105, 102, 102, 100, 99, 98, 98, 99, 100, 100, 100, 98};
}
import java.awt.*;
import java.awt.event.*;
public class texasButton extends Component {
boolean inPoly = false;
boolean mouseDown = false;
ActionListener listener;
Polygon poly = new Polygon(Texas.X, Texas.Y, Texas.X.length);
public texasButton() {
enableEvents(AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.MOUSE_MOTION_EVENT_MASK);
setBackground(Color.blue);
}
public synchronized void addActionListener(ActionListener l) {
listener = AWTEventMulticaster.add(listener, l);
}
public synchronized void removeActionListener(ActionListener l) {
listener = AWTEventMulticaster.remove(listener, l);
}
public void paint(Graphics g) {
if (inPoly && mouseDown)
g.setColor(getBackground().darker().darker());
else
g.setColor(getBackground());
g.fillPolygon(poly);
}
public void processMouseMotionEvent(MouseEvent e) {
if (poly.contains(e.getPoint())) {
if (!inPoly && mouseDown)
repaint();
inPoly = true;
}
else {
if (inPoly && mouseDown)
repaint();
inPoly = false;
}
}
public void processMouseEvent(MouseEvent e) {
switch (e.getID()) {
case MouseEvent.MOUSE_PRESSED :
if (inPoly) {
mouseDown = true;
repaint();
}
break;
case MouseEvent.MOUSE_RELEASED :
if (inPoly == true && mouseDown == true) {
if (listener != null)
listener.actionPerformed(new ActionEvent(this,
ActionEvent.ACTION_PERFORMED, ""));
repaint();
}
mouseDown = false;
break;
}
super.processMouseEvent(e);
}
public Dimension getPreferredSize() {
return getMinimumSize();
}
public Dimension getMinimumSize() {
return new Dimension(160,150);
}
}
import java.awt.*;
import java.awt.event.*;
public class texasTest extends Frame implements ActionListener {
public static void main(String args[]) {
texasTest t = new texasTest();
}
public void actionPerformed(ActionEvent ae) {
System.out.println(ae.getSource());
}
public texasTest() {
setBackground(Color.lightGray);
setLayout( new GridLayout(1, 3));
texasButton cb[] = new texasButton[ 3 ];
for( int i =0; i<cb.length; i++)
{
cb[ i ] = new texasButton();
cb[ i ].addActionListener(this);
add(cb[ i ]);
}
addWindowListener( new WindowAdapter(){
public void windowClosing( WindowEvent e ){
setVisible( false );
System.exit( 0 );
}
});
setBounds(1,1,500,200);
setVisible( true );
}
}
Arhitectura Model-View-Controller(MVC)
Clasele din pachetul Swing sunt bazate pe arhitectura MVC. Intr-o interfata grafica
MVC intotdeauna exista trei obiecte model, view si controller (structura, reprezentare
si comportament). Modelul este reprezentarea logica, view-ul este reprezentarea
vizuala si controller-ul specifica comportamentul. Separarea acestor elemente permite
urmatoarele:
Putem avea mai multe view-uri asociate aceluiasi model. De exemplu putem
vizualiza aceleasi date sub forma de tabel sau sub forma de grafic. Modificand
datele se modifica ambele reprezentari.
Modelul nespecificand reprezenarea, putem modifica view-ul fara sa-l afectam
modelul atasat
Pentru modelul unui buton putem avea o variabila intreaga cu doua valori 0 si 1, sau o
variabila logica cu valorile false si true.
Obiectul contentpane din figura precedenta este un obiect Container obisnuit si este
sub containerul swing.
Codul pentru crearea suprafetei grafice:
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textField);
panel.add(list);
Container contentPane = this.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(button1);
contentPane.add(button2);
contentPane.add(panel);
JLabel
Un JLabel este similar cu o eticehta java.awt.Label, avand o serie de functionalitati in
plus:
Clasa ImageIcon este o implementare a clasei Icon, care creaza o iconita dintr-un
obiect de tip Image.
Icon iconPicture = new ImageIcon("Apple.gif");
Un exemplu:
Sursa:
import javax.swing.*;
import java.awt.*;
public class SwingPanel extends JPanel
{
public SwingPanel()
{
setLayout( new GridLayout( 3, 1 ));
JLabel simplelabel = new JLabel("This is a simple label");
add( simplelabel );
JLabel iconlabel = new JLabel("This is a fancy label");
Icon icon = new ImageIcon("icon.gif");
iconlabel.setIcon( icon );
Font font = new Font("Serif",Font.BOLD|Font.ITALIC,30);
iconlabel.setFont( font );
add( iconlabel );
JLabel myiconlabel = new JLabel("This is my icon label");
Icon myicon = new RedOval();
myiconlabel.setIcon( myicon );
add( myiconlabel );
}
}
import javax.swing.JFrame;
public class SwingFrame extends JFrame
{
private SwingPanel p;
public SwingFrame()
{
p = new SwingPanel();
getContentPane().add( p );
}
public static void main( String args[] )
{
SwingFrame f = new SwingFrame();
f.addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e )
{
System.exit( 0 );
}
});
f.setBounds(1,1,400,300);
f.setVisible( true );
}
}
In toate exemplele demonstrative pentru componente se vor utiliza doua clase. O clasa
care extinde clasa JPanel si care contine componenta specifica si una de tip container
care extinde clasa JFrame si afiseaza panelul cu componentele specifice. De aceea in
cazul urmatoarelor exemple vom descrie doar constructorul clasei SwingPanel.
JButton
Un buton JButton se instantieaza analog ca si un butom java.awt.Button. Evenimentul
care se produce la apasarea acestuia este tot un ActionEvent si evenimentul se livreaza
tuturor receptorilor inregistrati.Culoarea butonului este identic cu culoarea
containerului, deci trebuie modificat la SystemColor.control.
setLayout( new FlowLayout() );
JButton simplebutton = new JButton("Simple");
add( simplebutton );
simplebutton.setBackground(SystemColor.control);
Icon icon = new ImageIcon("icon.gif");
JButton iconbutton = new JButton("Icon", icon );
iconbutton.setBackground(SystemColor.control);
add( iconbutton );
JTextComponent
JTextComponent este o clasa generala cu toate functiunile unui editor de text simplu.
Metodele cele mai utilizate:
copy()
cut()
paste()
getSelectedText()
setSelectionStart()
setSelectionEnd()selectAll()
replaceSelection()
getText()
setText()
setEditable()
setCaretPosition()
JPasswordField
Este subclasa clasei JTextField. Cu metoda setEchoChar() se poate specifica
caracterul care se afiseaza in locul caracterelor introduse. Implicit este '*'.
setLayout( new FlowLayout() );
JPasswordField pf = new JPasswordField(20);
pf.setEchoChar('*');
add(pf );
JScrollBar
Este varianta "lightweight" a componentei java.awt.Scrollbar.
setLayout( new BorderLayout() );
JScrollBar vertical = new JScrollBar(JScrollBar.VERTICAL,0,5,0,100);
add(vertical, BorderLayout.EAST );
JScrollBar horizontal = new JScrollBar(JScrollBar.HORIZONTAL,0,5,0,100);
add(horizontal, BorderLayout.SOUTH );
JSlider
JSlider este similar cu JScrollBar, dar permite afisarea marcjelor minore respectiv a
celor majore precum si desenarea unui chenar Border in jurul componentei.
JProgressBar
Se utilizeaza pentru vizualizarea evolutiei unei operatii Pentru a lucra cu o asemenea
componenta prima data trebuie s-o intializam
JProgressBar p = new JProgressBar();
p.setMinimum( 0 );
setMaximum( numar_operatii );
{
//se executa o operatie
p.setValue( i );
}
Exemplu:
import javax.swing.JFrame;
public class SwingFrame extends JFrame
{
private SwingPanel p;
public SwingFrame()
{
p = new SwingPanel();
getContentPane().add( p );
Thread t = new Thread( p );
t.start();
}
public static void main( String args[] )
{
SwingFrame f = new SwingFrame();
f.addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent
e )
{
System.exit( 0 );
}
}
);
f.setBounds(1,1,400,300);
f.setVisible( true );
}
}
import javax.swing.*;
import java.awt.*;
public class SwingPanel extends JPanel implements Runnable
{
JProgressBar pb;
public SwingPanel()
{
setLayout( new FlowLayout() );
pb = new JProgressBar();
pb.setMinimum(0);
pb.setMaximum(100);
pb.setValue( pb.getMinimum());
add( pb );
}
public void run()
{
JComboBox
Componenta este asemanatoare cu Choice din AWT, dar permite si editarea, adica
introducerea unei valori care nu exista in lista.
Exemplu de utilizare:
Sursa:
import javax.swing.*;
import java.awt.*;
public class SwingPanel extends JPanel
{
String elements[] ={"One","Two","Three","Four","Five"};
public SwingPanel()
{
JList
Componenta are doua implementari, una care respecta arhitectura MVC si una care
nu, se comporta la fel ca si o lista AWT. Totusi si aceasta implementare mai simpla sa imbunatatit. Putem adauga elementele prin contructor transmitandu-i un tablou de
stringuri. JList nu suporta scroll, adica daca dorim aceasta facilitate atunci trebuie s-o
punem intr-un ScrollPane.
import javax.swing.*;
import java.awt.*;
public class SwingPanel extends JPanel
{
String elements[] =
{"Orange","Lemon","Strawberry","Raspberry","Apple","Banana"};
public SwingPanel()
{
setLayout( new BorderLayout() );
JList list = new JList(elements);
ScrollPane pane = new ScrollPane();
pane.add( list );
add( pane, BorderLayout.CENTER );
}
}
Timer
Pe langa componente grafice, pachetul swing vine si cu o serie de utilitare. Un astfel
de utilitar este clasa Timer. Exemplul urmator este o fereastra cu trei butoane si cu trei
obiecte de tip Timer. Fiecare obiect Timer controleaza un buton, adica la trecerea
intervalului specific fiecarui timer se incrementeaza numarul de pe butonul
Diagrama de secventiere
Sursa
import
import
import
import
import
javax.swing.JFrame;
java.awt.event.ActionListener;
javax.swing.JButton;
javax.swing.Timer;
java.awt.event.ActionEvent;
b[0].setLabel( Integer.toString(
Integer.parseInt(b[0].getLabel())+1 ));
}
else
if( arg0.getSource() == t[1] )
{
System.out.println( "Button: "+1);
b[1].setLabel( Integer.toString(
Integer.parseInt(b[1].getLabel())+1 ));
}
else
if( arg0.getSource() == t[2] )
{
System.out.println( "Button: "+2);
b[2].setLabel( Integer.toString(
Integer.parseInt(b[2].getLabel())+1 ));
}
}
}