Professional Documents
Culture Documents
2
ORIENTATA
Iolu Mihai - S
tefan
19 noiembrie 2008
ii
Cuprins
1 Introducere
1.1 Mediul de programare Java
. . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
3
5
5
8
9
12
12
13
13
14
15
16
16
20
23
23
27
28
29
iv
CUPRINS
3.3
4 Obiecte si clase
4.1 Definirea unei clase . . . . . . . . . . . . . .
4.2 Declararea atributelor unei clase . . . . . . .
4.2.1 Modificatorii de vizibilitate . . . . . .
4.2.2 Modificatorul final . . . . . . . . . .
4.2.3 Modificatorul static . . . . . . . . . .
4.2.4 Modificatorii transient si volatile . .
4.3 Declararea metodelor unei clase . . . . . . .
4.3.1 Modificatorul static . . . . . . . . . .
4.3.2 Transmiterea parametrilor la metode
4.4 Declararea constructorilor unei clase . . . .
4.5 Initializatorul static al unei clase . . . . . .
4.6 Probleme rezolvate . . . . . . . . . . . . . .
4.7 Probleme propuse . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 Mostenirea n Java
5.1 Notiuni generale . . . . . . . . . . . . . . . . . . .
5.2 Exemplu de aplicatie folosind mostenirea . . . . .
5.3 Polimorfismul . . . . . . . . . . . . . . . . . . . .
5.4 Metode si clase finale . . . . . . . . . . . . . . . .
5.5 Operatia de casting . . . . . . . . . . . . . . . . .
5.6 Clase abstracte . . . . . . . . . . . . . . . . . . .
5.7 Clasa Object . . . . . . . . . . . . . . . . . . . .
5.7.1 Metoda toString() . . . . . . . . . . . . .
5.7.2 Metoda equals() . . . . . . . . . . . . . . .
5.7.3 Metoda hashCode() . . . . . . . . . . . . .
5.7.4 Metoda clone() . . . . . . . . . . . . . . .
5.8 Implementarea colectiilor generice folosind Object
5.9 Utilizarea colectiilor generice cu template-uri . . .
5.9.1 Boxing si unboxing n Java . . . . . . . . .
6 Tratarea exceptiilor n Java
6.1 Clasificarea exceptiilor . . . . . . . . . . .
6.2 Crearea claselor exceptie . . . . . . . . . .
6.3 Aruncarea exceptiilor . . . . . . . . . . . .
6.4 Prinderea exceptiilor . . . . . . . . . . . .
6.5 Indicatii referitoare la utilizarea exceptiilor
6.6 Exemple . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
37
37
38
39
40
41
42
42
43
43
44
46
47
65
.
.
.
.
.
.
.
.
.
.
.
.
.
.
67
67
68
73
75
75
76
82
83
83
84
84
85
89
90
.
.
.
.
.
.
93
94
95
96
96
98
98
CAPITOLUL
Introducere
Acest curs se refera la programarea obiect orientata si principalele caracteristici ale acesteia. Acestea vor fi prezentate n contextul unui limbaj
care ofera un foarte bun suport din acest punct de vedere, respectiv limbajul
Java.
Java este, n mod indiscutabil, unul din cele mai populare limbaje de
programare obiect orientate (alaturi de limbaje precum C++, C# sau Visual
Basic). Acest lucru a facut ca el sa fie folosit de milioane de dezvoltatori din
lumea ntreaga mai ales n contextul aplicatiilor web.
El a aparut la sfarsitul anului 1995 si a avut parte de o mare publicitate
nca de la nceput. Este un limbaj care ofera suport pentru toate tehnicile
moderne de programare precum: programarea n retea, lucrul cu fire de
executie, internationalizare, lucrul cu baze de date si multe altele.
De-a lungul timpului cei de la Sun Microsystems, care se ocupa de evolutia
limbajului, au scos 7 revizii majore ale acestuia. Cea mai importanta a fost
cea care a dus la aparitia versiunii JDK 5.0. Momentan s-a ajuns la versiunea
JDK 6.0.
Evolutia este impresionanta daca tinem cont ca s-a pornit de la un numar
de aproximativ 200 de clase si s-a ajuns acum la peste 3000 de clase.
Java este mult mai mult decat un simplu limbaj. Java este o platforma
care are o librarie imensa ce contine foarte mult cod reutilizabil precum si
un mediu de executie care ofera servicii precum: securitate, portabilitate pe
diverse medii de executie precum si garbage collection. Unele din principalele
avantaje ale acestui mediu Java sunt urmatoarele:
1
CAPITOLUL 1. INTRODUCERE
Limbajul Java este un limbaj relativ simplu. Dupa cum vom vedea n
cele ce urmeaza n Java nu avem numeroase constructii care existau n
C/C++ precum: pointeri, structuri, fisiere header, directive de preprocesor, suprancarcare de operatori, mostenire virtuala etc.
Limbajul Java este obiect orientat. In ziua de azi, majoritatea limbajelor care exista pe piata si au o foarte larga raspandire au la baza
principiile programarii obiect orientate (vezi C++, C#, Visual Basic).
Java are un bogat suport pentru aplicatiile distribuite. Exista numeroase
clase care permit crearea unor aplicatii care sa ruleze n retea, folosind
diverse modalitati de lucru: sockets, RMI, CORBA etc.
Java este un limbaj robust. Cei care au dezvoltat acest limbaj au avut
ca scop foarte important ncercarea de a evita pe cat posibil aparitia
erorilor, prin depistarea acestora cat mai rapida sau prin usurarea modului de a programa. Un astfel de exemplu este lipsa pointerilor care face
ca programarea sa fie mai usoara si practic face imposibila coruperea
memoriei care se putea produce destul de usor n C/C++.
Java este portabil. Aceasta nseamna ca daca scriem un cod pe platforma Windows, exact acelasi cod fara modificari va putea rula si pe o
platforma Linux de exemplu. Nu acelasi lucru se ntampla, de exemplu,
n cazul C++. Tipul int putea avea dimensiuni diferite n functie de
platforma tinta.
Java este neutru din punct de vedere arhitectural. In momentul n care
se compileaza codul Java, rezultatul produs este un bytecode. Acesta
este rulat cu ajutorul unei masini virtuale Java (JVM - Java Virtual
Machine). Din cauza acestui mod de gandire este posibil ca acelasi
cod sa ruleze pe orice sistem de operare, doar implementarea masinii
virtuale diferind. Un mecanism asemanator a fost dezvoltat si de catre
cei de la Microsoft pentru platforma .NET, care are la baza tot o masina
virtuala.
Aplicatii consola (n linie de comanda): se pot rula din linie de comanda, neavand o interfata grafica
Aplicatii grafice (folosesc librarii AWT sau Swing)
Applet-uri - sunt un anumit tip de aplicatii grafice care pot fi introduse
n pagini web, facand ca o pagina web sa aiba un aspect mult mai
dinamic asemanator aplicatiilor desktop
Pagini web dinamice - sunt create cu ajutorul unor tehnologii care s-au
dezvoltat peste Java si care adauga functionalitati noi limbajului (vezi
JSP, Servlets, Spring etc.)
Aplicatii pe mobil (se realizeaza cu ajutorul unei distributii Java numita
J2ME - Java 2 Microedition).
Accentul n continuare se va pune mai ales pe primul tip de aplicatie,
doar tangential se vor atinge celelalte tipuri.
Trebuie spus ca majoritatea ideilor prezentate vis-a-vis de programarea
obiect orientata sunt aplicabile si n cazul altor limbaje obiect orientate precum C++ (deja studiat) si C# (care va fi studiat n semestrul urmator).
Voi ncerca sa prezint n continuare urmatoarele lucruri:
Structurile de programare fundamentale n Java
Lucrul cu obiecte si clase, mostenirea si lucrul cu interfete
Tratarea exceptiilor
Stream-uri Java
Programarea generica si colectiile
Lucrul cu baze de date
Annotations
Java Reflection
1.1
CAPITOLUL 1. INTRODUCERE
CAPITOLUL
2.1
In aceasta sectiune vom crea primul nostru program Java, pe care-l vom
rula din linie de comanda. Acest program arata astfel:
public class Welcome
{
public static void main(String[] args)
{
System.out.println("Hello world!");
}
}
Pentru a rula acest program din linie de comanda se parcurg mai multi
pasi:
1. Se introduce programul ntr-un editor si apoi se salveaza cu extensia
.java. Uneori numele trebuie sa respecte anumite conditii dar asupra
acestui aspect vom reveni. In cazul nostru vom salva programul cu
numele Welcome.java.
2. Intram n linie de comanda prin Start+Run...+cmd (sau command, n
cazul calculatoarelor care ruleaza Win 98 sau Win ME ), dupa care ne
pozitionam n directorul n care a fost salvat fisierul anterior.
5
2.2
2.3. COMENTARII
System.exit(0);
}
double a=Double.parseDouble(args[0]);
double b=Double.parseDouble(args[1]);
double c=Double.parseDouble(args[2]);
double delta=b*b-4*a*c;
if(delta<0)
System.out.println("Ecuatia nu are solutii reale");
else
if(delta==0)
System.out.println("Solutie unica: "+ (-b)/(2*a));
else
{
double x1=(-b-Math.sqrt(delta))/(2*a);
double x2=(-b+Math.sqrt(delta))/(2*a);
System.out.println("x1="+x1);
System.out.println("x2="+x2);
}
}
}
Observatii:
Metoda statica parseDouble() a clasei Double are rolul de a transforma
un sir de caractere ntr-un numar de tip double. In mod asemanator
exista Integer.parseInt() si Float.parseFloat().
Functiile matematice gata definite n limbajul Java sunt implementate n clasa Math, ele fiind functii statice. Un exemplu este functia
Math.sqrt() folosita pentru a calcula radicalul unui numar.
2.3
Comentarii
In Java se pot realiza trei tipuri de comentarii care sunt toate prezentate
n exemplul urmator. Aceasta aplicatie calculeaza suma cifrelor unui numar
ntreg:
/**
*
* @author mihai
2.3. COMENTARII
11
2.4
Tipuri de date
2.4.1
Dimensiune
1 byte
2 bytes
4 bytes
8 bytes
float
4 bytes
double
8 bytes
Valori admise
-128...127
-32768 ... 32767
-2,147,483,648 ... 2,147,483, 647
-9,223,372,036,854,775,808
...
9,223,372,036,854,775,807
aproximativ 3.40282347E+38F (6-7 cifre zecimale semnificative)
aproximativ 1.79769313486231570E+308 (15
cifre zecimale semnificative)
2.5. OPERATORI
13
2.4.2
2.5
Operatori
2.6
Instructiuni decizionale
2.7. INSTRUCT
IUNI REPETITIVE
15
switch(expresie)
{
case val1: secventa1
[break;]
case val2: secventa2
[break;]
....
case valN: secventaN
[break;]
[default:
secventa]
}
Instructiunea se evalueaza astfel: se calculeaza valoarea expresiei dupa
care se gaseste case-ul corespunzator expresiei. Incepand de la acesta se
evalueaza toate secvenele pana la ntalnirea lui break. In cazul n care nici e
expresie nu se potriveste se executa instructiunea din clauza default.
Vom prezenta exemple atunci cand vom prezenta lucrul cu siruri de caractere.
2.7
Instructiuni repetitive
2.8
2.8.1
Vectori si matrici
Vectori
17
19
}
}
Observatii:
Se putea realiza afisarea sirului si n alt mod, folosind capabilitatile
oferite de JDK 1.6:
for(int x:a)
System.out.println(x+" ");
Pentru lucrul cu siruri avem clasa Arrays care are definite cateva
metode foarte utile. Astfel, puteam sorta elementele sirului folosind
urmatorul cod:
Arrays.sort(a);
Se recomanda consultarea API-ului Java pentru studierea celorlalte
metode utile pentru lucrul cu siruri.
Problema 2: Sa se scrie o metoda care primeste ca parametru un sir de
numere ntregi si returneaza sirul obtinut prin inserarea ntre fiecare 2 elemente a sumei lor.
Metoda ar putea arata astfel:
static int[] generareSir(int[] a)
{
int[] b=new int[2*a.length-1];
for(int i=0;i<a.length;i++)
b[2*i]=a[i];
for(int i=1;i<b.length;i+=2)
b[i]=b[i-1]+b[i+1];
return b;
}
Problema 3: Sa se scrie o metoda care primeste ca parametru un sir a,
o pozitie poz si o valoare val si returneaza ntr-un sir, vectorul obtinut prin
inserarea elementului val pe pozitia poz n sirul initial.
In Java exista o metoda prin care putem copia elemente dintr-un sir in
alt sir elegant si eficient, folosind metoda arraycopy a clasei System. Antetul
acestei metode este urmatorul:
2.8.2
Matrici
In Java, o matrice este retinuta sub forma unui sir de siruri. O matrice
se poate declara si initializa n trei feluri.
Cea mai simpla varianta este sa declaram matricea si sa alocam memorie
pentru ea ca n exemplul urmator:
int[][] a=new int[nrLinii][nrColoane];
Matricile se pot si initializa direct. Prezentam modul n care se poate
initializa o matrice cu 2 linii si 3 coloane:
int[][] a= {{2, 3, 4},
{1, 4, 2}};
Totusi, n Java o matrice poate avea un numar variabil de elemente pe
fiecare linie:
int[][] a= {{2, 3},
{1, 4, 2, 5}};
In acest caz, numarul de linii ale matricii este a.length iar numarul de
coloane ale liniei i este a[i].length.
Daca dorim sa citim o astfel de matrice de la tastatura putem proceda
astfel:
21
23
int max=a[0];
for(int i=1;i<a.length;i++)
if(a[i]>max)
max=a[i];
return max;
}
static int minMax(int[][] a)
{
int min=maximSir(a[0]);
for(int i=1;i<a.length;i++)
if(maximSir(a[i])<min)
min=maximSir(a[i]);
return min;
}
}
2.9
S
iruri de caractere
2.9.1
Clasa String
25
import java.util.*;
public class StringPalindrom
{
static boolean palindrom(String s)
{
for(int i=0;i<=(s.length()-2)/2;i++)
if(s.charAt(i)!=s.charAt(s.length()-i-1))
return false;
return true;
}
public static void main(String args[])
{
Scanner s=new Scanner(System.in);
System.out.print("Sirul de caractere: ");
String str=s.nextLine();
if(palindrom(str))
System.out.println("Are aspect de palindrom");
else
System.out.println("Nu are aspect de palindrom");
}
}
Problema 2 Se citeste un sir de siruri de caractere. Sa se sorteze crescator
sirul si sa se afiseze sirul astfel obtinut.
import java.util.*;
public class SortareStringuri
{
public static void main(String args[])
Observatie importanta:
Clasa String este immutable ceea ce nseamna ca niciodata o variabila
de tip String nu se poate modifica. Se poate doar ca ea sa retina o alta
referinta. Daca vrem sa putem modifica un sir de caractere folosim clasa
StringBuf f er.
2.9.2
27
Clasa StringBuffer
2.9.3
Clasa StringTokenizer
import java.util.*;
public class AfisareOperanzi
{
public static void main(String args[])
{
Scanner s=new Scanner(System.in);
System.out.print("Expresia matematica: ");
String expr=s.nextLine();
29
2.9.4
Una din cele mai importante facilitati legate de lucrul cu siruri de caractere n Java o constituie lucrul cu expresii regulate.
Acesta ne permite sa ne definim un anumit sablon si sa vedem daca sirul
de caractere respecta acel sablon sau sa gasim toate aparitiile ntr-un text a
unor subsiruri de caractere care verifica acel sablon.
Problema 1 De exemplu, pentru a verifica daca un sir de caractere este
alcatuit din exact 3 cifre, prima fiind diferita de zero putem proceda astfel:
import java.util.regex.Pattern;
import java.util.*;
public class ExpresiiRegulate {
public static void main(String args[]) {
Scanner s = new Scanner(System.in);
System.out.print("Introduceti sirul");
String str=s.nextLine();
if(Pattern.matches("[\\d&&[^0]]\\d\\d", str))
System.out.println("Respecta");
else
System.out.println("Nu respecta");
}
}
Tabela 2.2: Clase caracter si clase predefinite
Reprezentare
[abc]
[abc]
[a-zA-Z]
[a-d[m-p]]
[a-z&&[def]]
[a-z&&[bc]]
[a-z&&[m-p]]
Semnificatie
a, b sau c
orice caracter cu exceptia lui a, b sau c
caractere ntre a-z si A-Z
caractere ntre a-d si m-p
d, e sau f (intersectie)
de la a la z, cu exceptia lui b si c
de la a la z, cu exceptia lui m-p
Reprezentare
.
\d
\D
\s
\S
\w
\W
Semnificatie
X, odata sau deloc
X, de zero sau mai multe ori
X, odata sau de mai multe ori
X, exact de n ori
X, de cel putin n ori
X, de cel putin n ori dar nu mai mult de m ori
CAPITOLUL
3.1
Clasa defineste caracteristicile comune mai multor lucruri (obiecte), incluzand partea informationala a acestora (atribute, campuri sau proprietati)
si comportamentul lor (lucrurile pe care le pot face - reprezentate prin metode).
Clasa este un tip de date deoarece, la fel ca si tipul float are o parte
de informatie precum si o parte de comportament. Practic, lucrul cu clase
permite definirea de noi tipuri de date n loc de a folosi doar tipurile care
sunt deja existente n limbaj.
31
32
Astfel se mbogateste limbajul prin adaugarea de tipuri de date necesare programatorului. Limbajul nu numai ca permite acest lucru dar l si
ncurajeaza puternic.
Odata creata o clasa se pot crea oricate obiecte de tipul acelei clase,
obiecte care vor corespunde obiectelor din domeniul problemei.
Clasele ofera de asemenea modularitate si structura ntr-un program bazat
pe programarea obiect orientata.
Obiectul este un exemplar al unei clase (o instanta a unei clase).
Instant
a este un obiect creat la momentul rularii pe baza unei clase.
Setul de valori ale atributelor unui obiect reprezinta starea acelui obiect.
Metodele se refera la abilitatile unui obiect. In cadrul unui program
prin folosirea unei metode este afectat un singur obiect, cel asupra caruia
este apelata metoda respectiva (exceptie fac aici metodele statice).
Transmiterea de mesaje este procesul prin care un obiect trimite date
altui obiect sau i cere altui obiect sa apeleze o metoda.
In urma cu ceva timp un programator descria limbajul Smalltalk astfel:
Totul este un obiect (Un obiect este o variabila mai deosebita care are
atat stare cat si comportament)
Un program este alcatuit dintr-un set de obiecte care-si spun unul altuia
ce sa faca.
Fiecare obiect are propria sa memorie alcatuita eventual din alte obiecte.
Fiecare obiect are un tip (este o instanta a unei clase).
Toate obiectele de acelasi tip pot primi aceleasi mesaje (chiar si n
contextul mostenirii).
Dupa cum putem usor observa toate aceste lucruri sunt valabile si acum
n contextul limbajului Java.
3.2
Abstractizarea reprezinta simplificarea realitatii complexe prin modelarea de clase potrivite problemei de rezolvat precum si lucrul la cel mai
potrivit nivel de mostenire pentru un anumit aspect al unei probleme.
Toate limbajele de programare ofera un anumit grad de abstractizare.
Complexitatea problemei de abstractizat depinde foarte mult de tipul abstractizarii si de calitatea acesteia.
3.2. PRINCIPII ALE PROGRAMARII
OBIECT ORIENTATE
33
34
3.3
3.3. SOLUT
II PENTRU UTILIZAREA EFICIENTA A PRINCIPIILOR POO35
O alta idee extrem de sugestiva este cea enuntata de cunoscutul informatician Bertrand Meyer si care poarta numele de Principiul Open-Closed :
Toate entitatile software trebuie sa fie deschise pentru extensie si nchise
pentru modificare.
Atunci cand o schimbare ntr-o aplicatie conduce la numeroase alte schimbari
n cascada n alte zone ale aplicatiei, aceste este un semn ca avem de-a face
cu un design slab. Programul devine fragil, greu de stapanit si imprevizibil.
Acest principiu spune ca trebuie sa construim module care nu se schimba,
n sensul n care daca vrem sa adaugam noi facilitati putem scrie cod nou,
dar fara a modifica codul deja existent.
In mod evident, nu se poate ca un modul sa fie complet nchis. In anumite situatii este necesar sa modificam cod existent. Totusi aplicatia trebuie
gandita astfel ncat sa permita acest lucru ntr-un mod cat mai flexibil si
premeditat.
Exista nca doua principii importante referitoare la designul modulelor
ntr-o aplicatie (ele fac parte dintr-o suita mai mare de astfel de sfaturi care
poarta numele GRASP - General Responsabilities Assignmnet Software Patterns):
1. Intre componentele unui modul (clasa, pachet, etc.) trebuie sa existe
o coeziune nalta. Aceasta nseamna ca nu este bine, spre exemplu, ca
ntr-o clasa sa avem mai multe informatii si metode ntre care nu exista
legaturi stranse. Exista metrici specializate pentru masurarea acestei
caracteristici.
2. Intre diversele parti componente ale unei aplicatii trebuie sa existe o
cuplare slaba. Aceasta nseamna ca atunci cand modificam un modul,
modificarile asupra lui sa nu genereze modificari n cascada asupra altor
module.
In final vom spune cateva cuvinte despre un alt principiu foarte important
referitor la programarea obiect orientata si anume principiul numit Inversion
of Control (IoC). Acesta este un principiu abstract care descrie un anumit
aspect referitor la designul sistemelor soft n care fluxul evenimentelor este
invers fata de cursul normal ntr-o aplicatie traditionala.
El a fost asemanat cu principiul numit Hollywood Principle: dont call
us, well call you.
Se poate spune ca IoC este un mod de a scrie software n care un cod
generic si reutilizabil poate fi aplicat la diverse probleme.
Exista doua moduri de lucru care au la baza principiul IoC:
programarea orientata pe evenimente (event-driven programming)
36
CAPITOLUL
Obiecte si clase
In limbajul Java pentru a crea pana si cea mai simpla aplicatie este nevoie
sa cream macar o clasa.
Dupa cum vom vedea n continuare o aplicatie Java este alcatuita, n
principiu, din mai multe clase care colaboreaza ntre ele. De obicei exista o
clasa care contine si o metoda main() si care constituie punctul de intrare n
aplicatie, clasa care foloseste alte clase la rularea aplicatiei.
Se poate ntampla ca o aplicatie sa aiba mai multe metode main(),
situatie n care, la rularea programului putem specifica care este clasa a
carei metoda se va executa.
4.1
38
4.2
39
4.2.1
Modificatorii de vizibilitate
40
4.2.2
Modificatorul final
Un atribut care este declarat ca final nu mai poate sa-si schimbe valoarea
ntr-o atribuire ulterioara.
Acest lucru nseamna pentru tipurile primitive ca valoarea lor este constanta, iar pentru tipurile referinta ca nu se mai poate modifica adresa catre
obiectul catre care pointeaza.
Iata si cateva exemple:
class Test
{
final int a=100;
final String s="test";
final int[] b={2, 4, 5};
void metoda()
{
//genereaza eroare deoarece nu se poate modifica un atribut de
//un tip primitiv declarat constant
a=1000;
//va genera eroare deoarece cand se modifica valoarea unui
//obiect de tip String automat se aloca memorie pt un nou sir
s="alt test";
//functioneaza deoarece nu se modifica adresa retinuta de sir
b[2]=4;
//nu functioneaza deoarece se modifica adresa retinuta de sir
b=new int[5];
}
}
4.2.3
41
Modificatorul static
class Test
{
public static int atributStatic;
public int atributNestatic;
}
public class ExempluStatic
{
public static void main(String args[])
{
Test t1=new Test();
Test t2=new Test();
t1.atributNestatic=3;
t2.atributNestatic=6;
System.out.println(t1.atributNestatic+" "+t2.atributNestatic);
//afiseaza valorile 3 si 6
t1.atributStatic=1;
t2.atributStatic=2;
System.out.println(t1.atributStatic+" "+Test.atributStatic);
//afiseaza valorile 2 si 2
}
}
42
4.2.4
4.3
4.3.1
43
Modificatorul static
Prin specificarea unei metode ca fiind o metoda statica, practic, i comunicam calculatorului ca acea metoda nu a fost creata pentru apelarea ei
asupra obiectelor ci mai degraba avem o metoda a unei clase, care poate
folosi numai atribute si metode statice ale clasei.
Acesta este motivul pentru care pana acum, de fiecare data cand scriam
o metoda trebuia ca acea metoda sa fie statica (din metoda main() care este
statica nu se pot apela decat metode statice).
Prezentam n continuare un exemplu de clasa pentru care are sens sa
definim metode statice:
class Mathematica
{
private Mathematica()
{
}
public static int max(int a, int b)
{
return a>=b?a:b;
}
public static int abs(int a)
{
return a>=0 ? a : -a;
}
}
public class Testare
{
public static void main(String args[])
{
System.out.println(Mathematica.max(3,4));
}
}
4.3.2
44
4.4
45
46
}
Observatii:
Daca ntr-o metoda numele unui parametru al metodei este acelasi cu
numele atributului clasei, atunci pentru a se putea face distinctia ntre
cele doua se foloseste cuvantul cheie this pentru a specifica un atribut
al clasei.
Se poate ca dintr-un constructor sa se apeleze un alt constructor al
aceleiasi clase. Am facut acest lucru cu ajutorul cuvantului cheie this,
care primeste n paranteza parametri catre acel constructor. Apelul
acesta trebuie sa fie prima instructiune din cadrul constructorului apelant.
4.5
Initializatorul static al unei clase este codul care este executat prima oara
cand se foloseste o clasa. Acesta este marcat prin cuvantul cheie static urmat
de acolade ntre care se specifica codul de executat.
Iata si un exemplu:
class Test
{
static int max=10;
static
{
max=100;
System.out.println("In initializatorul static");
}
}
public class FolosireInitializatorStatic
{
public static void main(String args[])
{
Test t=new Test();
}
}
4.6
47
Probleme rezolvate
48
49
50
51
{
int[] newElemente=new int[2*elemente.length];
System.arraycopy(elemente, 0, newElemente, 0, elemente.length);
elemente=newElemente;
}
private boolean isFull()
{
return top==elemente.length;
}
public boolean isEmpty()
{
return top==0;
}
public void push(int x)
{
if(isFull())
expandare();
elemente[top++]=x;
}
public int top()
{
return elemente[top-1];
}
public int pop()
{
return elemente[--top];
}
public static void main(String args[])
{
Stack s=new Stack();
s.push(3);
s.push(2);
System.out.println(s.top());
}
}
52
import java.util.Scanner;
public class TestSpanzuratoare
{
private static void afisare(char[] c)
{
for(int i=0;i<c.length-1;i++)
System.out.print(c[i]+" ");
System.out.println(c[c.length-1]);
}
public static void main(String args[])
{
Scanner s=new Scanner(System.in);
Spanzuratoare joc=new Spanzuratoare();
while(!joc.isOver())
{
System.out.print("Cuvantul de ghicit: ");
afisare(joc.cuvantCurent());
System.out.print("Introduceti o litera: ");
char c=s.nextLine().charAt(0);
if(joc.ghiceste(c))
System.out.println("BRAVO!!! Ai ghicit !");
else
System.out.println("GRESEALA!!! Mai ai "+joc.incercariRamase()+" ince
}
if(joc.isWinner())
System.out.println("AI CASTIGAT!!!");
else
System.out.println("AI PIERDUT!!!");
}
}
53
54
55
56
57
58
}
Dupa cum se poate usor observa vom avea nevoie de doua clase: Queue
si EmptyQueueException.
Clasa Queue are urmatoarea interfata:
Queue
--------------------------public Queue()
public
public
public
public
void push(int x)
int top()
int pop()
boolean isEmpty()
59
60
61
sb.append("]");
return sb.toString();
}
}
Problema 6 Sa se construiasca o clasa HeapMin care sa ne permita sa
lucram cu heapuri minime.
Ea ar trebui sa poata fi folosita ntr-unul din modurile urmatoare:
import java.util.Random;
public class TestHeapMin
{
public static void main(String args[])
{
/*Random r=new Random();
int[] a={0, 2, 4, 8, 7};
HeapMin heap=new HeapMin(a);
for(int i=0;i<3;i++)
heap.add(r.nextInt(10));
System.out.println(heap);
while(!heap.isEmpty())
System.out.print(heap.extractMin()+" ");*/
Random r=new Random();
HeapMin heap=new HeapMin();
for(int i=0;i<5;i++)
heap.add(r.nextInt(10));
System.out.println(heap);
System.out.print("Elementul minim: "+heap.getMin());
}
}
62
HeapMin
--------------------------public HeapMin(int[] a)
public HeapMin()
public void add(int x)
public void add(int[] a)
public int extractMin()
public int getMin()
public boolean isEmpty()
public String toString()
Implementarea ei propriu-zisa poate arata ca n exemplul urmator:
public class HeapMin
{
private int count;
private int[] elements;
public HeapMin()
{
elements=new int[3];
}
public HeapMin(int[] a)
{
elements=new int[a.length+5];
System.arraycopy(a, 0, elements, 1, a.length);
count=a.length;
construiesteHeap();
}
private void expand()
{
int newSize;
if(elements.length<10)
newSize=elements.length*2;
63
else
newSize=elements.length*4/3;
int[] newElements=new int[newSize];
System.arraycopy(elements, 1, newElements, 1, elements.length-1);
elements=newElements;
}
private boolean isFull()
{
return count==elements.length-1;
}
public void add(int x)
{
if(isFull())
expand();
elements[++count]=x;
int j=count;
while(j!=1 && elements[j/2]>elements[j])
{
int aux=elements[j];
elements[j]=elements[j/2];
elements[j/2]=aux;
j=j/2;
}
}
public void add(int[] a)
{
for(int x:a)
add(x);
}
private void construiesteHeap()
{
for(int i=count/2;i>=1;i--)
reconstituieHeap(i);
}
private void reconstituieHeap(int i)
{
64
65
4.7
Probleme propuse
66
CAPITOLUL
Mostenirea n Java
5.1
Notiuni generale
68
O subclasa descrie obiecte care au aceleasi proprietati ca si cele ale superclasei si care, eventual, au si alte atribute sau metode.
Atributele si metodele din superclasa sunt accesibile si n subclasa, cu
exceptia atributelor si metodelor care sunt declarate private n superclasa.
De multe ori, atributele private din superclasa pot fi accesate prin intermediul
unor metode din superclasa.
Reamintim ca n limbajul Java exista modificatorul de vizibilitate protected care are urmatoarea semnificatie: acele atribute sau metode cu aceasta
vizibilitate sunt vazute oriunde n subclase precum si n toate clasele din pachetul curent.
Dupa cum stim si din C++, atunci cand avem mostenire, trebuie sa putem
apela din constructorul unei clase constructorul clasei de baza. Acest lucru
se poate face cu ajutorul cuvantului cheie super. Apelul constructorului din
clasa de baza trebuie sa fie prima instructiune din constructor.
Un astfel de exemplu este prezentat n continuare:
public class Profesor extends Persoana
{
private String gradDidactic;
public Profesor(String nume, String prenume, String grad)
{
super(nume, prenume);
this.gradDidactic=grad;
}
...
}
Observatie: Daca nu apelam dintr-un constructor dintr-o clasa derivata
un constructor din clasa de baza, atunci automat se apeleaza constructorul
fara parametri din clasa de baza. De aceea, trebuie sa fim atenti, pentru ca
n situatia n care avem doar constructori cu parametri n clasa de baza si
n constructorul din clasa derivata nu apelam pe niciunul din ei, vom obtine
eroare.
5.2
69
care-l are, iar pentru fiecare student se cunoaste daca este bursier sau nu. Sa
se sorteze crescator sirul de persoane dupa nume si sa se afiseze sirul obtinut.
In primul rand definim o clasa Persoan
a astfel:
public class Persoana
{
private String nume;
private String prenume;
public Persoana(String nume, String prenume)
{
this.nume = nume;
this.prenume = prenume;
}
public String getNume()
{
return nume;
}
public void setNume(String nume)
{
this.nume = nume;
}
public String getPrenume()
{
return prenume;
}
public void setPrenume(String prenume)
{
this.prenume = prenume;
}
public String toString()
{
return nume + " " + prenume;
}
}
Definim o clasa Profesor derivata din clasa Persoana:
70
71
72
5.3. POLIMORFISMUL
73
5.3
Polimorfismul
74
5.4
75
5.5
Operatia de casting
76
5.6
Clase abstracte
77
}
public abstract double aria();
public abstract double perimetru();
}
Observam ca aceasta clasa este abstracta si ca ea are doua metode abstracte, cele care calculeaza aria si respectiv perimetrul unei figuri geometrice.
O clasa abstracta este o clasa care nu poate fi instantiata n mod direct.
O metoda abstracta a unei clase este o metoda care are sens pentru acea
clasa dar a carei implementare nu poate fi oferita la momentul respectiv.
O clasa care are o metoda abstracta automat trebuie sa fie abstracta. Pe
de alta parte, putem avea clase abstracte care nu au nici o metoda abstracta.
Prima afirmatie este foarte naturala, deoarece ar fi greu de imaginat sa
putem crea instante ale unei clase care are niste metode neimplementate. In
situatia n care programatorul ar apela acele metode compilatorul nu ar stii
ce trebuie sa faca.
In cele ce urmeaza ne definim clasele Cerc si Dreptunghi care sunt
derivate din clasa Figura. Ele arata astfel:
public class Cerc extends Figura
{
private double raza;
public Cerc(String culoare, double raza)
{
//apel constructor din clasa de baza
super(culoare);
this.raza=raza;
}
public double getRaza()
{
return raza;
}
public void setRaza(double raza)
{
this.raza = raza;
}
78
79
}
public void setLatime(double latime)
{
this.latime = latime;
}
public double aria()
{
return lungime*latime;
}
public double perimetru()
{
return 2*(lungime+latime);
}
public String toString()
{
return "Dreptunghi de lungime "+lungime+", latime de "+
latime+"si culoare: "+super.getCuloare();
}
}
Observam ca n exemplul de mai sus clasele prezentate implementeaza
metodele aria() si perimetru() care erau declarate abstracte n clasa Figura.
Daca macar una din cele doua metode nu era implementata ar fi trebuit ca
clasa care nu o implementa sa fie abstracta (conform regulii care zice ca o
clasa care are metode abstracte este obligatoriu abstracta).
Programul care foloseste cele 3 clase reprezentate anterior este prezentat
n cele ce urmeaza:
import java.util.Scanner;
public class TestFiguri
{
public static void main(String[] args)
{
Scanner s=new Scanner(System.in);
System.out.print("Numarul de figuri geometrice: ");
int n=Integer.parseInt(s.nextLine());
80
81
}
private static void afisare(Figura[] f)
{
for(Figura fig:f)
System.out.println(fig);
}
}
Putem remarca ca n acest exemplu metoda aria() este tratata polimorfic,
deoarece n metoda main() ea este utilizata ntr-un asa mod ncat nu se poate
spune la momentul compilarii care metoda se va apela.
Solutia acestei probleme se poate reprezenta cu ajutorul diagramei de
clase reprezentata n figura 5.2.
82
5.7
Clasa Object
In Java, chiar daca acest lucru nu este vizibil n mod direct, toate clasele
sunt derivate din clasa Object. Acest lucru nseamna ca ele au deja o anumita
functionalitate deja definita, si ca au, de asemenea, anumite metode pe care
le pot suprascrie.
Metodele clasei Object sunt sintetizate n diagrama de clase din figura
5.3.
5.7.1
83
Metoda toString()
5.7.2
Metoda equals()
84
5.7.3
Metoda hashCode()
5.7.4
Metoda clone()
Metoda clone() este folosita pentru a crea o copie a unui obiect. Trebuie
ca atunci cand realizam copia unui obiect sa creem un nou obiect care nu
partajeaza absolut nimic cu vechiul obiect.
In primul rand trebuie spus ca exista situatii n care nu vrem ca o instanta
a unui obiect sa poata fi clonata. Daca suntem n aceasta situatie nu trebuie
5.8
Datorita faptului ca toate clasele n Java sunt derivate din clasa Object
se poate ca sa definim colectii care sa poata fi utilizate pentru a retine obiecte
de orice tip.
Acest lucru se face prin retinerea elementelor care alcatuiesc colectia n
structuri bazate pe clasa Object.
86
88
5.9
Cel mai bine pentru a ntelege cum se folosesc aceste liste, prezentam un
exemplu de folosire a lor.
import java.util.*;
public class TestLista {
public static void main(String[] args) {
List<String> lista=new LinkedList<String>();
lista.add("test1");
lista.add("test2");
lista.add("test3");
for(String s:lista)
90
System.out.println(s);
System.out.println("-----------------------------");
Iterator<String> iterator=lista.iterator();
while(iterator.hasNext())
{
String str=iterator.next();
System.out.println(str);
}
lista.remove("test2");
lista.add("test4");
System.out.println("-----------------------------");
for(int i=0;i<lista.size();i++)
{
String str=lista.get(i);
System.out.println(str);
}
System.out.println("-----------------------------");
System.out.println("Rezultat contains: "+lista.contains("test2"));
}
}
Se poate testa faptul ca n noua lista nu se mai pot introduce elemente
de alte tipuri decat cel declarat. Se poate observa, de asemenea, ca nu mai
este nevoie de operatii de cast pentru a obtine un anumit obiect din colectie.
Deocamdata nu intram n mai multe amanunte relativ la folosirea colectiilor
n Java, urmand a reveni n capitolul special dedicat colectiilor Java.
5.9.1
In mod normal n colectii nu se pot retine decat obiecte. Acest lucru era
valabil la versiunile mai vechi de Java. In versiunile mai noi s-a introdus
conceptul de boxing care face posibil urmatorul cod:
ArrayList<Integer> lista=new ArrayList<Integer>();
92
CAPITOLUL
Unul din cele mai importante lucruri pentru orice programator care foloseste
programarea obiect orientata este ntelegerea mecanismului care sta la baza
lucrului cu exceptii.
Evident, ar fi de dorit ca n practica sa nu apara exceptii, dar dupa cum
fiecare dintre noi a observat, acest lucru este imposibil. Astfel, este important
sa le tratam corespunzator.
Mecanismul de lucru cu exceptii n Java seamana foarte mult cu mecanismul pe care deja l cunoastem din C/C++.
In momentul n care apare o exceptie, cel care utilizeaza programul sau
programatorul trebuie sa fie nstiintat pentru a o putea trata corespunzator.
Astfel, aplicatia trebuie sa fie capabila sa faca unul din urmatoarele doua
lucruri:
Sa termine aplicatia ntr-un mod civilizat (cu salvarea eventual a lucrurilor care trebuie salvate, nchiderea conexiunilor care se folosesc n
aplicatie)
Sa permita utilizatorului sa se ntoarca la o stare din care sa poata
continua aplicatia (de exemplu, daca o citire nu reuseste, trebuie sa mi
se permita sa reiau acest pas sau sa tratez altfel aceasta situatie).
Teoretic, chiar daca acest lucru este mult mai complicat si mai putin elegant, se pot ncerca si alte abordari ale tratarii exceptiilor decat cele folosite
n limbajul Java. Astfel, se poate de exemplu, ca fiecare metoda sa returneze
un anumit cod, care sa ne spuna daca metoda a reusit sau nu.
93
94
6.1
Clasificarea exceptiilor
Exceptiile care pot fi ntalnite ntr-un program Java sunt de doua feluri:
unchecked exceptions - sunt acele exceptii care apar la momentul rularii
dar pe care programatorul nu este obligat sa le vaneze (sa le trateze
n mod explicit). Exemple de astfel de exceptii sunt: ArrayIndexOutOfBoundsException, DivisionByZeroException etc.
checked exceptions - exceptiile pe care programatorul este obligat sa le
ia n considerare (el trebuie sa fie constient de faptul ca acestea pot
aparea ntr-un anumit loc). Astfel de exceptii sunt: FileNotFoundException, IOException etc.
Cele mai importante clase care sunt folosite n Java pentru tratarea
exceptiilor sunt Throwable, Exception, Error si RuntimeException. Ele
se afla n relatiile prezentate n figura 6.1.
95
Toate exceptiile sunt derivate din clasa Throwable care se comporta pentru exceptii in modul n care Object se comporta pentru toate clasele. Avem
doua tipuri derivate din Throwable si anume Error (erori care apar din cauza
masinii virtuale si care n principiu sunt foarte greu de tratat; tot ceea ce
se poate face este sa ncheiem programul ntr-un mod elegant) si Exception
(erori care apar din cauze care nu tin de implementarea masinii virtuale).
Un caz mai deosebit de erori sunt cele de tipul RuntimeException care
sunt erorile unchecked de tipul Exception. Aceste erori sunt acele erori care
nu tin de masina virtuala ci mai degraba de programator si care daca ar trebui
tratate de fiecare data ar ngreuna foarte mult scrierea codului. Astfel,ar fi
greu daca de fiecare data cand folosim un sir sau o matrice am verifica daca
nu cumva se foloseste un element din afara matricii.
Totusi, n aceste situatii se poate trata o eroare de acest tip.
Erorile de tip Exception care nu sunt de tipul RuntimeException sunt
erori care trebuie neaparat tratate ntr-un fel de programator (checked errors).
6.2
Pentru a crea o noua exceptie n Java, trebuie sa scriem o clasa care este
derivata direct sau indirect din clasa Exception.
De exemplu, pentru a crea o exceptie de tipul checked exception putem
scrie urmatorul cod:
class MatriciIncompatibileException extends Exception
{
public MatriciIncompatibileException()
{
}
public MatriciIncompatibileException(String message)
{
super(message);
}
}
Noua clasa pentru tratarea unei exceptii poate fi derivata si dintr-o alta
clasa de tipul exceptie.
Daca dorim crearea unei exceptii unchecked derivam clasa exceptie din
RuntimeException sau dintr-o clasa derivata din aceasta:
96
6.3
Aruncarea exceptiilor
6.4
Prinderea exceptiilor
97
try {
instr1;
instr2;
....
}
catch(Exception1 e){
//tratare exceptie 1
}
catch(Exception2 e){
//tratare exceptie 2
}
finally{
//aici am cod care se executa mereu
//indiferent daca a aparut exceptie sau nu
}
Daca ntre instructiunile din blocul try nu apare nici o eroare atunci se
executa toate aceste instructiuni dupa care se executa toate instructiunile
din blocul finally.
Daca la un moment dat apare eroare cand se executa o instructiune n
blocul try atunci executia instructiunilor din acel bloc se opreste si se executa
instructiunile doar din primul catch care prinde eroarea potrivita, dupa care
se executa instructiunile din blocul finally.
Dupa cum se poate observa se poate sa avem mai multe blocuri catch
dar un singur bloc finally. Trebuie remarcat, de asemenea, ca blocul finally
poate lipsi.
In momentul n care scriem cod n care la un moment dat poate aparea o
exceptie de tipul checked putem sa rezolvam problema n unul din urmatoarele
moduri:
Daca nu stim cum sa tratam eroarea si vrem ca ea sa fie tratata n
alta parte, putem sa aruncam eroarea mai departe. Pentru acest lucru
trebuie sa specificam ca acea metoda poate arunca eroarea respectiva
n clauza throws.
Daca nu stim cum sa tratam eroarea dar vrem sa aruncam mai departe
o alta eroare, putem folosi un bloc try-catch n care pe ramura de catch
corespunzatoare exceptiei sa aruncam o alta exceptie.
Putem trata exceptia direct n sectiunea catch corespunzatoare.
98
6.5
6.6
Exemple