Documente Academic
Documente Profesional
Documente Cultură
2020-2021, Semestrul 1
1. Organizarea activităţii
Colecţii de obiecte
Interfeţe (Collection, Set, List, etc), implementări (HashSet, ArrayList, etc) şi algoritmi (pentru ordonarea colecţiilor,
dereminarea valorii minime, căutarea unui element)
Tratarea excepţiilor
Mecanismul de emitere-captare a excepţiilor, Instrucţiunea throw, clauza throws, care tipuri de excepţie vor apărea
într-o clauză throws, blocurile try-catch, secvenţa finally, excepţii predefinite ale limbajului Java
Caracteristicile Java 8
Metode implicite în interfețe, interfețe funcționale, expresii Lambda, referințe la metode, stream API, date time
API
Fire de execuție
Crearea firelor de executie, sincronizarea acestora, modelul producator consumator, etc
3
Aplicaţii cu interfaţă grafică:
Servleturi:
4
1.3 Instrumentele software necesare
MySQL
http://dev.mysql.com/downloads/installer/
Apache Tomcat
http://tomcat.apache.org/
Android Studio
https://developer.android.com/studio/index.html
5
1.4 Orarul activităţilor online
1.6 Evaluarea
Prima implementare JDK (Java Development Kit) a fost lansată în 1995 (versiunile alpha şi beta) şi
urmărea principiul "Write Once, Run Anywhere“ . JDK 1.0 a fost lansată în 1996
Versiuni de Java:
Java SE (Java Standard Edition)
Java EE (Java Enterprise Edition)
Java ME (Java Micro Edition)
Caracteristici
Traducere în executabil în 2 faze:
Compilarea: text Java -> cod de maşină virtuală Java (“byte code” sau cod intermediar)
Interpretarea: cod de maşină virtuală Java - > cod de maşină de execuţie efectivă, fizică
7
Are un mare grad de independenţă de platformă
Este concurent
Este distribuit - Programele Java pot îngloba, alături de obiecte locale, obiecte aflate la distanţă,
în mod normal în reţea, inclusiv în Internet. În Java, sunt respectate protocoalele de reţea FTP,
HTTP, etc
Este dinamic şi robust. În Java, alocarea memoriei este prin excelenţă dinamică –adică: nu se
face la compilare / linkeditare, ci în execuţie- şi orice alocare este precedată de verificări.
Este sigur. Înainte ca interpretorul Java să execute codul intermediar, acesta este supus unor
verificări de tipul: nedepăşirea stivei, etc.
8
3. JDK – Java Development Kit
compilatorul Java: javac
interpretorul de cod intermediar: java (este specific pentru fiecare maşină ţintă)
un depanator: jdb
etc
9
4. Pachete Java
java.lang - conţine clasele de bază (clasa Object, clasele înfăşurătoare, clase pentru tratarea
excepţiilor, clase pentru lucru cu fire de execuţie, etc)
java.util – conţine clasele necesare pentru lucrul cu colecţii de obiecte şi alte clase cu rol utilitar
java.rmi - conţine clase suport pentru apelul unor metode ale unor obiecte aflate la distanţă
Ş.a
10
5. Medii integrate de dezvoltare pentru Java
Eclipse (proiectat iniţial de IBM, dar aflat acum în stadiu de open source)
Probabil că, la ora actuală, cel mai popular dintre toate acestea este Eclipse.
11
2. Elementele de bază ale
limbajului Java
2020-2021, Semestrul 1
2.1 Alfabetul Java
Unicode - 32 768 caractere codificate pe 2 octeţi
Primele 256 coincid cu cele 256 ale standardului ASCII
Afişare caractere cu \uxxxx, unde xxxx=valoare hexa
System.out.print('\u0061'); //afişează a pe ecran
2
2.3 Identificatorii în limbajul Java
secvenţe de caractere Unicode de lungime nelimitată, dintre care primul este literă,
iar celelalte sunt litere sau cifre
Constante întregi
Octale – precedate de cifra 0, formate din cifre de la 0 la 7
Zecimale – prima cifra diferită de 0, iar restul cifre de la 0 la 9
Hexazecimale – precedate de grupul de caractere 0x, formate din cifre de la 0 la 9 şi/sau litere de la ‘a’ la ‘f’
Dacă înşiruirile respective nu sunt urmate de niciun sufix, atunci constantele în cauză se reprezintă intern pe
4 octeţi. Dacă înşiruirile respective sunt urmate de sufixul ”L”, atunci constantele în cauză se reprezintă
intern pe 8 octeţi. În ambele cazuri, reprezentarea internă este ”complement de doi”.
3
Exemple de constante întregi
023 notaţie octală, reprezentând constanta 19, exprimată intern pe 4 octeţi
23 notaţie zecimală, reprezentând constanta 23, exprimată intern pe 4 octeţi
0x15 notaţie hexazecimală, reprezentând constanta 21, exprimată intern pe 4 octeţi
0xffffffff notaţie hexazecimală, reprezentând constanta -1, exprimată intern pe 4 octeţi
023L notaţie octală, reprezentând constanta 19, exprimată intern pe 8 octeţi
23L notaţie zecimală, reprezentând constanta 23, exprimată intern pe 8 octeţi
0x15L notaţie hexazecimală, reprezentând constanta 21, exprimată intern pe 8 octeţi
0xffffffffL notaţie hexazecimală, reprezentând constanta -1, exprimată intern pe 8 octeţi
Constante caracter
System.out.println('A');
System.out.println('\u0041'); //secventa escape
System.out.println(‘\t’);//secventa escape speciala carcaterul t reprezintă tab, alte caractere posibile sunt:
b - pentru backspace
n - pentru line feed
f - pentru form feed
r - pentru carriage return
“ - pentru double quote
‘ - pentru single quote
\ - pentru backslash
Constantele şir
- secvenţe de caractere Unicode delimitate de ghilimele
- Exemplu:
System.out.println(”Automatica si Calculatoare”);
System.out.println(”Vechiul nume: Universitatea \”Politehnica\” din Timisoara”);
intregi
int
long
aritmetice
float
reale
double
primitive logice boolean
Adrese de obiecte
referinţă
Adrese de tablouri
6
2.5.2 Spaţiul ocupat şi domeniul de valori al variabilelor
7
2.5.3 Clasele înfăşurătoare în Java
Clasele înfășuratoare (wrapper classes) sunt clase asociate tipurilor primitive.
Clasele înfăsurătoare sunt: Byte, Short, Integer, Long, Float, Double, Boolean, Character
Obiectul clasei înfășurătoare conține o valoare a tipului primitiv asociat și dispune de metode care
permit diverse prelucrări asupra valorii primitive asociate
Instanțierea:
8
Conversia automată pe care compilatorul Java o face între tipurile primitive și
obiectele corespunzătoare claselor lor înfășurătoare se numește autoboxing
Integer intVar2;
intVar2=Integer.valueOf("123"); //conversie din String in Integer
int intVar3;
intVar3=Integer.parseInt("123"); //conversie din String in int
9
2.5.4 Tablourile în Java
Crearea şi iniţializarea tablourilor
int[] alfa=new int[5];
alfa[0]=100;
alfa[1]=200;
….
alfa[4]=500;
SAU
int[] alfa={100,200,300,400,500};
10
Copierea tablourilor
Copierea tablourilor se poate realiza cu ajutorul metodei statice arraycopy() din clasa
System sau cu ajutorul metodei statice copyOf() din clasa Arrays
public static void arraycopy (Object referinţăTablouSursă,
int indiceÎnSursă,
Object referinţăTablouDestinaţie,
int indiceÎnDestinaţie,
int numărElementeDeCopiat)
package exemplu;
a[0]=99;
System.out.println("a[0]="+a[0]+" b[0]="+b[0]);//Output a[0]=99 b[0]=99
11
int []c= {1,2,3};
int []d=new int[c.length];
System.arraycopy(c, 0, d, 0, c.length);
//valorile din zona de memorie a lui c se copiaza in zona de memorie a lui d
c[0]=99;
System.out.println("c[0]="+c[0]+" d[0]="+d[0]);
}
}
Ordonarea tablourilor
12
package exemplu;
import java.util.Arrays;
String[][] persoane = { { "Dl. ", "Dna. ", "Dsra. " }, { "Popescu", "Georgescu" } };
14
2.5.5 Şirurile de caractere în Java
Clasa String
Crearea și inițializarea String-urilor
String sir; //sau: String sir=”hello!”;
sir=”hello!”;
//sau:
String sir=new String(”hello!”);
//sau:
char[] helloArray={'h','e','l','l','o','!'};
String sir=new String(helloArray);
System.out.println(sir); // afişează: “hello!”
Lungimea unui String
System.out.println(sir.length()); // afişează:6
Concatenarea şirurilor
cu operatorul +
cu metoda concat() a clasei String
String s1=“afara”;
String s2=“ploua”;
int i=3;
double d=7;
String s1=Integer.toString(i);
String s2=Double.toString(d);
17
Căutarea unui caracter într-un şir dat
System.out.println(alfa.indexOf('a')); //Afiseaza 3
System.out.println(alfa.indexOf('a',4)); //Afiseaza 10
System.out.println(alfa.lastIndexOf('a')); //Afiseaza 38
System.out.println(alfa.lastIndexOf('a',37)); //Afiseaza 26
18
Compararea şirurilor şi porţiunilor de şiruri
System.out.println(alfa.startsWith("Luna")); //true
System.out.println(alfa.startsWith("tu",5)); //true
System.out.println(alfa.endsWith("Luneci")); //false
String beta=“abcd”;
System.out.println(beta.compareTo(“abce”)); //-1
System.out.println(beta.compareToIgnoreCase("ABCD")); //0
System.out.println(beta.equals("ABCD")); //false
System.out.println(beta.equalsIgnoreCase("ABCD")); //true
System.out.println(beta.regionMatches(1, "aaaBCd", 3, 2));//false
System.out.println(beta.regionMatches(true,1, "aaaBCd", 3, 2));//true
21
22
Operatorii limbajului Java, în ordinea puterii de precedenţă
23
2.7 Instrucţiile limbajului Java
Instrucţia if-then-else
if(expresieLogica){ //secvenţa de instrucţii dintre aceste acolade se execută doar dacă expresieLogica are valoarea true
…
}
else{ //secvenţa de instrucţii dintre aceste acolade se execută doar dacă expresieLogica are valoarea false
...
}
Instrucţia switch
class SwitchDemo{
public static void main(String[] args){
int month=8;
switch(month){ //se va executa doar linia de instrucţii pt. care parametrul etichetei caseeste egal cu valoarea variabilei month
case 1: System.out.println("January"); break;
case 2: System.out.println("February"); break;
case 3: System.out.println("March"); break;
case 4: System.out.println("April"); break;
case 5: System.out.println("May"); break;
case 6: System.out.println("June"); break;
case 7: System.out.println("July"); break;
case 8: System.out.println("August"); break;
case 9: System.out.println("September"); break;
case 10: System.out.println("October"); break;
case 11: System.out.println("November"); break;
case 12: System.out.println("December"); break;
default: System.out.println("Invalid month.");break;
}
}
}
24
Instrucţia while
while(expresieLogica){ // verifică dacă expresieLogica=true şi execută instrucţiile dintre
// acolade cât timp această condiţie este îndeplinită
...
}
Instrucţia do..while
do{ // execută instrucţiile dintre acolade şi apoi verifică dacă expresieLogica=true;
// în caz afirmativ reia totul, altfel treci la instrucţia următoare
...
} while(expresieLogica);
Instrucţia for
class ForDemo{ class EnhancedForDemo{
public static void main(String[] args){ public static void main(String[] args){
for(int i=1; i<11; i++){ int[] numbers={1,2,3,4,5,6,7,8,9,10};
System.out.println(“Contorul este: " + i); for(int item:numbers){
} System.out.println("Count is: " + item);
} }
} }
}
25
Instrucţia break
class BreakDemo{
public static void main(String[] args){
int[] arrayOfInts={32,87,3,589,12,1076,2000,8,622,127};
int searchfor=12;
int i;
boolean foundIt=false;
for(i=0;i<arrayOfInts.length;i++){
if(arrayOfInts[i]==searchfor){
foundIt=true;
break;
}
}
if(foundIt){
System.out.println("Found "+searchfor+" at index "+i);
}
else{
System.out.println(searchfor+" not in the array");
}
}
}
26
Instrucţia continue
class ContinueDemo{
public static void main(String[] args){
String searchMe="Un vultur sta pe pisc c-un pix in plisc";
int max=searchMe.length();
int numPs=0;
for(int i=0;i<max;i++){
if(searchMe.charAt(i)!='p')
continue;
numPs++;
}
System.out.println("Found "+numPs+" p's in the string.");
}
}
Instrucţia return
În metodele de tip void se foloseşte return;
În metodele de alt tip decât void se foloseşte return expresie, unde unde expresie trebuie să
fie în consonanţă cu tipul folosit la declararea metodei
27
3. Orientarea pe obiecte
2020-2021, Semestrul 1
3.1 Noţiuni generale
Declararea unei clase este similară cu declararea unui nou tip de date
Polimorfismul este abilitatea unui obiect de a lua mai multe forme. Una din cele
mai frecvente utilizări ale polimorfismului în POO este când o referinţă a unei clase
de bază este utilizată pentru a referi un obiect al clasei derivate
O clasă poate fi extinsă prin redefinirea unor metode şi / sau adăugarea unor
metode noi
O metodă care redefineşte o alta din clasa de bază are acelaşi nume, acelaşi tip
de rezultat sau o subclasa a acestuia şi aceeaşi listă de parametri
În cazul în care o clasă derivată are variabile membru cu acelaşi nume ca şi clasa
de bază nu este vorba de o redefinire, cei doi parametri coexista si pot si referiţi
distinct
3
Moştenirea
Permisă doar moştenirea simplă, spre deosebire de C++
Clasa moştenită – superclasă sau supraclasă sau clasă de bază
Clasa care realizează extinderea- subclasă sau clasă derivată
Un constructor este o metodă care acelaşi nume cu clasa şi este apelată implicit la
crearea obiectului
Interfaţă unui obiect –modul în care un obiect este cunoscut din exterior
Rădăcina ierarhiei de clase, clasa Object conţine o serie de metode finale care
vor fi moştenite de orice clasă definită în Java
4
Unele dintre metodele clasei Object nu sunt scrise în Java, deoarece implementarea
lor depinde de maşina pe care se face execuţia; despre aceste metode se spune că
sunt native
5
3.2 Moştenirea
Extinderea comportamentului unei clase existente prin definirea unei clase noi, care
moşteneşte conţinutul primei clase, adăugând la acesta elementele specifice ei
Clasa moştenită se numeşte clasă de bază, supraclasă sau superclasă, iar clasa care
realizează extinderea se numeşte subclasă, clasă derivată, sau clasă descendentă.
class nume_subclasa extends nume_supraclasa
{
//conţinut specific subclasei
}
class Poligon {
protected double[ ] laturi;
public Poligon(int n) { laturi = new double[n] }
public double perimetru( ) {
double s=0;
for(int i=0;i<laturi.length;i++) s+=laturi[i];
return s;
}
}
class Dreptunghi extends Poligon {
public Dreptunghi(double L, double h){
super(4);
laturi[0] = laturi[2] = L;
laturi[1] =laturi[3] = h;
}
public double aria( ){
return laturi[0]*laturi[1];
}
} 6
Clase derivate din clasa Object
în mod explicit:
class Chitara extends Object{
public String culoare;
public int nr_corzi;
}
în mod implicit:
class Chitara {
public String culoare;
public int nr_corzi;
}
sau
Chitara c=new Chitara();
În mod implicit prima instrucţiune dintr-un constructor este apelul constructorului fără
parametri ai supercasei. Singura abatere de la această regulă are loc atunci când
prima instrucţiune din constructor este un apel explicit la alt constructor al clasei sau
la un constructor al supraclasei.
Dacă într-o clasă se defineşte cel puţin un constructor, constructorul implicit fără
argumente nu mai este furnizat automat. Constructorii nu pot avea atributele abstract,
native, static, synchronized sau final
8
class Chitara {
private String culoare;
private int nr_corzi;
public Chitara(){
culoare=“Neagra”;
nr_corzi=6;
}
public Chitara(String culoare,int nr_corzi){
this.culoare=culoare;
this.nr_corzi=nr_corzi;
}
}
SAU:
class Chitara {
private String culoare;
private int nr_corzi;
public Chitara(String culoare,int nr_corzi){
this.culoare=culoare;
this.nr_corzi=nr_corzi;
}
public Chitara(){
this (“Neagra”,6);
}
}
private
se poate aplica constructorilor, variabilelor membre sau metodelor
restrânge nivelul de vizibilitate al variabilelor membre sau a metodelor
care au acest atribut doar la nivelul clasei
protected
se poate aplica constructorilor, variabilelor membre sau metodelor
metodele si variabilele membre protected sunt accesibile din metodele
clasei si din metodele subclaselor
un obiect al unei clase care conține variabile si metode protected nu
dispune de acces la acestea din afara pachetului (accesul este permis
doar daca obiectul se gaseste în același pachet cu clasa)
11
package exemplu2;
class Test {
protected String camp_protected;
}
class MainApp {
public static void main(String []args) {
Test t=new Test();
t.camp_protected="acces permis";
}
}
12
package exemplu2;
class Test {
String camp;
}
class MainApp {
public static void main(String []args) {
Test t=new Test();
t.camp="Acces permis";
}
}
13
package exemplu3;
import exemplu2.Test;
class OClasa{
void o_metoda() {
Test t=new Test();
//t.camp="Acces interzis";
}
}
14
3.5 Distrugerea obiectelor
Dacă spre un anumit obiect nu mai există nici o referinţă externă, în nici o funcţie
activă, acel obiect devine candidat la eliminarea din memorie
În metoda finalize pot fi scrise instrucţiuni care să reactiveze obiectul, sau poate fi
afişat un mesaj care precizează că obiectul urmează să fie distrus
Dacă există un cod care trebuie să se execute când un obiect nu mai este util atunci
acest cod trebuie scris într-o metodă care trebuie apelată în mod explicit pentru că nu
există garanţia că obiectul va fi distrus până se încheie programul 15
3.6 Conversii de tip
class Vapor{
private String denumire;
private int nr_membrii_echipaj;
v=c;
System.out.println(v.toString());
c=(VasDeCroaziera)v;
System.out.println(c.toString());
}
}
o=c;
…
c=(Ceva) o;
Fișierul ClasaExterioara.java
package clase_imbricate;
21
Declararea obiectelor clasei interioare se face cu ajutorul obiectelor clasei exterioare,
precum in exemplul de mai jos
Fișierul MainApp.java
package clase_imbricate;
22
3.9 Variabile şi metode statice. Secvenţe de cod statice.
Clase interioare statice
Variabilele statice ale unei clase sunt variabilele globale ale clasei, adică variabile a căror valoare
poate să fie referită de orice obiect din clasa respectivă
Pentru o variabilă membru statică se alocă memorie o singură dată indiferent de numărul de
obiecte de acel tip
O metodă statică poate să refere doar variabile sau metode statice, dar poate să fie apelată de
orice metoda a clasei
Class Aplicatie{
static final int versiune=3;
static int numarObiecte;
…
}
23
versiune este similară unei constante întregi şi globale din limbajul C
numarObiecte poate fi actualizată de orice obiect creat pentru a contoriza numărul total de obiecte
de tip Aplicatie
exemplul de mai jos arată că pentru o variabilă membru statică se alocă memorie o singură dată
indiferent de numărul de obiecte de acel tip
public class DespreStatic {
int x;
static int y;
DespreStatic(){
x=0;
y=0;
}
}
class Test{
public static void main(String args[]){
DespreStatic t1=new DespreStatic();
DespreStatic t2=new DespreStatic();
t1.x=10;
t1.y=10;
t2.x=20;
t2.y=20;
System.out.println("t1.x="+t1.x+" t1.y="+t1.y);
System.out.println("t2.x="+t2.x+" t2.y="+t2.y);
class Exemplu{
static{
Floare g=new Floare(7,“Laleaua");
g.afiseaza();
}
public static void main(String args[]){}
} 25
Clase interioare statice
Clasele interioare pot fi statice. În acest caz instantierea unui obiect al clasei
interioare nu mai necesita un obiect al clasei exterioare (vezi exemplul următor). Din
clasa interioara pot fi accesati membrii statici ai clasei exterioare
Fișierul Outer.java
package clase_imbricate;
26
3.10 Clase abstracte şi interfeţe
O clasă abstractă este o supraclasă pentru o ierarhie de clase
O interfaţă este doar o colecţie de constante şi metode abstracte care urmează să fie
implementate
Clase abstracte
abstract class Aplicatie extends Floare{
abstract void prelucrare();
}
O clasă abstractă poate să fie extinsă de o altă clasă abstractă sau de o clasă 27
normală
O metodă abstractă se află în mod obligatoriu într-o clasă abstractă sau într-o
interfaţă
28
Interfeţe
Variabilele de tip interfaţă pot fi utilizate ca argumente ale metodelor şi pot fi obţinute
ca rezultat, se pot crea ierarhii de interfeţe similare ierarhiilor de clase
interface Exemplu{
int versiune=3;
void prelucrare1();
void prelucrare2(Floare f);
}
29
class Implementare implements Exemplu{
…
void prelucrare1(){
…
}
void prelucrare2(Floare f){
...
}
void altaPrelucrare(){ //metoda care nu se gaseste in interfata
...
}
}
30
O interfaţă poate fi extensia unei alte interfeţe, adică poate să adauge noi modele de
metode la o interfaţă care există
interface Executabila{
public void executie();
}
public class Exemplu{
…
void prelucrare(Executabila e){
e.executie();
}
}
class Implementare implements Executabila{
public void executie(){
System.out.println(“s-a executat metoda executie din Implementare”)
}
}
31
….
new Exemplu().prelucrare(new Implementare());//se va apela metoda Implementare.executie()
O clasă anonimă este o expresie. Sintaxa unei clase anonime este asemănătoare cu
apelul unui constructor însoțit de definiția unei clase
package clase_anonime;
34
3.12 Clase generice
O clasă generică este o clasă care are parametri generici, enumerați între
parantezele unghiulare care însoțesc definiția clasei.
Valorile din interiorul parantezelor ungiulare reprezintă tipuri de date care vor fi
stabilite când se declară un obiect de tipul clasei respective.
35
class MainApp {
public static void main(String[] args) {
String nume1="Popescu Ion";
int varsta1=23;
Persoana<String, Integer> p1=new Persoana<String, Integer>(nume1, varsta1);
System.out.println(p1);
36
3.13 Metode generice
Metodele generice sunt metode care pot fi apelate cu argumente de diferite tipuri
package exemplu;
afiseazaVector(v1);
afiseazaVector(c);
}
} 37
3.13 Serializarea obiectelor
Serializarea obiectelor presupune descompunerea acestora într-o înșiruire de octeți
și salvarea lor într-un flux de date. Procesul opus, de recompunere a obiectelor din
șirul de octeți se numește deserializare
Pot să fie serializate obiectele oricărei clase care implementează intefața Serilizable
Câmpurile ale căror valoare nu se dorește să fie serializată trebuie să fie precedate
de cuvântul cheie transient
Fișierul Persoana.java:
package exemplu;
import java.io.Serializable;
39
Fișierul Adresa.java:
package exemplu;
import java.io.Serializable;
40
Fișierul MainApp.java:
package exemplu;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
41
static Object citeste(String fis) {
try {
FileInputStream f = new FileInputStream(fis);
ObjectInputStream ois = new ObjectInputStream(f);
Object o=ois.readObject();
ois.close();
f.close();
return o;
}
catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
Persoana []q;
q=(Persoana[])citeste("pers.bin");
for(Persoana p:q)
System.out.println(p);
}
} 42
Câmpul varsta fiind precedat de cuvântul cheie transient nu va fi serializat, își va
pierde valoarea
43
4. Colecţii de obiecte
2020-2021, Semestrul 1
4.1 Noţiuni generale
“The Collections Framework “ constituie o arhitectură unificată pentru reprezentarea şi
manipularea colecţiilor, permiţând manipularea acestora independent de detaliile implementării
lor.
Framework-ul este bazat pe interfeţele de colecţii din figura de mai jos. El include implementări
ale acestor interfeţe şi algoritmi pentru a le manipula
Interfeţe
Collection Map
SortedSet
2
Collection – un grup de obiecte. Este utilizată când se doreşte maximul de generalitate.
Map – o punere în corespondenţă cheilor şi valorilor (keys to values). Fiecare cheie corespunde
unei valori
SortedSet – un set a cărui elemente sunt automat ordonate, fie în ordine naturală fie printr-un
obiect de tip Comparator specificat când instanţa de tip SortedSet este creată. Extinde interfaţa
Set
SortedMap – un Map a cărui elemente sunt ordonate automat prin cheie fie în ordine naturală fie
printr-un comparator transmis instanţei SortedMap atunci când aceasta este creată
Implementări
HashSet - implementarea printr-un tabel de dispersie (HashTable) a interfeţei Set (cea mai bună
3
implementare a interfeţei Set)
TreeSet – implementarea printr-un arbore roşu – negru (Red-black tree) a interfeţei SortedSet.
Elementele sunt ordonate pe baza valorii lor
LinkedHashSet – implementarea interfeţei Set cu ajutorul unui tabel de dispersie şi a unei liste
înlănţuite (Linked list). O implementare care face inserare în ordinea adăugării şi care rulează
aproape la fel de rapid ca un HashSet
ArrayList – o implementare a interfeţei List printr-un vector care îşi ajustează dimensiunea (cea
mai bună implementare a interfeţei List).
LinkedList – o implementare a interfeţei List cu listă dublu înlănţuită. Poate furniza o performanţă
mai buna decât implementările cu ArrayList dacă elementele sunt inserate sau şterse frecvent
HashMap – Implementarea interfeţei Map cu ajutorul unui tabel de dispersie (în mod esenţial un
tabel de dispersie nesincronizat care suportă null pentru chei şi valori (cea mai bună
implementare a interfeţei Map)
4
Algoritmi
Algoritmii sunt furnizaţi de clasa Collections, sub forma unor metode statice, a căror prim
argument este colecţia de elemente asupra căreia se va aplică operaţia. Majoritatea algoritmilor
operează asupra unor instanţe List.
Algoritmii permit ordonarea ordonarea colecţiilor, căutarea unui element, determinarea valorii
maxime, a celei minime, etc
4.2 Interfeţe
În general trebuie să avem în minte interfeţele, nu modul în care acestea sunt implementate
Interfaţa Collection
O colecţie este formată dintr-un grup de obiecte. Interfaţa Collection este folosită pentru
transmiterea colecţiilor de obiecte în situaţii în care se doreşte maximul de generalitate
Interfaţa are metode precum:
size() – returnează numărul de elemente care fac parte din colecţie ()
isEmpty () - verifică dacă colecţia e goală ()
contains ()- verifică dacă un anumit obiect este în colecţie ()
add(), remove() - adaugă / elimină un obiect din colecţie ()
iterator() - furnizează un iterator pentru colecţie (), etc
Metoda de adăugare este definită destul de general încât să poată fi folosită in colecţii de
elemente care permit duplicatele respectiv în cele care nu permit acest lucru. Metodele add ()şi 5
remove() returnează true dacă adăugarea / ştergerea a reuşit şi false daca nu
Parcurgerea colecţiei
Parcurgerea cu for-each
Parcurgerea cu iterator
java.util.Iterator<Persoana> it=pers.iterator();
while (it.hasNext()){
p=it.next();
System.out.println(p.toString());
}
Bulk Operations
Realizează o operaţie asupra întregii colecţii. De exemplu:
containsAll() — returnează true dacă colecţia ţintă conţine toate elementele din colecţia
specificată
addAll() - adaugă toate elementele din colecţia specificată la colecţia ţintă
removeAll() – şterge din colecţia ţintă toate elementele care sunt de asemenea conţinute în
colecţia specificată
retainAll() – şterge din colecţia ţintă toate elementele care nu sunt conţinute în colecţia
specificată. Reţine în colecţia ţintă doar elementele care sunt şi în colecţia specificată
clear() –şterge toate elementele din colecţie
6
Interfaţa List
O listă este o colecţie în care elementele se găsesc în ordinea adăugării. Listele pot conţine
duplicate. Pe lângă operaţiile moştenite de la interfaţa Collection, interfaţa List include
următoarele operaţii:
Acces poziţional – manipulează obiectele pe baza poziţiei lor numerice în listă
Căutare – caută după un anumit obiect şi îi returnează poziţia în listă
Vizualizarea unui domeniu – permite realizarea unor operaţii asupra elementelor care se află
într-un domeniu al listei
package exemplu;
import java.util.*;
class Persoana{
private String nume;
private int varsta;
System.out.println("----Afisare2---");
for (int i=0;i<pers.size();i++)
System.out.println(pers.get(i).toString() );
System.out.println("----Afisare3---");
for (Persoana p:pers)
System.out.println(p);
System.out.println("----Afisare4---");
Iterator<Persoana> it=pers.iterator();
while (it.hasNext()){
Persoana p=it.next();
System.out.println(p.toString());
}
System.out.println("---Stergere---");
pers.remove(0);//stergerea primului element
System.out.println(pers);
System.out.println("----Ordonare varsta---");
Collections.sort(pers, new ComparaVarsta()); 8
System.out.println(pers);
System.out.println("----Ordonare nume---");
Collections.sort(pers, new ComparaNume());
System.out.println(pers);
System.out.println("----Colectie neordonata---");
Collections.shuffle(pers);
System.out.println(pers);
9
System.out.println("---Stergerea unei bucati din lista---");
pers.subList(0, 2).clear();
System.out.println(pers);
}
}
10
Interfaţa Queue
O coadă este o colecţie pentru păstrarea elementelor înainte de procesare. Pe lângă operaţiile de
bază ale interfeţei Collections cozile dispun de operaţii de inserare, ştergere şi inspectare
adiţionale
Cozile în mod tipic ordonează elementele în stil FIFO (first-in-first-out). Printre excepţii sunt cozile
prioritare care ordonează elementele pe baza valorii lor
Indiferent de stilul de ordonare, elementul care se va şterge atunci când se apelează metoda
remove() este cel din capul cozii.
package exemplu;
import java.util.*;
class MainApp2{
public static void main(String []args){
Queue<Persoana2> pers = new LinkedList<Persoana2>();
//Queue<Persoana2> pers = new PriorityQueue<Persoana2>();
pers.add(new Persoana2("Bogdan",30));
pers.add(new Persoana2("Vlad",20));
pers.add(new Persoana2("George",18));
pers.add(new Persoana2("Dorel",28));
Interfaţa Map
Un Map este un obiect care pune în corespondenţă cheile către anumite valori. Un Map nu poate
să conţină duplicate de chei. Fiecare cheie corespunde unei singure valori
Interfaţa Map are trei implementări HashMap, TreeMap şi LinkedHashMap
Operaţiile de bază cu Map sunt put, get, containsKey, containsValue, size şi isEmpty
Metodele de explorare a colecţiei permit Map-ului să fie vizualizat în aceste 3 moduri:
keySet — setul de chei conţinut în Map
values — colecţia de valori conţinute în Map. Această colecţie nu este de tip Set pentru că
diferite chei pot să corespundă aceleiaşi valori
entrySet — Set-ul de perechi key-value conţinut în Map.
Aceste vederi reprezintă singurul mijloc de a explora un Map
for (KeyType key : m.keySet())
System.out.println(key); 13
package exemplu;
import java.util.*;
import java.util.Map.Entry;
class MainApp3{
public static void main(String []args){
Map<String,Persoana> mp=new HashMap<String,Persoana>();
mp.put("unu",new Persoana("Maria",20) );
mp.put("doi",new Persoana("Ileana",10) );
mp.put("trei",new Persoana("Oana",20) );
mp.put("patru",new Persoana("Denisa",30));
mp.put("unu",new Persoana("Maia",30));
Set s=mp.entrySet();
Iterator it=s.iterator();
while(it.hasNext())
{
Entry m =(Entry)it.next();
String key=(String)m.getKey();
Persoana value=(Persoana)m.getValue();
System.out.println("Key :"+key+" Value :"+value.toString());
if (key.equalsIgnoreCase("trei"))
it.remove();
}
System.out.println(mp);
}
} 14
Interfaţa Set
O interfaţă Set conţine doar metodele moştenite de la interfaţa Collection şi adaugă restricţia că
duplicatele sunt interzise
Java oferă 3 implementări ale interfeţei Set: HashSet, TreeSet şi LinkedHashSet (vezi
subcapitolul 4.1 - Implementări)
Presupunând că avem o colecţie col şi vrem să creem o altă colecţie care să conţină aceleaşi
elemente dar toate duplicatele eliminate, putem scrie următorul cod:
Un exemplu de eliminare a duplicatelor dar care păstrează ordinea elementelor din colecţia în
urma eliminării este:
15
Exemplu care subliniază că într-un Set duplicatele sunt eliminate şi că elementele sunt ordonate
diferit în funcţie de implementarea aleasă
import java.util.*;
s.add("b");
s.add("a");
s.add("b");
TreeSet
s.add("c");
Iterator it=s.iterator();
while(it.hasNext()){
String value=(String)it.next();
System.out.println("Value :"+value); LinkedHashSet
}
}
}
16
În situatia în care se utilizează o implementare a interfeței Set cu table de dispersie (HashTable)
cum ar fi HashSet sau LinkedHashSet pe o celecție de obiecte în care obiectele nu au o ordine
naturală, duplicatele nu sunt automat eliminate. Vezi exemplul urmator:
package exemplu;
import java.util.HashSet;
import java.util.Set;
import java.util.LinkedHashSet;
Acest lucru se întamplă pentru ca nu fost redefinite metodele equals() și hashCode() din clasa
Object și se folosesc implementările implicite ale acestora
Implementarea implicită a metodei equals() din clasa Object compară referinta obiectului curent
cu cea a obiectului transmis ca și parametru 17
Tot din acest motiv codul de mai jos afiseaza mesajul Diferite, pentru că referințele celor două
obiecte sunt diferite, chiar daca ele au același continut.
package exemplu;
Pentru ca metoda equals() să compare câmpurilor obiectului current cu câmpurile obiectului dat
ca și parametru, ea trebuie redefinită în clasa Persoana și specificată o implementare
corespunzătoare
Metoda hashCode() returneaza valoarea hash a obiectului care este folosită ca și cheie în
tabelele de dispersie
Pentru două obiecte care sunt egale potrivit metodei equals() metoda hashCode() trebuie
să returneze acceași valoare hash
În Eclipse pot fi generate ambele metode din optiunea de meniu Source > Generate hashCode()
18
and equals()...
După ce se genereaza metodele hashCode() și equals() în clasa Persoana duplicatele nu vor mai
fi premise
În cazul în care se utilizează pentru interfața Set o implementare prin clasa TreeSet, va trebui
specificat un comparator. Acesta va fi folosit pentru ordonare si pentru eliminarea duplicatelor
(vezi exemplul următor)
Interfaţa SortedSet
Un obiect SotedSet este un set care menţine elementele în ordine crescătoare, sortate pe baze
ordonării naturale sau în acord cu un obiect de tip Comparator furnizat SortedSet-ului în momentul
creării. Pe lângă operatorii oferiţi de interfaţa Set, interfaţa SortedSet mai aduce operatori pentru:
Vizualizarea unui domeniu de valori
Determinarea primului şi ultimului element din SortedSet
Returnează comparatorul utilizat pentru a ordona setul
package exemplu;
import java.util.*;
class MainApp6{
public static void main(String []args){
SortedSet<Persoana2> pers = new TreeSet<Persoana2>();
pers.add(new Persoana2("Bogdan",30));
pers.add(new Persoana2("Vlad",20));
pers.add(new Persoana2("George",18));
pers.add(new Persoana2("Bogdan",30));
pers.add(new Persoana2("Dorel",28)); 19
System.out.println("Dimensiunea initiala a SortedSet-ului="+pers.size());
System.out.println("---Setul initial ordonat dupa nume---");
java.util.Iterator<Persoana2> it=pers.iterator();
while (it.hasNext()){
Persoana2 p=it.next();
System.out.println(p.toString());
}
System.out.println("---Stergere---");
pers.remove(new Persoana2("Bogdan"));
System.out.println("---Cautare---");
for (Persoana2 pe:pers)
if (pe.getNume().equals("George") )
System.out.println("Gasit!");
System.out.println("---Primul---");
System.out.println(pers.first());
}
}
20
4.3 Clasa Vector
Capacitatea unui Vector (capacity) este întotdeauna cel puţin la fel de mare ca şi dimensiunea
vectorului (size). Capacitatea unui vector se poate modifica în funcţie de conţinutul acestuia. (De
exemplu, capacitatea iniţială este 10 şi rămâne atât până se adaugă primele 10 obiecte. Înainte
să se adauge elementul al 11-lea se produce o realocare şi capacitatea vectorului se dublează,
ajungând la 20).
Clasa Vector este sinconizată, ceea ce înseamnă că metodele care modifică structura vectorului
cum ar fi add (), remove () sunt sincronizate şi pot fi folosite cu încredere în aplicaţiile cu fire de
execuţie (sunt thread safe). ArrayList nu este thread safe deci nu este recomandata în fire de
execuţie. Pe de alta parte ArrayList este mai rapidă, deci recomandată în programele fără fire de
execuţie
21
package exemplu;
import java.util.*;
class MainApp7{
public static void main(String []args){
Vector pers=new Vector();
pers.add(new Persoana("Maria",30));
pers.add(new Persoana("Ela",20));
pers.add(new Persoana("Oana",18));
pers.add(new Persoana("Denisa",28));
System.out.println("Capacitate vector="+pers.capacity());
System.out.println("Numar elemente in vector="+pers.size());
System.out.println("---Vectorul initial---");
for (int i=0;i<pers.size();i++)
System.out.println(pers.elementAt(i).toString());
System.out.println("---Stergere---");
pers.removeElementAt(0);
Iterator<Persoana> it=pers.iterator();
while(it.hasNext()){
Persoana p=it.next();
System.out.println(p.toString());
}
System.out.println("---Ordonare---");
Collections.sort(pers, new ComparaNume());
System.out.println(pers);
for (int i=0;i<pers.size();i++)
if (((Persoana)pers.elementAt(i)).getNume().equals("Denisa") )
System.out.println("Gasit!");
} 22
}
4.4 Clasa Properties
Clasa Properties este utilizată la colecții de obiecte formate din perechi chei-valoare la care atât
cheia cât și valoarea sunt striguri.
Proprietățile pot să fie salvate într-un stream sau încărcate dintr-un stream cu ajutorul metodelor
load() și store()
package exemplu;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
System.out.println(judete);
23
Set jud = judete.keySet();
Iterator itr = jud.iterator();
while (itr.hasNext()) {
String s = (String) itr.next();
System.out.println("Judetul " + judete.getProperty(s) + " are codul “ + s + ".");
}
scrie(judete,"judete.properties");
System.out.println("citire din fisier");
Properties jud_in = new Properties();
citeste(jud_in, "judete.properties");
}
24
public static void citeste(Properties p, String fis) {
FileReader reader;
try {
reader = new FileReader(fis);
p.load(reader);
p.list(System.out);
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Introducerea elementelor în colecție se poate face cu ajutorul metodelor setProperty() sau put()
Metoda list() permite afișarea colecției în streamul dat ca și parametru de intrare, care poate fi
asociat monitorului, unui fișier, etc
import java.util.Arrays;
import java.util.Comparator;
class MainApp9{
static void afis(Persoana []pers,int n){
for (int i=0;i<n;i++)
System.out.println(pers[i].toString());
}
System.out.println("---Vectorul initial---");
afis(pers,n); 26
System.out.println("---Stergerea primului element---");
for (int i=0;i<n-1;i++)
pers[i]=pers[i+1];
n--;
afis(pers,n);
Ordonarea s-a făcut cu ajutorul metodei statice sort din clasa Arrays care primește ca și parametri
de intrare vectorul de ordonat, indexul de start (inclusiv), indexul de stop(exclusiv) și comparatorul
care va fi utilizat pentru ordonarea colecției care în cazul de față s-a transmis folosind o clasă
anonimă
27
5. Tratarea excepţiilor
2020-2021, Semestrul 1
5. Tratarea excepţiilor
O excepţie este un eveniment care nu permite continuarea normală a execuţiei
programului
Exemple de excepţii
Încercarea de a accesa un element aflat dincolo de limitele unui vector
(IndexOutOfBoundsException)
Încercarea de a accesa un fişier de intrare care nu există
(FileNotFoundException)
Încercarea de a realiza o împărţire la 0 (ArithmeticException)
Încercarea de a accesa cu metoda charAt() un caracter din afara unui String
(StringIndexOutOfBoundsException)
Încercarea de a converti în întreg cu ajutorul metodei Integer.parseInt () un
String necorespenzător (NumberFormatException)
Utilizarea excepţiilor este un mecanism elegant de a renunţa la execuţia secvenţei de
cod care a provocat excepţia, semnalarea acesteia şi eventual execuţia unei
secvenţe de tratare corespunzătoare
O excepţie este un obiect ce aparţine casei Throwable sau unei clase derivate din
aceasta
Java oferă o ierarhie de clase predefinite pentru tratarea excepţiilor, care se găsesc 2
în pachetul java.lang. La rădăcina ierarhiei se află clasa Throwable
Din clasa Throwable sunt derivate în mod direct următoarele două ierarhii de clase:
Error – pentru erorile nerecuperabile. De obicei aceste erori se referă la maşina
virtuală sau la editarea legăturilor. Aceste erori nu trebuie tratate pentru că în
cazul apariţiei unor astfel de erori nu mai poate continua execuţia. În astfel de
situaţii se afişează un mesaj şi programul se închide
Programatorul poate utiliza clasele predefinite de excepţii sau poate să-şi definească
propriile clase pentru tratarea excepţiilor
apelul unei funcţii prevăzute special pentru cazurile de eroare; această funcţie,
la rândul ei are de ales între cele 3 alternative de mai sus.
4
Tratarea unei excepţii are două componente:
Componenta care semnalează excepţia (throws)
Componenta care tratează excepţia (prinde excepţia)
Instrucţiunea throw
throw obiect;
Dacă în lista de tipuri din clauza throws există cel puţin două tipuri, tip_exi şi tip_exj,
derivate dintr-o superclasă comună tip_exsup, limbajul permite înlocuirea celor două
cu tip_exsup.
Dacă în listă se trece doar Exception, informaţia este foarte vagă pentru cititorul
programului
Dacă programatorul nu prevede clauza throws, şi nici secvenţe try-catch într-o funcţie
dezvoltată care apelează funcţii predefinite dotate cu clauze throws, compilatorul va
sesiza acest lucru ca eroare.
6
Blocurile try -catch
Acestea indică zona de instrucţiuni în care pot să apară excepţiile, tipul excepţiilor şi
modul în care se face tratarea acestora
try {
//secventa obisnuita de operatii, care poate fi intrerupta de aparitia unei exceptii
}
catch(tip_ex1 e){
//tratare exceptie de tipul tip_ex1
}
catch(tip_ex2 e){
//tratare exceptie de tipul tip_ex2
}
//. . .
catch(tip_exn | tip_exm e){ //incepand cu java 7
//tratare exceptie de tipul tip_exn si tip_exm
}
finally {
//secventa optionala
}
Un bloc try este urmat de 0, 1 sau mai multe blocuri catch şi eventual de un bloc
finally
7
Dacă pe parcursul executării intrucţiunilor din blocul try este emisă o excepţie,
secvenţa se întrerupe şi se baleiază blocurile catch pentru a-l găsi pe cel
corespunzător excepţiei emise
Dacă un astfel de bloc există se execută instrucţiunile din el. După aceea execuţia
programului continuă cu linia care urmează după ultimul bloc catch sau, dacă blocul
opţional finally există atunci cu instrucţiunile din el
Prin bloc catch corespunzător unei excepţii se înţelege un bloc catch care are tipul
specificat ca parametru identic cu tipul excepţiei, sau o supraclasă a tipului excepţiei.
Un bloc catch se poate termina normal (adică prin epuizarea instrucţiunilor care îl
compun) sau printr-un throw care să emită o nouă excepţie sau tot pe cea primită. În
acest din urmă caz are loc retransmisia excepţiei. 8
Secvenţa finally
Secvenţa finally reprezintă un mecanism prin care se forţează execuţia unei porţiuni
de cod indiferent dacă o excepţie a apărut sau nu.
try{
flux_in = new BufferedReader (new InputStreamReader(new FileInputStream(nume_fis)));
String linie;
while ((linie = flux_in.readLine()) != null)
if(linie.equals(cuvant)) return true;
return false; //nu s-a gasit cuvantul in fisier
}
finally {
System.out.println("Secventa finally");
if(flux_in != null) flux_in.close();
}
}
Codul din secventa finally se executa chiar dacă codul din try returnează valoare
9
Blocuri try cu resurse
O resursă este un obiect care trebuie închis după ce programul a terminat de lucrat
cu el (vezi obiectul numit flux_in din exemplul precedent)
Într-ul bloc try cu resurse, resursele sunt închise automat la finalul blocului (nu este
necesară închiderea lor explicită, precum în exemplul precedent)
Orice obiect care implementează interfaţa java.lang.AutoCloseable, poate fi folosit ca
o resursă
Codul din exemplul precedent poate fi rescris mai comasat dacă se fosloseşte un
bloc try cu resurse, precum în exemplul următor:
String linie;
while ((linie = flux_in.readLine()) != null)
if(linie.equals(cuvant)) return true;
return false; //nu s-a gasit cuvantul in fisier
}
}
Dacă sunt mai multe resurse acestea se separă prin simbolul punct şi virgulă
10
Exemplu de utilizare a unei excepţii predefinite
import java.io.*;
public class Tablou {
public static void main (String[ ] args) {
int [ ] tab = new int[10];
int i;
try {
for(i=0;;)
tab[i++]=i;
}
catch(IndexOutOfBoundsException e) { //cand i >=tab.length
System.out.println(e);
}
}
}
11
Exemplu de definire şi utilizare a unei excepţii
class OExceptie extends Exception{
OExceptie(String s){
super(s);
}
}
class OClasa {
public static void oFunctie( ) throws OExceptie{
//. . .
if(eroare) throw new OExceptie( “Mesaj!”);
}
}
class ClientClasa{
public static void main(String [] args){
try{
OClasa. oFunctie( ) ;
}
catch(OExceptie e){
System.out.println(e);
}
}
}
12
6. Dezvoltarea aplicaţiilor cu
interfaţă grafică în Java
– biblioteca Swing
2020-2021, Semestrul 1
6.1 Noţiuni introductive
Biblioteca Swing este formată dintr-un set de componente grafice configurabile, a căror aspect
poate fi stabilit la rulare. Programatorii pot utiliza Swing pentru a crea aplicaţii grafice puternice.
Componentele din aplicaţiile grafice pot fi uşor extinse sau modificate pentru a le controla apariţia
şi comportamentul
Swing este o parte a familiei de produse java cunoscuta sub numele Java Foundation Classes (
JFC)
JFC este o suită de biblioteci proiectate pentru a asista programatorii în crearea de aplicaţii cu
Java. Swing este doar una din cele cinci biblioteci care fac parte din JFC:
2
AWT (Abstract Window Toolkit) este setul de bază de instrumente GUI livrat cu toate versiunile
de JDK. În vreme ce biblioteca Swing nu reutilizează nici una din componentele mai vechi ale
AWT, ea construieşte unele componente introduse în AWT 1.1.
2D API - conţine clase pentru implementarea unor stiluri diferite de desenare, forme complexe,
fonturi şi culori
Drag and Drop – este unul din cele mai comune concepte utilizate în interfeţele grafice de azi.
Utilizatorului i se permite sa facă click şi să tragă un obiect grafic mutându-l într-o altă fereastră cu
rezultate predictibile. Biblioteca permite utilizatorilor să implementeze elemente “dropable”
AWT şi Swing
În versiunea JDK 1.1 clasele swing trebuie descărcate separat şi incluse ca o arhivă swingall.jar
în classpath, iar în versiunile JDK mai mari sau egale cu 1.2, Swing este integrat
3
Clase AWT
JDK Clase AWT
Scopul bibliotecii AWT a fost de a oferi un pachet de clase care să-i permită programatorului să
construiască aplicaţii care să arate bine pe toate platformele. Acest scop nu a fost atins. Existau
probleme la accesarea fonturilor şi a unor elemente GUI din sistemul de operare. AWT 1.0 nu era
orientat pe obiecte.
Lucrurile s-au îmbunătăţit odată cu AWT 1.1, care are o abordare mult mai clară şi orientată pe
obiecte, dar în continuare clasele AWT nu furnizau funcţionalitatea necesară aplicaţiilor dezvoltate
pe scară largă
Swing reprezintă o regândire a lui AWT. Swing este construit deasupra nucleului bibliotecii AWT1.1
Swing conţine mult mai multe componente grafice decât predecesorul sau AWT 1.1
4
Swing depinde mult de mecanismul de manipulare al evenimentelor din AWT 1.1
6.2 JFrame
Orice aplicaţie cu interfaţă grafică începe cu crearea ferestrei pe care vor fi amplasate controalele
5
Amplasarea ferestrei pe ecran
myFrame.setLocation(100, 400); y=400
X=100
Activarea / dezactivarea ferestrei
myFrame.setEnabled(true); ECRAN
myFrame.setResizable(false);
6
Fereastră fără buton de maximizare şi minimizare
Soluţia 1
O soluţie:
frm.setContentPane(et);
frm.pack();
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setVisible(true);
8
Lucrul cu evenimente
Afişarea unui mesaj la un click pe JFrame şi afişarea în consolă a coordonatelor mouse-ului când
acesta ajunge deasupra JFrame-ului
//…
class EvenimenteJFrame1{
public static void main(String[]args){
JFrame frame=new JFrame("Face-ti click pe JFrame");
frame.addMouseListener(new MouseClick());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.setVisible(true);
}
}
class MouseClick extends MouseAdapter{
9
Afişarea coordonatelor mouse-ului la trecerea acestuia deasupra ferestrei
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
class EvenimenteJFrame2{
public static void main(String[]args){
JFrame f = new JFrame();
f.getContentPane(). addMouseMotionListener(new CoordonateMiscareMouse());
f.setSize(600, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
mouseMoved(e);
}
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
int mX = (int) e.getPoint().getX();
int mY = (int) e.getPoint().getY();
System.out.println(mX+" "+mY);
}
}
10
6.3 JLabel
Crearea unui control JLabel şi adăugarea acestuia pe JFrame
JFrame frm=new JFrame();
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setSize(300, 300);
frm.setVisible(true);
Modificarea fontului
et.setFont(new Font("Serif", Font.BOLD, 48));
12
Alinierea textului în cadrul etichetei
et.setHorizontalAlignment(JLabel.LEFT);
et.setHorizontalAlignment(JLabel.RIGHT);
Bordarea etichetei
Se utilizează interfaţa Border care descrie un obiect ce e capabil să redea un chenar în jurul unei
componente swing
blackline = BorderFactory.createLineBorder(Color.black);
raisedetched = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
loweredetched = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
raisedbevel = BorderFactory.createRaisedBevelBorder();
loweredbevel = BorderFactory.createLoweredBevelBorder();
empty = BorderFactory.createEmptyBorder();
et.setBorder(raisedetched);
13
Evenimentele JLabel-ului
//… class MouseStaff implements MouseListener{
class Eticheta2{ private int nr_click=0;
public static void main(String []args){ private int nr_vizite=0;
JFrame frm=new JFrame(); private JLabel et;
14
6.4 JTextField
Crearea unei casete de text particulatizate
JFrame myFrame = new JFrame("JTextFied");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setSize(300, 300);
myFrame.getContentPane().setBackground(Color.yellow);
myFrame.setLayout(null);
myText.setBackground(Color.blue );
myText.setToolTipText(“A kind of Magic");
myText.setForeground(Color.white);
myFrame.getContentPane(). add(myText);
myFrame.setVisible(true);
15
Evenimente
Apăsarea tastei Enter
myText.addActionListener(new EnterApasat(myText));
//…
class EnterApasat implements ActionListener
{
private JTextField myText;
public EnterApasat(JTextField myText) {
this.myText=myText;
}
}
}
16
Apăsarea oricărei taste
//…
myText.getDocument().addDocumentListener(new TastaApasata(myText));
//…
class TastaApasata implements DocumentListener
{
private JTextField myText;
public TastaApasata(JTextField myText) {
this.myText=myText;
}
public void changedUpdate(DocumentEvent e) {
System.out.println(myText.getText());
}
public void insertUpdate(DocumentEvent e) {
System.out.println(myText.getText());
}
public void removeUpdate(DocumentEvent e) {
System.out.println(myText.getText());
}
}
17
6.5 JPanel
Crearea unui JPanel particulatizat
myFrame.setLayout(null);
myPanel.setToolTipText("JPANEL");
myPanel.setBounds(10, 20, 100, 200);
myPanel.setBackground(Color.MAGENTA);
blackline = BorderFactory.createLineBorder(Color.black);
raisedetched = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
loweredetched = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
raisedbevel = BorderFactory.createRaisedBevelBorder();
loweredbevel = BorderFactory.createLoweredBevelBorder();
empty = BorderFactory.createEmptyBorder();
myPanel.setBorder(raisedbevel);
myFrame.getContentPane().add(myPanel);
myFrame.setVisible(true);
18
Lucrul cu evenimente
Mouse-ul şi suprafaţa Jpanel-ului
//…
myPanel.addMouseListener(new MouseDeasupa());
//…
class MouseDeasupa implements MouseListener
{
public void mouseClicked(java.awt.event.MouseEvent arg0) {
System.out.println("Mouse click");
}
20
6.6 JButton
Crearea unui control JButton
//…
JFrame myFrame = new JFrame("JButton");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setSize(300, 300);
myFrame.getContentPane().setLayout(null);
myFrame.getContentPane(). add(myText);
myFrame.getContentPane(). add(myButton);
myFrame.setVisible(true);
//…
class ButtonClick implements ActionListener
{
private JTextField myText;
public ButtonClick(JTextField myText){
this.myText=myText;
}
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, myText.getText());
} 21
}
Crearea unui buton cu imagine pe fundal
File f=new File("push.jpg");
Image img = ImageIO.read(f);
myButton2.setIcon(new ImageIcon(resizedImage));
//myButton2.setIcon(new ImageIcon("push.jpg"));
myFrame.getContentPane().add(myButton2);
22
6.7 Amplasarea controalelor în cadrul containerelor
Swing permite gruparea unor controale împreună cu ajutorul unor containere. Un container este o
componentă ce poate conţine alte componente
Modul în care sunt amplasate controalele în cadrul unui container este controlat de o componentă
numită LayoutManager (Gestionar de Componente). Aceasta decide cum sunt amplasate
controalele în funcţie de tipul LayoutManager-ului utilizat şi de ordinea în care au fost adăugate
controalele în container. Dimensiunea, forma şi amplasamentul controalelor diferă de la un layout
manager la altul. Un layout manager adaptează dimensiunea şi poziţia controalelor dacă se
schimbă dimensiunea ferestrei
La adăugarea unui control se poate utiliza metoda add supraîncărcată care primeşte ca şi parametri
controlul de adăugat dar şi o constantă care corespunde poziţiei în care va fi amplasat controlul în
cadrul container-ului
25
FlowLayout
Controalele “curg” pe fereastra, de la stânga la dreapta până când se umple spaţiul liber pe
orizontală. Apoi se trece la rândul următor şi controalele îşi continuă aşezarea în linie, unul lângă altul
Controalele au dimensiunea lor “naturală”. De exemplu dimensiunea unui control JButton sau a unui
control JLabel se adaptează la dimensiunea Stringului sau. Toate controalele vor fi compactate la
dimensiunea lor cea mai mica
}
myFrame.setVisible(true);
26
GridLayout
GridLayout permite construirea unui tabel de componente şi pe măsură ce acestea sunt adăugate
sunt amplasate de la stânga la dreapta şi de sus în jos în celulele tabelului
Fiecare componentă ocupă tot spaţiul disponibil în celula în care se află şi toate celulele au acceaşi
dimensiune
}
myFrame.setVisible(true);
27
BoxLayout
Cu ajutorulul lui Boxlayout se pot amplasa controalele unele lângă altele atât pe orizontală cât şi pe
verticală
myFrame.setVisible(true);
28
CardLayout
Clasa CardLayout administrează de regulă două sau mai multe componente (de regulă instanţe a lui
JPanel) care folosesc acelaşi spaţiu de afişare. Când se utilizează clasa CardLayout utilizatorul poate
alege între componente folosind de exemplu un comboBox
GridBagLayout
GridBagLayout este unul din cei mai flexibili şi complecşi manageri de aspect (LayoutManager) pe
care platforma Java îi oferă. GridBagLayout plasează componentele într-un tabel cu rânduri şi
coloane, permiţând anumitor componente să se întindă pe mai multe rânduri sau coloane. Rândurile
şi coloanele pot avea înălţimi şi lăţimi diferite. GridBagLayout plasează componentele în dreptunghiuri
(celule) şi apoi cu ajutorul metodei setPreferredSize se poate stabili cât de mare va fi celula.
GroupLayout
GroupLayout lucrează cu două layout-uri: unul vertical şi unul orizintal. Layout-ul este definit pentru
fiecare dimensiune separat. Layout-ul corespunzător fiecărei axe este total independent de cel a
celeilalte axe. Când se lucrează asupra unei singure axe se rezolva la un moment dat doar o jumătate
de problemă. Avantajul este că e mai uşor de gestionat o singură dimensiune decât două dimeniuni la
un moment dat.
SpringLayout
SpringLayout este un layout manager foarte flexibil, care poate să emuleze multe din caracteristicile
altor layout manageri. SpringLayout se situează la un nivel de jos şi de accea se recomandă mai
degrabă utilizarea lui împreună cu un GUI builder decât din cod
29
6.8 JComboBox
Adăugarea listei de opţiuni a JComboBox-ului
JFrame myFrame = new JFrame("JComboBox");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setSize(200, 200);
myFrame.setLayout(null);
myFrame.getContentPane().add(myCombo);
myFrame.setVisible(true);
Schimbarea culorilor
myCombo.setBackground(Color.white );
myCombo.setForeground(Color.magenta);
//….
myCombo.addActionListener(new SchimbareSelectie(myCombo));
//….
31
6.9 JCheckBox
//…
public class ExempluCheckBox {
public static void main(String[] args) {
JFrame myFrame = new JFrame("JCheckBox");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setSize(300, 300);
myFrame.setLayout(new GridLayout(7,1));
myFrame.getContentPane(). add(myLabel);
myFrame.getContentPane(). add(chk1);
myFrame.getContentPane(). add(chk2);
myFrame.getContentPane(). add(chk3);
myFrame.getContentPane(). add(chk4);
myFrame.getContentPane(). add(btn);
myFrame.getContentPane(). add(lblAfis);
btn.addActionListener(new AfiseazaSelectate(lblAfis,chk1,chk2,chk3,chk4));
myFrame.setVisible(true);
} 32
}
class AfiseazaSelectate implements ActionListener
{
private JLabel lblAfis;
private JCheckBox chk1;
private JCheckBox chk2;
private JCheckBox chk3;
private JCheckBox chk4;
private String text;
//…
chk1.addActionListener(new SchimbareStare(chk1));
//…
34
6.10 JRadioButton
//Exemplu cu clase imbricate
//…
public Radio_Frame(){
super("JRadioButton");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
setLayout(new GridLayout(7,1));
35
getContentPane(). add(myLabel);
getContentPane(). add(rdo1);
getContentPane(). add(rdo2);
getContentPane(). add(rdo3);
getContentPane(). add(rdo4);
getContentPane(). add(btn);
getContentPane(). add(lblAfis);
btn.addActionListener(new AfiseazaSelectate2());
rdo1.addItemListener(new SchimbareStare2());
}
lblAfis.setText(text);
}
}
36
//clasa interioara (InnerClass)
class SchimbareStare2 implements ItemListener
{
class Main5{
public static void main(String[] args) {
Radio_Frame frm=new Radio_Frame();
frm.setVisible(true);
}
}
37
6.11 Lucru cu evenimente
O componentă poate iniţia un eveniment. Fiecare tip de eveniment este reprezentat de o clasă
distinctă. Atunci când un eveniment se produce, acesta este “auzit” de către unul sau mai mulţi
"ascultători“ (listeners), care acţionează pe acel eveniment. Astfel, sursa a unui eveniment şi locul în
care evenimentul este tratat pot fi separate. Codul care se execută atunci când se produce
evenimentul trebuie editat de către programator.
Fiecare ascultător de evenimente (event listener) este un obiect al unei clase care implementează un
tip particular de interfaţă de ascultare. Deci când vrem să scriem o rutină de tratare a unui eveniment
trebuie să creăm un obiect ascultător pe care trebuie să-l asociem cu componenta care produce
evenimentul. Această asociere se realizează cu ajutorul metodei an addEventListener(), în care
“Event” reprezintă tipul de eveniment care se ascultă.
Când se creează o clasă listener, singura restricţie este ca aceasta să implementeze interfaţa
corespunzătoare
38
39
După cum se vede în tabel fiecare componentă suportă numai anumite tipuri de evenimente
//…
40
Interfaţa listener Metodelele interfeţei
ActionListener actionPerformed(ActionEvent)
AdjustmentListener adjustmentValueChanged( AdjustmentEvent)
ComponentListener componentHidden(ComponentEvent)
componentShown(ComponentEvent)
componentMoved(ComponentEvent)
componentResized(ComponentEvent)
ContainerListener componentAdded(ContainerEvent)
componentRemoved(ContainerEvent)
FocusListener focusGained(FocusEvent)
focusLost(FocusEvent)
KeyListener keyPressed(KeyEvent)
keyReleased(KeyEvent)
keyTyped(KeyEvent)
MouseListener mouseClicked(MouseEvent)
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mousePressed(MouseEvent)
mouseReleased(MouseEvent)
MouseMotionListener mouseDragged(MouseEvent)
mouseMoved(MouseEvent)
WindowListener windowOpened(WindowEvent)
windowClosing(WindowEvent)
windowClosed(WindowEvent)
windowActivated(WindowEvent)
windowDeactivated(WindowEvent)
windowIconified(WindowEvent)
windowDeiconified(WindowEvent)
41
ItemListener itemStateChanged(ItemEvent)
6.12 JList
Crearea unei componente JList cu elemente; elementele sunt transmise cu ajutorul constructorului
clasei JList prin intermediul unui vector de String-uri
import javax.swing.JFrame;
import javax.swing.JList;
public MyFrame(){
super("JList");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
getContentPane().setLayout(null);
class MainApp{
public static void main(String []args){
MyFrame frm=new MyFrame();
frm.setVisible(true);
}
}
42
Adăugarea unor elemente în JList după ce componenta a fost creată; În comparaţie cu varianta
precedentă, în locul vectorului de String-uri se transmite un obiect de tip DefaultListModel, acesta
fiind cel care oferă metoda addElement cu care se pot adăuga item-uri în JList
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
class MainApp{
public static void main(String []args){
MyFrame frm=new MyFrame();
frm.setVisible(true);
}
} 43
Accesarea tuturor elementelor unui JList; Se utilizează metoda getModel() care returnează un
obiect de tip ListModel. Acesta reprezintă modelul de date care deţine lista de elemente afişate de o
componentă JList. Metoda getSize () returnează numărul de elemente din JList, iar accesarea unui
anumit element se poate face cu ajutorul metodei getElementAt()
44
Afişarea doar a elementelor selectate într-o componentă JList; Se crează un vector de întregi
care conţine indicii elementelor selectate, în ordine crescătoare (cu ajutorul metodei
getSelectedIndices).
class JListExemplu extends JFrame
{
private JPanel mainPanel;
private JList lstLuni;
private JScrollPane jspScroll;
private JButton btnAfiseaza;
private String luni[] = {"Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie","August",
"Septembrie", "Octombrie", "Noiembrie", "Decembrie"};
public JListExemplu(){
mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
În cazul în care într-un JList se introduc multe elemente, iar spaţiul necesar pentru a afişa aceste
elemente este mai mare decât dimensiunea JList-ului, atunci se va realiza o tunchiere: nu vor fi
afişate decât o parte din elemente. Această problemă se poate rezolva introducând JList-ul într-un
container JScrollPane, care permite vizualizarea prin derulare, atât pe verticală cât şi pe orizontală,
a întregului obiect JList (vezi exemplul precedent)
Ştergerea elementelor selectate în JList; Pentru ştergerea elementelor selectate este necesară
utilizarea metodei removeElementAt() a obiectului de tip DefaultListModel; deci este necesară
crearea unui astfel de obiect şi asocierea lui cu obiectul JList, fie prin constructor, fie cu ajutorul
metodei setModel(ListModel)
int []n=myList.getSelectedIndices();
for(int i=n.length-1;i>=0;i--){
listModel.removeElementAt(n[i]);
}
46
Evenimente - Afişarea unui mesaj când se face click pe un element a unei componente JList
//…
class myFrame extends JFrame{
private JList myList;
public MyFrame(){
super("JList");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
getContentPane().setLayout(null);
Obiecte necesare:
JMenuBar – bara care conţine meniul. Pe aceasta se adaugă obiecte de tip JMenu. Când un
utilizator selectează un obiect de tip JMenu, meniul de tip popup asociat acestuia este afişat,
permiţând utilizatorului să selecteze unul din elementele JMenuItems de pe el
JMenuItem – Este un buton care stă într-o listă. Când un utilizator selectează butonul acţiunea
asociată cu acesta se execută
JCheckBoxMenuItem - O opţiune de meniu care poate fi selectată sau deselectată. Dacă este
selectată opţiunea de meniu apare însoţită de o bifă. Pentru a determina starea componentei, se
pot utiliza metode isSelected, getState, iar pentru a seta componenta setSelected, setState
48
Exemplu:
//…
class MyFrame2 extends JFrame implements ActionListener{
JTextArea myTextArea;
public MyFrame2(){
super("JMeniu");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
getContentPane().setLayout(new BorderLayout());
myMenu1.setMnemonic(KeyEvent.VK_M);
mnuItem1.setMnemonic(‘O');
mnuItem1.setAccelerator(KeyStroke.getKeyStroke("control O")); 49
ButtonGroup group = new ButtonGroup();
mnuItem6.setSelected(true);
group.add(mnuItem6);
group.add(mnuItem7);
myMenu1.add(mnuItem1);
myMenu1.add(mnuItem2);
myMenu1.addSeparator();
myMenu1.add(mnuItem3);
myMenu1.add(submenu);
myMenu1.addSeparator();
myMenu1.add(mnuItem6);
myMenu1.add(mnuItem7);
myTextArea=new JTextArea();
myTextArea.setEditable(false);
myBar.add(myMenu1);
myBar.add(myMenu2);
getContentPane(). add(myBar,BorderLayout .NORTH);
getContentPane(). add(myTextArea,BorderLayout .CENTER);
mnuItem1.addActionListener(this);
mnuItem2.addActionListener(this);
mnuItem3.addActionListener(this);
mnuItem4.addActionListener(this);
mnuItem5.addActionListener(this);
mnuItem6.addActionListener(this);
mnuItem7.addActionListener(this);
}//constructor
50
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)(e.getSource());
String s = "S-a ales " + source.getText()+" de meniu " + " (" +
getClassName(source) + ")\n";
myTextArea.append(s);
}
class Main2{
public static void main(String []args){
MyFrame2 frm=new MyFrame2();
frm.setVisible(true);
}
}
51
6.14 JTabbedPane
Un obiect JTabbedPane este o componentă care permite utilizatorului să comute între grupuri de
componente, făcând click pe un tab care are un anumit titlu
//…
class MyFrame4 extends JFrame{
public MyFrame4(){
super("JTabbedPane");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
getContentPane().add(myBar,BorderLayout.NORTH);
JButton btnFirst=new JButton();
JButton btnPrevious=new JButton();
JButton btnNext=new JButton();
JButton btnLast=new JButton();
JTextField txtAfis=new JTextField();
btnFirst.setIcon(new ImageIcon("MoveFirst.png"));
btnPrevious.setIcon(new ImageIcon("MovePrevious.png"));
btnNext.setIcon(new ImageIcon("MoveNext.png"));
btnLast.setIcon(new ImageIcon("MoveLast.png"));
myBar.add(btnFirst);
myBar.add(btnPrevious);
myBar.add(txtAfis);
myBar.add(btnNext);
myBar.add(btnLast);
}
}
class Main3{
public static void main(String []args){
MyFrame3 frm=new MyFrame3();
frm.setVisible(true);
}
} 53
6.15 JTable
package exemplu;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
String[][] date = {
{ "1", "Ana", "20" },
{ "2", "Maria", "30" },
};
getContentPane().add(sp);
setVisible(true);
}
public static void main(String[] args)
{
new MyFrame1();
}
} 54
6.16 Crearea fişierului rulabil (JAR)
După ce dezvoltarea programului cu interfaţă grafică a fost finalizată se poate crea
fişierul rulabil
În Eclipse se alege comanda File > Export > Runnable JAR file
55
6.17 Designerul grafic WindowBuilder Pro
WindowBuilder Pro este un designer Swing care simplifică realizarea aplicaţiilor cu
interfaţă grafică în Java, întrucat permite crearea aplicaţiei grafice prin drag and drop
de componente, schimbarea proprietăţilor componentelor cu ajutorul unui Property
Editor şi generarea codului Java. Designerul se instalează ca şi un plug-in în Eclipse
In Eclipse se alege comanda Help > Install New Software… şi se introduce linkul de
pe care se va face instalarea pluginului
56
Componentele interfeţei grafice se trag prin drag and drop pe JFrame
Proprietaţile componetelor pot fi configurate din Property Editor
Codul generat poate fi vizualizat alegând tabul Source (stânga jos)
57
7. Java Database Connectivity
(JDBC) şi MySQL
2020-2021, Semestrul 1
7. Java Database Connectivity (JDBC) şi MySQL
JDBC este o tehnologie care permite conectarea la baze de date şi oferă metode pentru
interogarea şi actualizarea acestora.
Tehnologia JDBC este orientată către baze de date relaţionale (Oracle, MySql, Microsoft Sql
Server,etc), dar permite conectarea şi la fişiere tabelare (Microsoft Excel spreadsheets) sau
fişierele plate (flat files).
Conectarea la un anumit tip de bază de date se face cu ajutorul driver-ului aferent bazei de date
respective
Conexiunile JDBC suportă crearea şi executarea comenzilor SQL. Acestea pot fi comenzi de
actualizare precum CREATE, INSERT, UPDATE şi DELETE, sau pot fi interogări precum
SELECT. De asemenea procedurile stocate pot fi invocate cu ajutorul unei conexiuni JDBC.
JDBC execută comenzile sql cu ajutorul metodelor oferite de una din următoarele interfeţe:
2
Statement – este folosită pentru trimiterea comenzilor SQL simple fără parametri
PreparedStatement – permite folosirea instrucţiunilor SQL precompilate şi a parametrilor de
intrare în interogări.
CallableStatement – permite executarea unor proceduri stocate pe baza de date.
Comenzile SQL precum INSERT, UPDATE şi DELETE returnează un contor care reprezintă
numărul de rânduri care au fost afectate de comandă
Interogările SQL (SELECT) returnează un obiect JDBC, de tip ResultSet, care este organizat pe
rânduri şi coloane. Coloanele pot să fie accesate fie cu ajutorul numelui, fie cu ajutorul indexului
coloanei.Un ResultSet conţine metadate care descriu numele coloanelor si tipul acestora
7.2 MySQL
Caracteristici
Unul din cele mai populare SGBD-uri (Sisteme de Gestiune a Bazelor de Date) din lume
Scris în C şi C++
3
Testat cu Purify (un instrument software care ajută la buna gestiune a memoriei)
Server-ul poate fi tratat ca un program separat şi poate fi utilizat în aplicaţii de tip client-
server în reţea, dar poate fi tratat şi ca o librărie care poate fi încorporată în aplicaţii de sine
stătătoare. Aceste aplicaţii pot fi utilizate în medii în care nu este disponibilă nici o reţea
Descărcare şi instalare
http://dev.mysql.com/downloads/installer/
4
La instalare alegeţi opţiunea Default care instalează următoarele instrumente
MySQL Server
Utilizarea
în sistemul de operare a fost instalat un serviciu care se lansează automat atunci când
pornim calculatorul. Acest serviciu porneşte serverul MySQL.
Serverul pornit ascultă şi acceptă, pe bază de utilizator şi parolă, cererile de conectare
5
Conectarea la server, crearea bazelor de date (schemelor) şi a tabelelor, popularea acestora cu
date, etc se realizează cu ajutorul instrumentului MySQL Workbench
6
O bază de date poate conţine tabele, vederi sau proceduri stocate
Se deschide baza de date în care se doreşte să se creeze tabelul (sau se creează o nouă bază
de date)
Se face click dreapta pe secţiunea Tables şi se alege comanda Create Table
7
Se generează automat comanda SQL de creare a tabelului în conformitate cu cele menţionate în
interfaţa grafică
Popularea cu date a tabelului creat se face prin click dreapta pe numele tabelului şi alegând
comanda Edit Table Data
8
După introducerea datelor se apasă comanda Apply, în urma căreia se generează automat
comenzile SQL - INSERT pentru introducerea datelor în tabel
Popularea cu date a tabelului creat se face prin click dreapta pe numele tabelului şi alegând
comanda Edit Table Data
9
Conectarea din Eclipse la MySQL
Pentru conectare la o bază de date MySQL, este necesară includerea în proiect a driverului de
conectare la baza de date (fişierul jar de mai jos)
C:\Program Files\MySQL\Connector J 5.1.20.0\mysql-connector-java-5.1.20-bin.jar
Se face click dreapta pe proiect şi se alege Properties> Java Build Path>Libraries>Add External
Jar
10
7.3 Accesarea unei baze de date folosind JDBC
Odată ce s-a încărcat un driver putem să-l folosim pentru stabilirea unei conexiuni către baza de
date. O conexiune JDBC este identificată printr-un URL JDBC specific
Sintaxa standard pentru URL-ul unei baze de date este cea de mai jos. Driver este un nume de
driver valid, server este numele sau adresa IP a calculatorului care găzduieşte serverul MySQL,
port este numărul unui port deschis pe care se poate face conectarea
jdbc:driver://server:port/baza_de_date
Pentru baza de date test, în care a fost creat tabelul persoane, din exemplul precedent URL-ul
este următorul
11
Pentru stabilirea unei conexiuni se foloseşte metoda statică getConnection() din clasa
DriverManager
După ce s-a stabilit conexiunea se pot trimite instrucţiuni SQL către baza de date
API-ul JDBC specifică 3 interfeţe (cărora cel care implementează driver-ul trebuie să le dea
implementare) pentru trimiterea de interogări către baza de date, fiecăreie corespunzându-i o
metodă specială în clasa Connection, cu care se pot crea instanţele corespunzătoare
12
Pentru a trimite SGBD-ului comenzile SQL putem utiliza una din metodele execute(),
executeQuery() sau executeUpdate() a obiectului de tip Statement.
Metoda executeQuery() este utilizată în cazul interogărilor (SELECT) care returnează o mulţime
rezultat
Metoda executeUpdate() este utilizată în cazul unor comenzi de tip INSERT, UPDATE, DELETE.
Metoda returnează un întreg care reprezintă numărul de rânduri afectate
Metoda execute() se poate utiliza pentru a rula comenzi de tipul insert, update delete şi în
interogări care furnizează mai mult decât o mulţime rezultat
Pentru a prelua datele din tabelul persoane executăm o interogare SELECT şi preluăm datele într-
un obiect de tip ResultSet
ResultSet rs;
rs = sql.executeQuery("select * from persoane");
13
7.3.3 Procesarea rezultatelor
Pentru parcurgerea simplă a înregistrărilor unui obiect din clasa ResultSet se poate utiliza metoda
next(), iar pentru obţinerea valorilor unui câmp se pot utiliza metode de genul getString(), getInt()
getBoolean(), etc în acord cu tipul câmpului. Parametrul acestei metode este fie denumirea
câmpului fie index-ul acestuia (primul câmp are index-ul 1)
Pentru afişarea pe ecran a datelor din tabelul persoane se poate utiliza codul de mai jos
while (rs.next())
System.out.println("id="+rs.getInt("Id")+", nume= " + rs.getString("nume")+ ",
varsta="+rs.getInt(3));
Pentru a determina dacă cursorul este la sfârşit sau început se pot utiliza metode: isFirst(),
isLast(), isBeforeFirst(), isAfterLast()
14
7.3.4 Actualizarea bazei de date
Baza de date se poate actualiza prin rularea unor interogări SQL de tip INSERT, UPDATE,
DELETE dar şi cu ajutorul unor actualizări programatice.
Actualizările programatice sunt actualizări aplicate direct ResultSet-ului care sunt automat
efectuate şi asupra bazei de date.
Actualizările programatice nu se pot executa decât dacă obiectul de tip Statement a fost creat cu
parametrii de mai jos
sql = (Statement)con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
rs.first();
rs.updateInt("varsta", 30);
rs.updateString(2, "Alina");
rs.updateRow();
import java.sql.*;
ResultSet rs;
Connection con = DriverManager.getConnection (url, "root", "root");
sql = con.createStatement();
rs = sql.executeQuery("select * from persoane");
while (rs.next())
System.out.println("id="+rs.getInt("Id")+", nume= " + rs.getString("nume")
+ ",varsta="+rs.getInt(3));
con.close();
sql.close();
rs.close();
}
}
16
7.3.6 Utilizarea comenzilor SQL cu parametri
Interfaţa PreparedStatement permite rularea comenzilor SQL cu parametri. Comanda SQL se
transmite metodei prepareStatement() din interfaţa Connection. Metoda returnează un obiect de
tip PrepareStatement.
Stabilirea valorilor parametrilor se face cu ajutorul unor metode precum setString(), setInt() care
primesc ca şi parametri indexul parametrului care va fi setat şi valoarea acestuia
Exemplu, preluarea datelor din tabelul persoane:
package exemplu;
import java.sql.*;
pr.setString(1, "Vladut");
pr.setInt(2, 15);
ResultSet rs = pr.executeQuery();
while (rs.next())
System.out.println("id="+rs.getInt("Id")+", nume= " + rs.getString("nume")
+ ", varsta="+rs.getInt(3));
Procedura creată va permite adăugarea unei noi înregistrări în tabela persoane și va avea
conținutul de mai jos
18
Exemplul de mai jos arată cum se poate apela procedura stocată si afișează conținutului tabelei:
package exemplu;
import java.sql.*;
ResultSet rs;
Class.forName ("com.mysql.cj.jdbc.Driver").newInstance ();
Connection con = DriverManager.getConnection (url, "root", "root");
con.close();
sql.close();
rs.close();
}
} 19
7.3.8 Determinarea denumirii coloanelor unei tabele și tipul lor
În aplicații în care se lucrează cu diferite tabele care o structură diferită, determinarea unor
metadate cum ar fi numărul de coloane, denumirea lor, tipul etc se poate realiza cu ajutorul
interfeței ResultSetMetaData:
Liniile de cod de mai jos ilustrează cum pot fi determinate denumirile coloanelor, numărul lor, tipul
și dimensiunea. Liniile de cod pot fi completatate și rulate în unul din exemplele precedente
20
7.4 Corespondenţa dintre tipurile de date MySQL şi tipurile de date Java
Tipurile de date din SQL sunt diferite de tipurile de date din Java
Conectorul MySQL Connector/J este flexibil în ceea ce priveşte modul în care gestionează
conversiile dintre tipurile de date MySQL şi cele Java
În general orice tip MySQL poate fi convertit în java.lang.String, şi orice tip numeric poate fi
convertit la orice tip numeric din Java, deşi pot apărea rotunjiri, depăşiri, posibile pierderi de
precizie
Tabelul de mai jos ilustrează în ce mod sunt mapate tipurile de date din MySQL la cele din Java
de către driver
21
7.5 Comenzi SQL
SELECT
SELECT <listacampuri> FROM <numetabela> WHERE <expresiebooleana>
INSERT
INSERT INTO <numetabela> (camp1,camp2,…,campn) values (valcamp1,valcamp2,…,valcampn)
UPDATE
UPDATE <numetabela> SET camp2= valcamp2,…,campn= valcampn WHERE camp1=valcamp1
2020-2021, Semestrul 1
8.1 Noţiuni generale
XML (eXtensible Markup Language) este un limbaj definit de Consorţiul Web (W3C)
XML este un set de reguli, specificaţii şi convenţii pentru structurarea datelor în fişiere text
Avantajul utilizării unui fişier text faţă de unul binar este că programatorul sau utilizatorul poate citi,
înţelege şi utiliza respectivul fişier fără a fi nevoie de programul care l-a produs
XML utilizează taguri, atribute şi text. Tagurile sunt cuvinte cuprinse între caracterele “<” şi “>” iar
atributele sunt secvenţe de forma nume= “valoare” şi apar în interiorul tag-urilor
XML-ul utilizează tag-uri doar pentru a delimita datele iar interpretarea este dată de aplicaţia care
îl utilizează
2
8.2 Exemplu de document XML
Fişierul optionale.xml conţine informaţii cu privire la materiile opţionale şi va fi utilizat de către
unele din exemplele care urmează:
<?xml version="1.0"?>
<optionale>
<optional id=“c1">
<nume>Postmodernismul si Abordarea Metafilosofica a Culturii</nume>
<profesor>Tudor Radac</profesor>
<an>3</an>
<url>http://www.pamc.ro</url>
<studenti min="20" max="160"/>
<recomandari>
<curs>PM</curs>
<curs>AMC</curs>
</recomandari>
</optional>
<optional id=“c2">
<nume>Conceptul de Fenomenologie si Ego Transcedental</nume>
<profesor>Ana Tudose</profesor>
<an>4</an>
<url>http://www.cfet.ro</url>
<studenti min="30" max="140"/>
<recomandari>
<curs>CF</curs>
<curs>ET</curs>
</recomandari>
</optional>
<optional id=“c3">
<nume>Mecanismele Cunoasterii Stiintifice</nume>
<profesor>Matei Ionescu</profesor>
<an>2</an>
<url>http://www.mcs.ro</url>
<studenti min="25" max="100"/>
<recomandari>
<curs>RST</curs>
<curs>IMN</curs>
</recomandari>
</optional>
</optionale>
Fişierul poate fi creat cu ajutorul unor editoare text precum Notepad ,TextPad , etc
În Eclipse se poate crea un fişier XML prin click dreapta pe proiect şi alegând comanda New >
File
fişierul creat poate fi editat cu ajutorul editorului de text sau cu ajutorul editorului XML
XML Editor:
Text Editor:
8.3 SAX
8.3.1 Aspecte teoretice
Simple API for XML parsing (SAX) – permite procesarea documentelor XML prin intermediul
unor evenimente.
Se parcurge fişierul XML iar la apariţia elementelor XML se vor lansa evenimente care pot fi
tratate
5
8.3.2 Obţinerea informaţiilor din documente XML
Fiecărui eveniment îi corespunde o metodă definită în interfaţa ContentHandler. Metodele sunt
apelate automat de către parser, iar cele mai importante sunt următoarele:
Unele documente XML pot utiliza spaţii de nume. Acestea sunt utile pentru a furniza nume unice
elementelor şi atributelor dintr-un fişier XML. Spaţiile de nume sunt introduse în documentele XML
cu ajutorul atributului xmlns.
uri (uniform resource identifier ) este un string utilizat pentru a identifica un nume sau o resursă
Dacă este activată facilitatea de procesare a spaţiilor de nume şi dacă spaţiul de nume are ataşat
un uri atunci adresa spaţiului de nume va fi transmisă în parametrul uri. În acest caz localName
va conţine numele tag-ului fără prefix, iar qName cu tot cu prefix
6
Dacă nu este activă facilitatea de procesare a spaţiilor de nume atunci localName va conţine şirul
vid iar qName numele tag-ului. Atributele vor fi memorate în parametrul attributes. Dacă tag-ul nu
posedă atribute atunci parametrul va fi un obiect vid
public void endElement(String uri, String localName, String qName) throws SAXException
Această metodă este apelată atunci când este întâlnit un tag de sfârşit. Dacă tagul este de sine
stătător (de exemplu <studenti />) atunci se apelează automat după startElement
Se execută la apariţia unui text aflat între taguri. Respectivul text se află în parametrul ch,
începând cu poziţia start şi va conţine length caractere
Toate metodele din interfaţa ContentHandler transmit mai departe excepţia SAXException
Pentru a obţine informaţiile din documentele XML putem fie să implementăm interfaţa
ContentHandler fie să extindem clasa DefaultHandler
Clasa SAXParserFactory este utilizată pentru crearea şi configurarea de parsere bazate pe SAX.
Obţinerea unei noi instanţe se realizează cu ajutorul metodei statice newInstance() a clasei
SAXParserFactory
7
Clasa SAXParser este utilizată pentru procesarea efectivă a documentelor XML. Instanţele
acestei clase se obţin prin apelul metodei newSAXParser() din clasa SAXParserFactory.
Fişierul XML este transmis ca parametru metodei parse() împreună cu un obiect de tip
DefaultHandler()
class Main{
public static void main(String []args){
SAXParserFactory factory=SAXParserFactory.newInstance();
DefaultHandler handler=new OptionaleXML();
SAXParser parser;
try{
parser=factory.newSAXParser();
parser.parse("optionale.xml", handler);
}
catch(Exception ex){
System.out.println(ex.toString());
}
}
}
9
8.3.3 Obţinerea valorilor atributelor unui tag
Valorile atributelor se obţin cu ajutorul metodei getValue(numeAtribut), a parametrului attributes
Codul de mai jos poate fi completat în metoda startElement () din exemplul precedent
else if (qName.equals("studenti"))
{
String min=attributes.getValue("min");
String max=attributes.getValue("max");
if (min!=null){
System.out.println("\tMin="+min);
}
if (max!=null){
System.out.println("\tMax="+max);
}
}
else if (qName.equals("studenti"))
{
for (int i=0;i<attributes.getLength();i++)
System.out.println("\t"+attributes.getQName(i)+"="+attributes.getValue(i));
}
10
8.3.4 Procesarea documentelor XML care conţin DTD
Pentru ca un document XML să respecte o anumită structură, se defineşte un DTD (Document
Type Definition)
DTD specifică care este structura documentului XML: numele tag-ului rădăcină, subtagurile
acestuia, cu eventuale condiţii de repetare sau de obligativitatea apariţiei, lista atributelor pentru
fiecare tag, etc
Fişierul optionale2.xml are în plus faţă de fişierul optionale.xml, următoarele linii
<!DOCTYPE optionale SYSTEM "cursuri.dtd"> <!-- linia 2 -->
//…
<optional id="c4" /> <!-- penultima linie -->
<!ATTLIST studenti
min CDATA #IMPLIED
max CDATA #IMPLIED
> 11
Într-un document DTD, elementele sunt declarate cu următoarea sintaxă:
<!ELEMENT numele_elementului categoria>
//sau
Elementele care nu pot conţine decât text (nu mai pot conţine alte elemente) se declară cu
#PCDATA între paranteze rotunde (Parsed Character Data)
Elementele care pot sa aibă unul sau mai mulţi copii sunt declarate punând numele copiilor între
paranteze rotunde
<!ELEMENT numele_elementului(copil1)>
//sau
Când copii sunt declaraţi într-o secvenţă separată prin virgule, copii trebuie să apară în aceeaşi
ordine în document
12
Declararea a cel puţin unei apariţii a unui copil se face în felul următor:
13
SAXParserFactory factory=SAXParserFactory.newInstance();
DefaultHandler handler=new OptionaleXML();
SAXParser parser;
XMLReader xmlReader;
factory.setValidating(true);
try{
parser=factory.newSAXParser();
xmlReader=parser.getXMLReader();
xmlReader.setContentHandler(handler);
xmlReader.parse(“optionale2.xml");
}
catch(Exception ex){
System.out.println(ex.toString());
}
Pentru pornirea parsării se apelează metoda parse() care primeşte ca şi parametru fişierul xml de
parsat
În plus este afişat un mesaj de avertizare care anunţă faptul că nu a fost specificat un obiect care
să trateze erorile şi că este utilizat unul implicit care nu reţine decât primele 10 erori.
Pentru a elimina warningul trebuie să definim un obiect a cărui clasă să implementeze interfaţa
ErrorHandler. Putem să specificăm obiectul handler care aparţine unei clase ce extinde
DefaultHandler, pentru că aceasta implementează şi ErrorHandler. În funcţia main(), înainte de
parsare se adaugă următoarea linie:
xmlReader.setErrorHandler(handler);
Această modificare face ca să nu mai apară nici un mesaj de eroare pentru că, clasa
DefaultHandler implementează funcţiile specificate în interfaţa ErrorHandler ca şi funcţii vide
Pentru a semnala erorile care apar va trebui sa redefinim în clasa OptionaleXML warning(),
error() şi fatal()
15
Pentru aceasta se poziţionează cursorul în interiorul clasei OptionaleXML şi se alege opţiunea de
meniu Source> Override/Implement Methods şi se aleg cele 3 metode
16
8.4 DOM
DOM (Document Object Model) este un standard stabilit de consorţiul Web şi conţine interfeţe
pentru manipularea arborelui de obiecte asociat unui document XML
Cu ajutorul DOM se pot adăuga noi noduri în arbore respectiv modifica sau şterge cele existente
Fişierul studenti.xml:
<?xml version="1.0" ?>
<!DOCTYPE studenti[
<!ELEMENT studenti (student)+>
<!ELEMENT student (nume,an,grupa)>
<!ELEMENT nume (#PCDATA)>
<!ELEMENT an (#PCDATA)>
<!ELEMENT grupa (#PCDATA)>
]>
<studenti>
<student>
<nume>Maria Tudoroiu</nume>
<an>2</an>
<grupa>3</grupa>
</student>
<student>
<nume>Marian Mocofan</nume>
<an>3</an>
<grupa>1</grupa>
</student>
<student>
<nume>Ionel Panduru</nume>
<an>4</an>
<grupa>2</grupa>
</student>
17
</studenti>
Pachetele necesare procesării documentelor XML prin intermediul DOM sunt:
javax.xml.parsers – conţine clasele necesare procesării documentelor XML (atât cu SAX cât şi
cu DOM)
org.w3c – oferă clasele pentru reprezentarea arborescentă a documentelor XML
Pentru crearea arborelui corespunzător documentului 1.xml vom utiliza următorul cod:
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document document=builder.parse(“optionale.xml");
În memorie s-a construit arborele corespunzător documentului XML, iar referirea la acesta se va
realiza prin intermediul interfeţei Document 18
8.4.2 Manipularea arborelui DOM
Fiecărui nod din arbore îi corespunde un obiect care implementează interfaţa Node. Aceasta
posedă subinterfeţe corespunzătoare fiecărui tip de nod. Spre exemplu unui tag îi corespunde
interfaţa Element.
Pentru identificarea tipului unui nod, interfaţa Node oferă metoda getNodeType() care poate
returna mai multe valori de tip short, o parte din acestea sunt:
ATTRIBUTE_NODE –nod de tip atribut
CDATA_SECTION_NODE – nod corespunzător unei secţiuni CDATA
COMMMENT_NODE - nod corespunzător unui comentariu
DOCUMENT_NODE –nod corespunzător unui document XML
ELEMENT_NODE – nod corespunzător unui tag
TEXT_NODE – nod de tip text
Node getNextSibling () –întoarce nodul următor nodului curent din lista nodurilor
descendente ale nodului părinte
20
Exemplul de mai jos procesează documentul optionale.xml şi afişează lista cursurilor opţionale:
try{
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document document=builder.parse(“optionale.xml");
if (n.hasAttributes()){
System.out.println("Atributele tagului "+n.getNodeName()+" sunt: ");
map=n.getAttributes();
for (int i=0;i<map.getLength();i++)
System.out.println("\t"+map.item(i).getNodeName()+"=\""+
map.item(i).getNodeValue()+"\"");
}
if (n.hasChildNodes()){
aux=n.getChildNodes();
for (int i=0;i<aux.getLength();i++)
rec(aux.item(i));
}
} 22
Dacă un nod posedă atribute atunci acesta este de tip Element (cu siguranţă este un tag) iar
metoda getNodeName() va returna numele tag-ului
În cazul în care un nod posedă copii se va apela metoda recursivă pentru aceste noduri
Interfaţa NamedNodeMap este utilizată pentru a putea accesa o colecţie de noduri cu ajutorul
numelui sau a indecşilor. Este permisă eliminarea sau înlocuirea anumitor noduri
Interfaţa NodeList reprezintă o colecţie ordonată de noduri. Se pot doar obţine nodurile din
colecţie dar colecţia nu poate fi modificată
Interfaţa Document are o importanţă deosebită pentru că prin intermediul acesteia se pot crea
noi noduri pentru arborele DOM asociat unui document XML. Aceasta mai oferă posibilitatea
obţinerii unei colecţii de noduri care au acelaşi nume. Cele mai importante metode ale interfeţei
sunt:
Element getDocumentElement() - returnează nodul rădăcină al arborelui
Element getElementById() – returnează elementul care are indicatorul precizat sau null
dacă acesta nu există
23
NodeList getElementsByTag() – Furnizează o colecţie de noduri de tip element care au
numele specificat
Nodurile create de metodele interfeţei Document nu sunt automat adăugate în arborele DOM
corespunzător documentului XML. Acestea ar trebui inserate în lista nodurilor descendente ale
unui nod. Modificarea arborelui nu implică actualizarea fişierului sursă XML
Se consideră fişierul studenti.xml. Exemplul următor adaugă un nou nod în arborele DOM
(adaugă un nou student) şi apoi parcurge nodurile “nume” din arbore
24
Pentru a putea crea marcatorul nume cu textul Ana Lana este necesar să să creăm două noduri:
unul corespunzător tagului nume, iar celălalt corespunzător nodului text. Nodul tagului va avea ca
descendent nodul cu text. Analog se creează nodurile corespunzătoare marcatorilor an şi grupa.
Aceştia 3 marcatori vor fi descendenţi pentru nodul student
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document document=builder.parse(“studenti.xml");
Node stud=document.createElement("student");
Node n=document.createElement("nume");
Node t=document.createTextNode("Ana Lana");
n.appendChild(t);
stud.appendChild(n);
n=document.createElement("an");
t=document.createTextNode("3");
n.appendChild(t);
stud.appendChild(n);
n=document.createElement("grupa");
t=document.createTextNode("2");
n.appendChild(t);
stud.appendChild(n);
document.getDocumentElement().appendChild(stud);
NodeList lista=document.getElementsByTagName("nume");
for (int i=0;i<lista.getLength();i++)
System.out.println(lista.item(i).getFirstChild().getNodeValue()); 25
9. Caracteristicile Java 8
2020-2021, Semestrul 1
9.1 Noțiuni introductive
Prima versiune Java 8 a fost lansată în martie 2014
Expresii Lambda – sunt funcții anonime care de regulă sunt transmise ca și parametru de
intrare al altor funcții
Referințe la metode – permit referirea metodelor prin nume, fără a le invoca. Permit
utilizarea funcțiilor ca și parametru. Permit definirea expresiilor Lambda prin referirea directă
a metodelor prin nume
Stream API – o clasă iterator specială care permite procesarea colecțiilor de obiecte într-o
manieră functională
Clasa Triunghi implementează interfața Figura, specifică o implementare pentru metoda abstractă și
redefinește una din cele două metode implicite
Din metoda deseneaza_figura() a clasei Triunghi se apelează atât metoda implicită din interfață cât
si cea redefinită în clasă
4
9.3 Expresii Lambda
O expresie Lambda este caracterizată prin următoarea sintaxă:
parametri -> corpul expresiei
Expresiile Lambda sunt utilizate în principal pentru a defini implementarea inline (printr-o linie de
cod) a unei interfețe cu o singură metodă
Expresia Lambda elimină necesitatea unei clase anonime și oferă o capacitate de programare
funcțională foarte simplă, dar puternică pentru Java.
Nu este necesar sa se declare tipul unui parametru. Compilatorul poate sa deducă tipul lui
Parantezele rotunde sunt necesare doar pentru cel putin doi parametri. Pentru un parametru
sunt opționale
În corpul expresiilor sunt necesare paranteze accolade doar dacă acestea conțin două sau mai
multe instrucțiuni
Cuvantul return este opțional – compilatorul automat returnează valoarea dacă corpul are o
singură expresie care să returneze valoarea
5
Fisierul Persoana.java are conținutul de mai jos
package exemplu2;
class Persoana{
private String nume;
private int varsta;
public Persoana(String nume, int varsta) {
this.nume = nume;
this.varsta = varsta;
}
public String getNume() {
return nume;
}
public int getVarsta() {
return varsta;
}
@Override
public String toString() {
return nume + " " + varsta;
}
}
6
Fisierul MainApp.java are conținutul de mai jos
package exemplu2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class MainApp {
public static void main(String[]args) {
List<Persoana> pers=new ArrayList<Persoana>();
pers.add(new Persoana("Maria",23));
pers.add(new Persoana("Ana",24));
pers.add(new Persoana("Oana",22));
Collections.shuffle(pers);
System.out.println("Colectia aleatoare: "+pers);
7
Collections.shuffle(pers);
Collections.sort(pers,(Persoana a,Persoana b)->a.getNume().compareToIgnoreCase(b.getNume()));
System.out.println("Colectia ordonata dupa nume in Java 8 style 1: "+pers);
Collections.shuffle(pers);
Collections.sort(pers,(a,b)->{
return a.getNume().compareToIgnoreCase(b.getNume());
});
System.out.println("Colectia ordonata dupa nume in Java 8 style 2: "+pers);
Collections.shuffle(pers);
Collections.sort(pers,(Persoana a,Persoana b)->{
if (a.getVarsta()<b.getVarsta()) return -1;
else
if(a.getVarsta()>b.getVarsta()) return 1;
else return 0;
});
8
În Java 7 ordonarea unei colecții se face cu ajutorul unei clase care implementează interfața de
comparare
Parametrii care apar în expresia Lambda sunt parametrii metodei de comparare a interfeței. Tipul
acestor parametrii poate să fie specificat (Persoana a, Persoana b) sau nu (a,b) (vezi slide-ul
precedent).
Corpul expresiei Lambda conține codul din metoda de comparare, care este automat returnat
În cazul în care corpul expresiei Lambda conține mai multe linii de cod, este necesar să se utilizeze
paranteze accolade și să se returneze prin utilizarea lui return valorile dorite (vezi exemplul de
ordonare după vârsta din slideul precedent)
package exemplu3;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
Exemplul de mai sus ilustrează cum se poate adăuga un listener pe un buton in stilul Java 8, cu
ajutorul expresiilor Lambda
10
9.4 Referințe de metode
O referință de metodă este o construcție Java 8 care poate fi folosită pentru a referi o metodă fără a
o apela
O referință de metodă poate fi identificată cu ajutorul notatiei :: care separă o clasă sau un obiect de
numele unei metode
String::new
11
Fisierul MethodReference.java are conținutul de mai jos:
package exemplu4;
import java.util.List;
import java.util.ArrayList;
orase.forEach(System.out::println);
}
}
forEach este un nou operator introdus în Java 8 pentru a traversa colecțiile. Acesta traversează
colecția și realizează pentru fiecare element actiunea transmisă ca și parametru de intrare
O referință către metoda println a fost transmisă ca și parametru de intrare a metodei forEach care
traversează colecția și realizează acțiunea dată de parametrul de intrare pentru fecare element al
colecției, lucru care va determina afișarea colecției în consolă
12
9.5 Stream API
Un stream este un iterator a cărui rol este de a accepta un set de acțiuni să fie aplicate fiecăruia din
elementele pe care le conține
Streamurile au fost proiectate cu scopul de a face procesarea colecțiilor mai simplă și concisă.
Spre deosebire de colecții cu ajutorul streamurilor se pot face o serie de prelucrări încă din etapa de
declarare
Operațiile streamurilor pot să fie ori intermediare ori terminale. Operațiile terminale returnează un
rezultat de un anumit tip, iar cele intermediare returneaza însăși streamul, în acest fel se pot pune
într-o singură instrucțiune mai multe apeluri de metodă
Colecțiile în Java 8 au fost extinse deci se poate crea un Stream foarte ușor apelând una din
metodele Collection.stream() or Collection.paralelStream()
Streamul paralel împarte taskul furnizat în mai multe taskuri pe care le rulează în diferite fire de
execuție.
13
Fisierul MainApp.java:
package exemplu5;
import java.util.ArrayList;
import java.util.List;
Cel de-al doilea stream transforma toate elementele colecției în majuscule, apoi ordonează colecția
și o afișează
Liniile de cod de mai jos generează aleatoriu 10 întregi, îi ordonează și îi afișează în consolă
În exemplul de mai jos se creeaza un stream paralel pentru o colecție de stringuri, se pune un filtru
care determină doar ementele necompletate și apoi se determină numărul acestora cu ajutorul
metodei count
15
9.6 Interfețe funcționale
Interfețele funcționale au o singură metodă abstractă. Metodele implicite nu sunt abstracte deci pot
fi prezente în număr oricât de mare în interfețele funcționale. Fiecare expresie Lambda va
corespunde acestei metode abstracte. Deaspupra interfețelor functionale se poate adăuga
adnotația @FunctionalInterface. Datorită acestei adnotații compilatorul va semnala eroare dacă se
încearcă adăugarea unei alte metode abstracte
Se consideră clasa Persoana cu variabilele membre nume și varsta, din pachetul exemplu2. Datele
mai multor persoane vor fi adăugate unei colecții de obiecte de tip List și apoi cu ajutorul unei
interfețe funcționale și a notației Lambda vor fi afișate filtrat, doar datele persoanelor care au peste
22 de ani
package exemplu6;
import java.util.ArrayList;
import java.util.List;
import exemplu2.Persoana;
@FunctionalInterface
interface Filtru{
boolean test(Persoana p);
}
16
class MainApp {
static void afisare_filtrata(List<Persoana> pers, Filtru f) {
for(Persoana p:pers)
if(f.test(p))
System.out.println(p);
}
public static void main(String[]args) {
List<Persoana> pers=new ArrayList<Persoana>();
pers.add(new Persoana("Maria",23));
pers.add(new Persoana("Ana",24));
pers.add(new Persoana("Oana",22));
afisare_filtrata(pers, (Persoana p)->p.getVarsta()>22);
}
}
În exemplul precedent, pentru a putea utiliza notația Lambda și a afișa datele unei persoane doar
dacă aceasta îndeplinește o condiție, a fost creată o interfață funcțională care conține o metodă de
test ce returneză o valoare booleană care indică dacă un anumit element respectă o condiție sau nu
Prin notația Lambda se specifică o implementare pentru metoda interfeței funcționale, care
returnează true dacă vârsta unei persoane este mai mare de 22 de ani, respectiv false dacă nu este
mai mare
17
Expresia Lambda este transmisă ca și parametru de intrare de tip Filtru al metodei statice
afisare_filtrata() şi utilizată în această metodă pentru a afișa doar datele persoanelor care
îndeplinesc condiția impusă:
Interfața funcțională Filtru a fost creată doar pentru a putea transmite notația Lambda ca și
parametru de intrare a metodei de afișare
În pachetul java.util.function.* din Java 8 există mai multe interfețe funcționale oferite de limbaj. Una
din aceste interfețe funcționale este interfața Predicate
Interfața Predicat <T> este o interfață funcțională cu o metodă test(Object) care returnează o
valoare booleană. Metoda testează dacă o anumită condiție este îndeplinită sau nu
În exemplul precedent în locul creări interfeței funcționale Filtru s-ar fi putut utiliza interfața Predicate
din limbaj care conține o metodă de testare similară. Vezi exemplul următor:
18
package exemplu7;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import exemplu2.Persoana;
class MainApp {
static void afisare_filtrata(List<Persoana> pers, Predicate<Persoana> f) {
for(Persoana p:pers)
if(f.test(p))
System.out.println(p);
}
BiFunction<T,U,R> are o funcție care are doi parametri de intrare și produce un rezultat
BinaryOperator<T> are o funcție care are doi parametri de intrare de același tip si produce un
rezultat de același tip ca și parametrii de intrare
Consumer<T> reprezintă o operație care accepta un singur parametru de intrare si nu produce nici
un rezultat
etc
20
9.7 Date Time API
package exemplu8;
import java.time.*;
import java.time.temporal.*;
import java.util.Calendar;
LocalDateTime d2 =dateTimeNow.withMonth(2).withDayOfMonth(2);
System.out.println("d2="+d2);
LocalTime d5 = LocalTime.parse("20:15:30");
System.out.println("date5: " + d5);
LocalDate d6 = LocalDate.parse("2017-11-20");
System.out.println("d6: " + d6);
Calendar c=Calendar.getInstance();
Instant now = c.toInstant();
22
23
9.8 Clasa Optional
Pentru a evita excepția NullPointerException, de obicei în programe trebuie făcute multe verificări
ale null-ului
Clasa Optional oferă facilitați pentru scrierea unui cod fără multe teste ale null-ului.
Prin clasa Optional se pot specifica valori alternative care să fie returnate sau cod alternativ care să
fie rulat când se întâlnește null
Metoda de mai jos afișează numărul de cuvinte al unui propoziții dată ca şi parametru de intrare al
funcţiei, printr-un String ale cărui cuvinte sunt separate prin spaţii
Dacă la afelul funcţiei i se transmite un String care are valoarea null, aceasta determină producerea
exceptiei NullPointerException
Optional este un container care poate să conțină o valoare sau nu. Dacă valoarea este prezentă
funcția get() o va returna
API-ul oferă metode adiționale care depind de prezența sau absenta valorii cum ar fi orElse()
metodă care returnează o valoare implicită în caz că valoarea inspectată nu e prezentă sau metoda
ifPresent() care execută un bloc de cod dacă valoarea este prezentă 25
Un exemplu de utilizare a acestora este următorul:
package exemplu_optional;
import java.util.Optional;
opt.ifPresent(value ->System.out.println(value.toUpperCase()) );
Parametrul de intrare al funcției ifPresent() a fost transmis printr-o expresie lambda care afișează cu
majuscule valoarea din containerul Option
Persoana p=findPersoanaById(2);
System.out.println(p.getNume());
În exemplul de mai sus, dacă persoana căutată nu se găseşte, rândul următor produce
NullPointerException
optional.ifPresent(p -> {
System.out.println("Numele persoanei este " + p.getNume());
});
28
10. Fire de execuţie
2020-2021, Semestrul 1
10.1 Crearea firelor de execuţie
Firele de execuţie reprezintă porţiuni de cod ale aceluiaşi program care se pot executa în paralel
una faţă de alta
Maşina Virtuală Java permite dezvoltarea de aplicaţii care au mai multe fire de execuţie ce
rulează concurent
Pentru orice fir de execuţie există o metodă run() care reprezintă codul executat de firul de
execuţie respectiv.
Mecanismul de fir de execuţie este descris de clasa Thread din biblioteca java.lang
Metoda start() pregăteşte un fir de execuţie de rulare. Începerea rulării efective depinde de mai
mulţi parametri
f.start();
În cazul 2, din metoda run nu se pot apela metode specifice de tip Thread (sleep(),
setPriority(),getPriority()). Pentru a rezolva această problemă trebuie procedat ca mai jos:
public void run(){
Thread t=Thread.currentThread();
…
t.sleep(100);
}
Metoda 2 permite clasei firului de execuție să extindă o altă clasă decât Thread
Oprirea brutală a firelor de execuţie poate să aibă consecinţe neaşteptate mai ales dacă firele de
execuţie aveau controlul unor resurse
public class Fir extends Thread{
public Fir(String nume){
super(nume);
}
public void run(){
for (int i=0;i<10;i++){
System.out.println(i+" "+getName());
try {
sleep(100);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Gata! "+getName());
}
}
class Main{
public static void main(String []args){
Fir f1=new Fir("La");
Fir f2=new Fir("Sol");
f1.start();
f2.start();
System.out.println("Numarul de fire de executie " +Thread.activeCount());
} 4
}
Programul precedent are 3 fire de execuție, firul main-ului și cele două fire create
La rulări diferite se obțin ieșiri diferite în funcție de cum se alocă procesorul pentru cele 3 fire
Dacă firul de execuţie este derivat din clasa Thread şi pornirea lui se face imediat după instanţiere
atunci poate fi modificat constructorul clasei în felul următor:
class FirExecutie1 extends Thread{
public FirExecutie1 (String str){
super(str);
start();
}
}
Dacă există mai multe fire de execuţie care se execută pe un singur procesor se pune problema
cum se alege firul de execuţie care se va executa la un moment dat
Alegerea firului de execuţie care se execută la un moment dat se face pe baza priorităţii sale.
Prioritatea unui fir de execuţie este cuprinsă între valorile:
Thread.MIN_PRIORITY //valoarea 1
Thread.MAX_PRIORITY //valoarea 10
La creare un fir de execuţie are o prioritate egală cu cel care l-a creat
5
Dacă există mai multe fire de execuţie cu aceeaşi prioritate atunci acestea se execută într-o
ordine care depinde de modul în care sistemul de operare tratează firele (cu sau fără divizarea
timpului)
În orice variantă execuţia este preemtivă adică sistemul poate să întrerupă firul de execuţie curent
pentru a executa un fir cu prioritate mai mare
În sistemele care asigură divizarea timpului un fir de execuţie rulează pentru un interval de timp
apoi se trece la alt fir de execuţie şi aşa mai departe. Firul de execuţie pierde procesorul în
următoarele situaţii:
Se termină cuanta de timp alocată
Firul execută un apel de metodă de blocare (sleep, wait)
Firul execută un apel explicit de cedare (yield)
Dacă un fir de execuţie vrea să permită execuţia altor fire va executa metoda yield
6
Stările firelor de execuţie:
Creat - un obiect de tip fir de execuţie este creat cu ajutorul operatorului new()
Gata de execuţie – după execuţia metodei start() un fir de execuţie poate să fie executat.
Execuţia lui depinde de disponibilitatea procesorului şi de prioritatea firului
Suspendat – dacă un fir de execuţie a apelat metoda sleep() sau wait() atunci acesta trece în
starea suspendat. Revenirea în starea gata de execuţie se poate face în următoarele moduri:
Dacă firul a fost blocat prin sleep (durata) firul revine în starea gata de execuţie după
trecerea timpului specificat
Dacă firul a fost blocat prin wait() atunci în momentul în care se execută una din funcţiile
notify () sau notifyall()
Dacă firul a fost blocat prin wait(durata) atunci în momentul în care se execută una din
funcţiile notify() sau notifyall() sau la epuizarea intervalului de timp menţionat
Terminat – dacă metoda run() îşi încheie execuţia sau dacă se execută metoda stop() . Execuţia
metodei stop generează o excepţie de tip ThreadDeath() care extinde clasa Error().
Dacă în momentul în care se opreşte firul datorita metodei stop() sunt necesare unele prelucrări
atunci obiectul trebuie să fie prins
7
După terminarea prelucrărilor obiectul trebuie să fie aruncat din nou (throw) altfel prelucrările nu
se mai termină niciodată
Definiţia clasei Thread permite testarea stării unui fir de execuţie utilizând metoda isAlive().
Valoarea returnată este:
True dacă firul este în starea gata de execuţie sau suspendat.
False dacă firul este în starea creat sau terminat
package FireExecutie;
f.start();
System.out.println("Fir gata de executie");
f.stop();
f.xx();
f=null;
9
10.2 Sincronizarea firelor de execuţie
În cazul unor fire de execuţie care se execută simultan problema sincronizării apare dacă relaţia
dintre ele este de:
Concurenţa se referă la faptul că la un moment dat cel mult un fir trebuie să aibă acces la resursa
comună. Rolul sincronizării în acest caz este de a asigura accesul exclusiv la resursele comune.
O secvenţă de cod pentru care trebuie să se asigure accesul exclusiv se numeşte regiune critică.
Schimbul de informaţii în cazul cooperării trebuie să se facă atunci când firele au ajuns la un
anumit moment în execuţia lor. Sincronizarea în acest caz se referă la faptul că procesele, care
pot să se execute cu viteze diferite trebuie să aştepte unele după altele până când îşi pot trimite
informaţiile de care au nevoie
10
Fire de execuţie nesincronizate
exemplul de mai jos ilustrează că cele doua variabile nu sunt actualizate în mod corect
la rulări diferite se vor obţine valori diferite pentru cele 2 variabile
Exemplul se referă la situaţia în care mai multe fire de execuţie modifică o resursă comună
package FireExecutie;
void metoda(){
System.out.println(getName()+" a= "+a+" b= "+b);
a++;
try{
sleep((int)(Math.random()*1000));
}
catch(InterruptedException e){}
b++;
}
public void run(){
for (int i=0;i<3;i++)
metoda();
System.out.println( getName()+" GATA a="+ a+"; b="+b);
}
}
Datorită faptului că metoda nu este executată în acces exclusiv, există pericolul ca pe parcursul
execuţiei, un fir de execuţie care a început să execute metoda respectivă să piardă controlul
procesorului şi un alt fir de execuţie care execută aceeaşi metodă dar din alt obiect să înceapă să
se execute
În exemplul următor acelaşi obiect este accesibil din mai multe fire de execuţie, care execută în
paralel metode ale acestui obiect
class AccesComun{
int a=0,b=0; //variabilele nu mai sunt statice
13
Fire de execuţie sincronizate
La nivelul limbajului este posibil să se declare secvenţe de cod care vor fi executate în excludere
mutuală, cu ajutorul lui synchronized
Când începe execuţia unei zone de cod sincronizate, nici un alt fir de execuţie nu poate să
execute zona respectivă de cod. Se creează o coadă de aşteptare.
În acest mod execuţiile metodei din acelaşi obiect dar invocate din fire de execuţie diferite sunt
secvenţializate, şi un singur fir de execuţie poate poate să fie în execuţia metodei respective
package FireExecutie; class TestSincronizare4 extends Thread{
public static void main(String[] args) {
class AccesComun2{ AccesComun2 a=new AccesComun2();
int a=0,b=0; new FirSincroAltfel("1",a).start();
new FirSincroAltfel("2",a).start();
synchronized void metoda(String nume){ System.out.println("GATA main");
Thread t=Thread.currentThread(); }
System.out.println(nume+" a= "+a+" b= "+b); }
a++;
try{
t.sleep((int)(Math.random()*1000)); Rularea x: Rularea y:
}
catch(InterruptedException e){}
b++;
}
}
producătorul depune o valoare în zona de memorie, iar consumatorul extrage o valoare din zonă
de memorie
producătorul nu poate depune o valoare dacă zona de memorie este ocupată, trebuie să aştepte
eliberarea ei
consumatorul nu poate extrage o valoare dintr-o zonă de memorie goală, în acest caz trebuie să
aştepte umplerea ei
package FireExecutie;
public synchronized void aTransmis(int valoare){
class ZonaTampon{ if(disponibil){
private int valoare; try{
private boolean disponibil=false; wait();
}catch(InterruptedException e){}
public synchronized int aPreluat(){ }
if(!disponibil){ this.valoare=valoare;
try{ disponibil=true;
wait(); System.out.println("+ A fost depusa
}catch(InterruptedException e){} valoarea "+valoare+" in resursa");
} notify();
disponibil=false; }
notify(); }//end class
System.out.println("- A fost extrasa
valoarea "+valoare+" din resursa");
return valoare;
}
16
class Producator extends Thread{ class Main4{
private ZonaTampon z; public static void main(String[] args) {
ZonaTampon r=new ZonaTampon();
public Producator(ZonaTampon z){ Producator p=new Producator(r);
this.z=z; Consumator c=new Consumator(r);
} p.start();
c.start();
public void run(){ }
for(int i=0;i<10;i++){ }
z.aTransmis(i);
try{
sleep((int)(Math.random()*1000));
}
catch(InterruptedException e){}
}
}
}
17
Utilizare Join
Dacă un fir de execuţie trebuie să aştepte un alt fir de execuţie ca să preia un rezultat de la el se
poate utiliza Join
În exemplul de mai jos se creează şi se trece în starea gata de execuţie firul c. Firul aşteaptă
terminarea firului de execuţie care face calcule. Terminarea firului de execuţie se face prin
terminarea metodei run(). Pentru a prelua rezultatul se apelează metoda soluţie ().
package FireExecutie;
class UtilizareJoin{
public static void main(String []args){
Calcul c=new Calcul();
c.start();
try{
c.join();
System.out.println("rezultat="+c.solutie());
}
catch(InterruptedException e){
System.out.println("Eroare");
}
} 18
}
10.3 Utilizarea priorităţilor
La pornire un fir de execuţie are asociată o prioritate egală cu cea a firului de execuţie care l-a
pornit
Dacă un fir de execuţie care are o prioritate mai mare decât firul de execuţie care se execută
devine gata de execuţie atunci el va prelua controlul
Dacă avem două fire de execuţie cu aceeaşi prioritate felul în care vor fi tratate depinde de politica
sistemului de operare
Dacă exemplul de mai jos afişează doar “unu”, înseamnă că trecerea de la un fir de execuţie la
altul se face doar când firul de execuţie curent se blochează în mod explicit (execută wait(),
sleep()) sau cedează controlul
Dacă exemplul de mai jos afişează şi “unu” şi “doi”, înseamnă că sistemul de operare atribuie pe
rând cuante de timp celor două fire de execuţie
class Exemplu2 extends Thread{
String mesaj;
public Exemplu2(String mesaj){
this.mesaj=mesaj;
}
public void run(){
while(true)
System.out.println(mesaj);
}
}
class UtilizareExemplu2{
public static void main(String []args){
new Exemplu2("unu").start();
new Exemplu2("doi").start();
}
}
19
Dacă firului de execuţie “doi” i se va atribui o prioritate mai mare decât firului de execuţie “unu”
atunci vor fi afişaţi mai mulţi “doi” pe ecran
class UtilizareExemplu2{
public static void main(String []args){
new Exemplu2("unu").start();
Exemplu2 e=new Exemplu2("doi");
Thread curent=Thread.currentThread();
e.setPriority(curent.getPriority()+1);
e.start();
}
}
20
Caracteristicile limbajului Java
Se traduce în cod executabil printr-un proces în două faze, ce cuprinde, mai întâi, o compilare,
iar apoi, o interpretare. Compilarea se face de la textul Java la un cod de maşină virtuală Java,
iar interpretarea -de la codul de maşină virtuală Java la codul de maşină de execuţie efectivă,
fizică. Prin termenul “maşină virtuală” se desemnează un program translator de limbaj, de tip
interpretor, emulând un procesor ipotetic. Dezavantaje ale limbajului Java în raport cu C++: 1.
necesitatea ca pe maşina de execuţie să fie întotdeauna prezent traducătorul cod intermediar – cod
maşină –adică: maşina virtuală Java-; 2. lungirea timpului total necesar rulării unui program cu
timpul de interpretare a expresiei lui în cod intermediar.
Are un mare grad de independenţă de platformă. Mai exact, este total independent de platformă,
în ceea ce priveşte compilarea de la text Java la byte code şi dependent în privinţa interpretării de
la byte code la cod maşină. Fisierele byte code sunt executate pe calculatoare ce nu au instalat
mediul de programare Java, ci doar o maşină virtuală Java
Este orientat pe obiecte. Zestrea de clase îmbibliotecate ale mediului Java este extrem de bogată
şi complexă.
Este concurent. Concurenţa în Java este una de tip multithreading. Reamintim că prin thread sau
fir de execuţie înţelegem un modul de program ce reuneşte activităţi autonome sau independente şi
are proprietatea că o sesiune de rulare a sa se poate desfăşura în paralel sau cvasiparalel cu sesiunile
de rulare ale altor module delimitate pe acelaşi principiu sau chiar cu alte sesiuni de rulare ale lui
însuşi.
Prezintă câteva simplificări în raport cu C++, şi anume: nu admite moştenirea multiplă, nu
operează cu pointeri, ci cu referinţe, asupra cărora se pot efectua doar operaţii de atribuire, nu şi
operaţii aritmetice, efectuează alocarea / dezalocarea memoriei implicit (există, totuşi, un mecanism
de eliberare a memoriei şi gestiune a ei raţională, numit “garbage collection”), este mai puternic
tipizat.
Este distribuit. Este distribuit în sensul că permite programarea de aplicaţii în care procesarea
este distribuită. Programele Java pot îngloba, alături de obiecte locale, obiecte aflate la distanţă, în
mod normal în reţea, inclusiv în Internet. În Java, sunt respectate protocoalele de reţea FTP, HTTP,
etc.
Este performant. Dezavantajul că fiecare execuţie a unui program Java incumbă şi un proces de
traducere –interpretarea- este diminuat prin faptul că maşinile virtuale Java sunt realizate excelent –
mai nou: cu atributul JIT (Just In Time)- şi apoi compensat prin aceea că programele pot fi
organizate multithreading.
Este dinamic şi robust. În Java, alocarea memoriei este prin excelenţă dinamică –adică: nu se
face la compilare / linkeditare, ci în execuţie- şi orice alocare este precedată de verificări.
Este sigur. Înainte ca interpretorul Java să execute codul intermediar, acesta este supus unor
verificări de tipul: nedepăşirea stivei, etc.
O interfata poate sa reprezinte extensia unei alte interfete, adica sa adauge noi modele
de metode la o interfata care exista. O clasa poate implementa mai mult decat o singura interfata,
adica sa defineasca modul de implementare a metodelor ale caror modele sunt continute in mai
multe interfete. Ex. DataInput si DataOutput, continute in biblioteca Java.io descriu modelele citirii
respectiu scrierii intr-un format independent de masina.
Despre instructiune:
Intructiunea try are cel mult 3 componente:
1) o secventa de instructiuni prin executia carora ar putea sa apara exceptia. Intre
instructiuni sau o met invocata de acestea, apare o instructiune throw sal se executa o instructiune
care poate produce o eroare recunoscuta de interpretorul masinii virtuale care va “arunca” un obiect
al carui tip este o subclasa pt Exception.
2) perechi de argumente catch(tipExceptie) si secventa de cod care trateaza exceptia. Argumentul
primeste ca valoare un obiect care este o instanta a unei subclase a tipului Exception. Se executa
secv de cod asociata. Secventa de cod repr domeniu de valabilitate pt argument.
3) optional - o secventa de instructiuni precedata de cuv cheie finally. Intotdeauna se va executa
secv de instructiuni precedata de finally.
Applet in HTML
Un applet este o colectie de clase Java care se executa prin interpretarea codului obiect de
catre masina virtuala dintr-un program de navigare care "stie" java. Una dintre clase este clasa
"principala" si fisierul care contine codul ei este fisierul care va fi invocat din textul HTML. Clasa
"principala" trebuie intotdeauna sa extinda o clasa speciala numita Applet.
O prima diferenta intre aplicatiile Java si Applet-uri este ca Applet-urile nu contin metoda
statica main(). Executia unui applet se face prin apelarea de catre programul de navigare a unor metode
cu nume standard ale clasei principale. In urma apelarii acestor metode se vor crea obiecte, fire de
executie sau clase principale.
O a doua diferenta intre aplicatiile Java si Applet-uri este ca un applet are asociata o zona in
fereastra programului de navigare. Tot ce afiseaza un applet se realizeaza prin desenare.
Exemplu applet in HTML:
<HTML><BODY>
<APPLET CODE=HelloWorldApplet.class WIDTH=100 HEIGHT=^)>
</APPLET>
</BODY></HTML>
Exemplu de applet in HTML care afiseaza informatii despre locul de unde a fost incarcat,
documetul din care este referit si parametrii:
<HTML><BODY>
<APPLET CODE=InfoApplet.class WIDTH=300 HEIGHT=160
CODEBASE='http://gogu.home.ro/APPLET">
<PARAM NAME='info" VALUE="Un sir parametru">
<PARAM NAME="nl" VALUE="6">
<PARAM NAME='nc" VALUE="40">
</APPLET>
</BODY></HTML>
Dupa ce instantiaza un obiect de tipul InfoApplet programul de navigare apeleaza automat
metoda init() care initializeaza applet-ul, prea parametrii si stabileste ce se va afla pe suprafata applet-
ului. Ulterior se apeleaza automat metodele start() - metoda apelata de fiecare data cand este vizitata
pagina careia ii este asociat applet-ul - si stop() - metoda apelata cand este parasita pagina asociata
applet-ului.
Daca urmeaza distrugerea applet-ului se va apela automat metoda destroy() - spre exemplu
atunci cand va fi incarcat din nou- .
CE POT SA FACA APPLET-URILE: deschid ferestre, lanseaza fire de executie, deschid un document
HTML in acelasi program de navigare care le executa, obtin referinte la alte applet-uri
CE NU POT SA FACA APPLET-URILE: nu au acces la fire de executie care nu le apartin, nu pot lansa
in executie programe, nu pot incarca biblioteci cu legare dinamica, nu pot utiliza fisiere, nu pot stabili
conexiuni TCP/IP, nu pot instala un incarcator de clase, nu pot instala un gestionar de securitate.
Lucrarea 1
Concepte de bază ale programării orientate pe obiecte
Cuprins
Concepte fundamentale în programarea orientată pe obiecte ................................................................................. 1
Primul program Java................................................................................................................................................ 2
Pregătirea instrumentelor software necesare………………………………………............................................... 3
Crearea unui proiect nou, compilarea si rularea lui…............................................................................................. 3
Operaţii de intrare/ieşire la nivel de linii de caractere……………………………………………………………..7
Utilizarea mediului de dezvoltare Eclipse .................……………………………………………………………...9
Temă……………………………………………..…………………………………………………………………9
1) Abstractizarea este una dintre căile fundamentale prin care oamenii ajung să înţeleagă şi
să cuprindă complexitatea. Ea scoate în evidenţă toate detaliile semnificative pentru
perspectiva din care este analizat un obiect, suprimând sau estompând toate celelalte
caracteristici ale obiectului. În contextul programării orientate pe obiecte, toate acestea se
transpun astfel:
• obiectele şi nu algoritmii sunt blocurile logice fundamentale;
• fiecare obiect este o instanţă a unei clase. Clasa este o descriere a unei mulţimi de
obiecte caracterizate prin structură şi comportament similare;
• clasele sunt legate între ele prin relaţii de moştenire.
Referindu-ne strict la structura acestui program, trebuie spus că programele Java sunt
constituite ca seturi de clase (în cazul nostru avem o singură clasă). Pentru descrierea unei
clase se foloseşte o construcţie sintactică de forma:
class nume_clasa {
//continut clasa
}
Aproape orice program, indiferent că este scris într-un limbaj procedural sau obiectual,
are o rădăcină sau un punct de plecare. Astfel, în programele Pascal avem ceea ce se numeşte
program principal, iar în C avem funcţia main(). În programele Java vom avea o clasă
rădăcină care se caracterizează prin faptul că include o funcţie al cărei prototip este:
2
Concepte de bază ale programării orientate pe obiecte
Elementele desemnate prin cuvintele public şi static vor fi lămurite mai târziu. Numele
clasei rădăcină este un identificator dat de programator. Parametrul funcţiei main() este de tip
tablou de elemente String (şiruri de caractere). Prin intermediul acestui parametru putem
referi şi utiliza în program eventualele argumente specificate la momentul lansări în execuţie a
programului. Acţiunile executate de programul de mai sus presupun două operaţii de afişare:
print() şi println(). Prefixul System.out care însoţeşte numele celor două operaţii reprezintă
numele unui obiect: este vorba despre un obiect predefinit care se utilizează atunci când
destinaţia unei operaţii de scriere este ecranul monitorului. Deoarece metodele sunt incluse în
clase şi, majoritatea, şi în instanţele claselor, apelul presupune precizarea numelui clasei (dacă
e vorba de metode statice) sau al obiectului „posesor”. Cu alte cuvinte, în Java, apelul unei
operaţii se realizează folosind una din notaţiile:
nume_obiect.nume_metoda(parametri_actuali)
sau:
nume_clasa.nume_metoda(parametri_actuali)
Revenind la primul nostru program Java, vom spune că metodele print() / println() pot
primi ca parametru un şir de caractere dat, fie sub formă de constante, aşa ca în exemplul
prezentat, fie sub formă de expresii al căror rezultat este de tip String. Metodele print() /
println() mai pot primi ca parametru şi valori ale tipurilor primitive sau referinţe de clase, dar
acestea sunt convertite tot la tipul String înainte de afişare. Println() poate fi apelată şi fără
parametri, caz în care execută doar un salt la linie nouă: System.out.println( );
• JDK (Java Development Kit) JRE (Java Runtime Environment) for Windows:
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
3
Programare Java, Laborator 1
Următorul pas presupune crearea unui nou proiect din meniul File (File > New > Java
Project). În fereastra care se deschide (New Java Project – vezi figura 1.2) se atribuie un
nume proiectului şi se apasă comanda „Finish”.
În următoarea etapă trebuie adăugat un pachet nou în proiectul creat (vezi figura 1.4).
Un pachet reprezintă un grup de tipuri de date (clase, interfeţe, enumerări etc.) care au
legătură între ele. Pachetele oferă protecţie la acces şi gestionarea spaţiului de nume. Câteva
dintre avantajele utilizării pachetelor sunt următoarele:
4
Concepte de bază ale programării orientate pe obiecte
• Pot fi grupate anumite tipuri şi astfel pot fi determinate cu uşurinţă care sunt
tipurile care au legătură între ele.
• Sunt evitate conflictele dintre numele tipurilor aflate în pachete diferite (deoarece
un pachet creează un spaţiu de nume).
Următoarea etapă constă în crearea unei noi clase (vezi fig 1.6), în pachetul selectat.
:
Fig 1.6 – lansarea comenzii de creare a unei noi clase în pachetul selectat
În fereastra pentru crearea unei noi clase se introduce numele acesteia (se recomandă
introducerea unei denumiri care începe cu literă mare) şi se menţionează dacă clasa conţine
metoda main (vezi fig 1.7).
5
Programare Java, Laborator 1
Odată cu crearea clasei se va crea un fişier care conţine numele clasei şi extensia java
(în cazul nostru PrimulProgram.java). Fişierele java sunt amplasate în următoarea cale:
Compilarea şi executarea programului se face apăsând butonul Run (vezi figura 1.9)
sau apăsând combinaţia de taste Ctrl+F11.
În urma compilării vor rezulta un număr de fişiere egal cu numărul claselor conţinute
de sursă. Fiecare dintre fişierele rezultate are extensia .class şi numele identic cu numele
6
Concepte de bază ale programării orientate pe obiecte
clasei căreia îi corespunde (în cazul nostru PrimulProgram.class). Fişierele class vor fi
amplasate pe următoarea cale:
Un fişier .class conţine cod maşină virtual (Java Byte Code). Acesta este codul maşină
al unui calculator imaginar. Pentru a putea fi executat pe o maşină reală, este necesar un
interpretor (sau executiv) care să execute fiecare instrucţiune a codului virtual în termenii
operaţiilor maşină ai calculatorului real. După compilare, programul în cod virtual obţinut
poate fi transportat pe orice maşină pentru care există executivul corespunzător, iar scrierea
unui executiv este mult mai uşoară decât a unui compilator întreg.
7
Programare Java, Laborator 1
la nivel de linie vor fi utilizate două subclase ale clasei Reader (BufferedReader şi
InputStreamReader). Pentru scrierea de linii, se va folosi clasa PrintStream.
Clasa care modelează citirea unei linii dintr-un flux de intrare este BufferedReader,
prin operaţia readLine(). Această operaţie nu are parametri, iar execuţia ei are ca efect citirea
din fluxul de intrare a unei secvenţe de caractere până la întâlnirea terminatorului de linie.
Operaţia returnează o referinţă la un obiect String care conţine caracterele citite, dar fără a
include şi terminatorul. Cu alte cuvinte, şirul returnat conţine doar caracterele utile
(semnificative) ale liniei. Dacă s-a ajuns la sfârşitul fluxului de intrare, operaţia returnează
valoarea null. Dacă citirea nu se poate desfăşura, operaţia emite o excepţie de tip IOException.
De aceea, semnătura unei funcţii care apelează metoda readLine(), dar nu tratează eventualele
erori de citire, trebuie sa conţină clauza throws IOException. Una dintre cele mai frecvente
erori într-un program Java este omiterea clauzelor throws din antetul funcţiilor utilizatorului
care apelează funcţii predefinite dotate cu această clauză. Pentru a crea un obiect al clasei
BufferedReader este necesar să i se furnizeze constructorului acesteia o referinţă la un obiect
al clasei InputStreamReader. Constructorul acesteia din urmă necesită:
• referinţă la un obiect FileInputStream, dacă citirea se face dintr-un fişier de pe disc
• referinţă System.in, dacă citirea se face de la tastatură.
Deci, dacă urmează o citire dintr-un fişier al cărui nume este dat de o variabilă String
nume_fis, va trebui să se creeze un obiect BufferedReader ca în una din cele două secvenţe de
cod de mai jos:
BufferedReader flux_in;
flux_in = new BufferedReader(new InputStreamReader(new FileInputStream(nume_fis)));
//SAU
linie = flux_in.readLine();
unde linie este o referinţă String. În urma apelului, ea va indica spre un obiect care
conţine caracterele citite. Când se ajunge la sfarsitul fișierului funcția readLine() returnează
null. În funcţie de natura datelor reprezentate de aceste caractere, uneori pot fi necesare
conversii de la String la alte tipuri, în vederea utilizării datelor respective în diverse calcule.
Toate clasele înfășurătoare, asociate tipurilor primitive conțin metode de conversie. Spre
exemplu clasa înfășurătoare a tipului primitiv int se numește Integer și conține metoda statica
parseInt(String) care realizeză conversie de la String la tipul primitiv asociat:
int x=Integer.parseInt(“123”);
8
Concepte de bază ale programării orientate pe obiecte
Afişarea unei linii pe ecran se realizează apelând metodele print() / println() definite în
clasa PrintStream, pentru obiectul System.out. Pentru a scrie o linie într-un fişier de pe disc, se
vor folosi aceleaşi metode, dar va trebui să se creeze un obiect separat al clasei PrintStream.
Pentru aceasta, trebuie furnizată constructorului clasei PrintStream, ca parametru, un String
care reprezintă numele fişierului, ca în secvenţa de mai jos:
Facilitatea de autocompletare
Pentru a crește lizibilitatea codului, acesta trebuie scris indentat. Liniile de cod ale
unei funcții se scriu cu un tab spre interiorul funcției. Dacă codul respectiv conține o
instrucțiune repetitivă (for, while, do…while) atunci codul care aparține de acea instrucțiune
repetitivă se pune la un tab de începutul ei, etc. Eclipse dispune de o facilitate de
9
Programare Java, Laborator 1
Depanarea programelor
Prima acțiune care trebuie realizată atunci când se dorește depanarea unui program
este modificarea persepctivei din Eclipse. Se alege opțiunea de meniu Window > Open
perspective > Debug sau se lansează aceeași comandă prin accționarea butonului Open
Perspective de pe bara de unelte din colțul dreapta sus. În continuare se pune un Break Point
pe linia pe care se dorește întreruperea execuției programului. Break pointul se introduce cel
mai rapid prin dublu click în partea stangă a cifrei care indică numărul liniei de cod. Pentru ca
programul să ruleze până la break point trebuie lansată comanda Debug (opțiunea de meniu
Run > Debug) sau și mai rapid se apasă tasta F11). Programul va rula până la break point și în
continuare poate fi rulat pas cu pas urmărind evoluția variabilelor în memorie. Se poate utiliza
comanda F5 (Step into) ca să intre în metodele apelate și să permită executarea acestora pas
cu pas, sau F6 (Step over) ca să execute metodele apelate cu totul fără a intra în ele. Valorile
tuturor variabilelor active în zona de cod care se depanează este afișat în secțiune Variables, a
perspecțivei Debug. După ce depanarea programului s-a încheiat se revine la persepctiva
adecvată dezvoltării de aplicații Java Standard Edition.
Temă
1. Se cere să se scrie un program Java care să calculeze şi să afişeze perimetru şi aria unui
dreptunghi. Valorile pentru lungime şi lățime se citesc de la tastatura. Sa se adauge un break
point pe prima linie care citește valoarea unei laturi si din acel punct să se ruleze programul
linie cu linie urmărind valorile variabilelor în memorie.
2. Să se scrie un program care citește un set de numerele din fișierul de intrare in.txt, care are
conținutul din figura 1.11. Programul va determină suma lor, media aritmetică, valoarea
minimă, valoarea maximă, va afișa aceste valori pe ecran și le va scrie în fișierul de ieșire
out.txt. Media aritmetică va fi afișată ca un număr real.
4. Să se determine cmmdc a două numere naturale, a căror valoare maximă este 30. Numerele
vor fi generate aleatoriu cu ajutorul unui obiect de tip Random și metodei nextInt();
5. Să se scrie un program care generează aleatoriu un număr întreg cuprins între 0 și 20.
Progamul va determina dacă numărul aparține șirului lui Fobonacci.
10
Lucrarea 2
Componenţa unei clase. Crearea şi iniţializarea obiectelor.
Tablouri
Cuprins
Componenţa unei clase............................................................................................................................................. 1
Crearea obiectelor.................................................................................................................................................... 1
Modificatori de acces............................................................................................................................................... 2
Iniţializarea câmpurilor unui obiect. Constructori .................................................................................................. 3
Membri statici ai claselor......................................................................................................................................... 5
Iniţializarea variabilelor…....................................................................................................................................... 6
Simbolul this.............................................................................................................................................................6
Colectorul de reziduuri (Garbage Collector) ...........................................................................................................8
Tablouri în Java ........................................................................................................................................................9
Temă......................................................................................................................................................................... 9
class Punct{
private int x;
private int y;
public void init(int xx, int yy) {
x = xx; y = yy;
}
public void move(int dx, int dy) {
x += dx; y += dy;
}
public int getX( ) { return x; }
public int getY( ) { return y; }
}
Crearea obiectelor
În continuare se va considera un mic program Java pentru a vedea cum se creează
obiectele clasei Punct descrisă anterior:
class Punct{
private int x;
private int y;
public void init(int xx, int yy) {
x = xx; y = yy;
}
public void move(int dx, int dy) {
x += dx; y += dy;
}
public int getX( ) { return x; }
public int getY( ) { return y; }
}
class MainApp {
public static void main(String[ ] args) {
Punct p1 = new Punct( ); //se creează o instanţă a clasei Punct
Punct p2 = new Punct( ); // şi încă una
p1.init (10,20); p2.init (30,40); //se apeleaza metodele init ale instantelor
p1.move(5,5); p2.move(6,-2); //se apeleaza metodele move
System.out.println("(x1,y1) = ("+p1.getX()+","+p1.getY( )+ ")"); //se afiseaza
//coordonatele curente ale primului punct
System.out.println("(x2,y2) = ("+p2.getX()+","+ p2.getY( )+ ")"); //se afiseaza
//coordonatele curente ale celui de-al 2-lea punct
}
}
Modificatori de acces
Se poate observa că definiţiile datelor şi ale funcţiilor din clasa Punct sunt prefixate de
anumite cuvinte cheie (public, private) care se numesc modificatori de acces. Aceştia
stabilesc drepturile de acces ale clienţilor la membrii unei clase. Când se discută despre
drepturile de acces la membrii unei clase trebuie să se abordeze acest subiect din două
perspective:
• Interiorul clasei sau, mai concret, metodele clasei. În cadrul metodelor unei clase
există acces nerestrictiv la toţi membrii, date sau funcţii. De exemplu, în metodele
clasei Punct se face referire la câmpurile x şi y. În interiorul clasei nu se foloseşte
notaţia cu punct pentru a referi membrii, aceştia fiind pur si simplu accesaţi prin
2
Componenţa unei clase. Crearea şi iniţializarea obiectelor. Tablouri
numele lor. Când o metodă face referire la alţi membri ai clasei, de fapt sunt accesaţi
membrii corespunzători ai obiectului receptor, indiferent care ar fi el. De exemplu,
când se apelează metoda init() a obiectului referit de p1, are loc iniţializarea
membrilor x şi y ai acelui obiect. În legătură cu accesul din interiorul unei clase,
trebuie spus că absenţa restricţiilor se aplică şi dacă este vorba despre membrii altui
obiect din aceeaşi clasă, dar diferit de cel receptor. De exemplu, dacă în clasa Punct
am avea câte o metodă de calcul a distanţei pe verticală/orizontală dintre 2 puncte,
unul fiind obiectul receptor, iar celălalt un obiect dat ca parametru, atunci am putea
scrie:
class Punct{
//. . .
public int distV(Punct p) {
return y - p.y;
}
public int distH(Punct p) {
return x - p.x;
}
//. . .
}
Se observă că din interiorul metodelor distV() / distH() putem accesa liber membrii
privaţi ai obiectului p dat ca parametru. La fel ar sta lucrurile şi dacă p ar fi o variabilă locală
a unei metode din clasa Punct.
• Exteriorul sau clienţii clasei. Clienţii unei clase pot accesa doar acei membri care au
ca modificator de acces cuvântul public. Membrii declaraţi cu modificatorul private
NU sunt vizibili în afară, sunt ascunşi. Dacă s-ar încerca folosirea, în metoda main()
din exemplul considerat, o referinţă de genul:
p1.x
3
Programare Java, Laborator 2
class Punct{
//. . .
public Punct(int xx, int yy) {
x = xx; y = yy;
}
public Punct(Punct p) {
x = p.x; y = p.y;
}
//. . .
}
Caracteristicile unui constructor sunt:
• este o metodă care are acelaşi nume cu clasa în care este definită
• nu are tip returnat (nici măcar void)
• se apelează în mod automat la crearea unui obiect
Astfel, în locul metodei init(), în funcţia main() a clasei MainApp, se poate scrie:
class MainApp {
public static void main(String[ ] arg) {
Punct p1 = new Punct(10,20 ); //se creează o instanţă a clasei Punct
Punct p2 = new Punct(30,40 ); // şi încă una
//. . .
}
}
O clasă poate avea mai mulţi constructori, datorită facilităţii de supraîncărcare a
funcţiilor existentă în limbajul Java. Se oferă, astfel, posibilitatea de a defini, în acelaşi
domeniu de vizibilitate, mai multe funcţii care au acelaşi nume, dar parametrii diferiţi ca tip şi
număr. Al doilea constructor definit anterior poate fi apelat astfel:
class Punct{
private int x; //iniţializator implicit
private int y = 1; //iniţializator explicit
//se presupune că nu există constructori
}
//. . .
Punct p1 = new Punct(); //în acest caz p1.x = 0 si
p1.y=1
4
Componenţa unei clase. Crearea şi iniţializarea obiectelor. Tablouri
class Punct{
private int x=2; //iniţializator explicit
{ //bloc de iniţializare
int a=1,b=1;
for(int i=3;i <= 6;i++)
{
b+=a; a=b-a;
x+=b;
}
//. . .
}
Deosebirea esenţială dintre constructori şi celelalte tipuri de iniţializări este aceea că,
în cazul constructorilor, se putea iniţializa fiecare instanţă cu valori diferite care se transmit ca
parametri. Celelalte mecanisme de iniţializare presupun ca toate instanţele clasei respective să
aibă aceleaşi valori. Dacă se doreşte crearea şi iniţializarea unui câmp cu comportare
echivalentă unei constante din limbajul C++, atunci câmpul este marcat ca final, cuvânt cheie
plasat între modificatorul de acces şi tip.
Referirea unui membru static nu se va face prin intermediul numelui obiectului, ci prin
intermediul numelui clasei:
nume_clasa.nume_membru_static
5
Programare Java, Laborator 2
class Punct{
private int x;
private int y;
private static int contor=0; //iniţializator implicit
public Punct(int xx,int yy ) { x=xx; y=yy; }
public void move(int dx, int dy) { x+=xx; y+=yy;contor++;}
public static int getContor() {return contor;}
//. . .
}
//. . .
//metoda main din clasa rădăcină
Punct p1 = new Punct(10,20);
Punct p2 = new Punct(15,13);
p1.move(8,-2); p2.move(6,7);
//. . .
System.out.println(”S-au executat “+Punct.getContor()+”mutari.”);
În legătură cu membrii statici ai unei clase trebuie făcută următoarea observaţie: într-o
metodă statică nu este permisă referirea simplă a unui membru non-static. Acest lucru se
explică prin aceea că un membru non-static există doar în interiorul unui obiect, pe când
membrii statici există independent de obiecte. Dacă în exemplul dat s-ar fi declarat variabila
contor ca non-statică, atunci ea ar fi existat în atâtea exemplare, câte obiecte s-ar fi creat şi ar
fi contorizat pentru fiecare obiect în parte numărul de apeluri ale metodei move().
Iniţializarea variabilelor
În Java, variabilele al căror tip este o clasă sunt reprezentate ca referinţe (adrese) spre
obiecte ale clasei. Pentru a putea iniţializa o asemenea referinţă, trebuie generat un obiect nou
sau folosită o referinţă la un obiect deja existent. Unei referinţe îi poate fi atribuită valoarea
specială null, care se traduce prin faptul că referinţa respectivă nu indică nici un obiect.
Valoarea null nu este atribuită automat tuturor variabilelor referinţă la declararea lor, ci
conform următoarei reguli: dacă referinţa este o dată membru a unei clase şi ea nu este
iniţializată în nici un fel, la crearea unui obiect al clasei respective referinţa va primi implicit
valoarea null. Dacă referinţa este o variabilă locală a unei metode, iniţializarea implicită nu
mai funcţionează. De aceea, se recomandă ca programatorul să realizeze ÎNTOTDEAUNA o
iniţializare explicită a variabilelor.
Simbolul this
Simbolul this este o referinţă care poate fi utilizată doar în cadrul funcţiilor membru
non-statice ale unei clase. Din punctul de vedere al unei funcţii membru, acesta este referinţa
spre obiectul receptor, „posesor“ al acelei funcţii. Se poate spune că this reprezintă „conştiinţa
de sine“ a unui obiect, în sensul că obiectul îşi cunoaşte adresa la care este localizat în
memorie. Practic, orice referire a unei date membru nonstatice v în interiorul unei metode,
poate fi considerată ca echivalentă cu this.v. De exemplu, metoda move() din clasa Punct,
poate fi scrisă sub forma:
6
Componenţa unei clase. Crearea şi iniţializarea obiectelor. Tablouri
class Punct {
private int x;
private int y;
//. . .
public void move(int dx, int dy) {
this.x += dx;
this.y += dy;
}
//. . .
}
Referinţa this este folosită explicit în cazul în care ar putea exista conflicte de nume cu
datele membru ale unui obiect. De exemplu:
class Punct {
private int x,y;
//. . .
public Punct(int x, int y){
// parametrii constructorului au nume
// identice cu cele ale datelor membru
this.x = x;
this.y = y;
}
}
O altă situaţie când se foloseşte explicit referinţa this este atunci când referinţa la
obiectul receptor trebuie transmisă ca parametru la apelul unei alte metode.
class Context {
private int x;
private Algoritm a;
// obiectul Algoritm va executa anumite calcule pentru un obiect Context
class Algoritm {
public int Calcul(Context c) {
return c.getX()*c.getX();
}
}
7
Programare Java, Laborator 2
În fine, simbolul this reprezintă mijlocul prin care poate fi apelat un constructor al unei
clase din interiorul altui constructor al aceleiaşi clase.
class OClasa {
private int x,y;
public OClasa(int x, int y) {
this.x = x;
this.y = y;
}
public OClasa(OClasa p) {
this(p.x, p.y); // se apelează constructorul cu 2 parametri int
}
//. . .
}
Apelul unui constructor din interiorul altui constructor al clasei în cauză NU înseamnă
crearea unui nou obiect, ci, pentru obiectul receptor curent, se va executa codul
constructorului apelat, la fel ca în cazul apelării unei funcţii-membru obişnuite. De asemenea,
un constructor nu poate fi apelat cu ajutorul simbolului this DECÂT din interiorul altui
constructor şi nu al altor metode. În felul acesta se asigură îndeplinirea condiţiei ca pentru un
obiect iniţializarea datelor prin constructor să se execute O SINGURĂ dată. Referinţa this NU
poate fi utilizată în interiorul unei funcţii-membru statice. Referinţa this nu poate fi modificată
(nu poate să apară ca membru stâng într-o atribuire) şi nu poate să apară în afara corpului de
instrucţiuni al metodelor non-statice ale unei clase sau în afara blocurilor de iniţializare
asociate cu variabilele membru ale unei clase.
această metodă va fi executată chiar înainte ca obiectul să dispară. Dacă metoda este
definită astfel încât să tipărească pe ecran un anumit mesaj, poate fi detectat momentul în care
un obiect este eliminat din memorie.
8
Componenţa unei clase. Crearea şi iniţializarea obiectelor. Tablouri
Tablouri în Java
Limbajul Java oferă tipul tablou (tip predefinit), cu ajutorul căruia se pot crea colecţii
de variabile de acelaşi tip. Componentele tabloului pot fi accesate cu ajutorul unui index.
Acesta trebuie să aparţină unui tip întreg, iar numerotarea elementelor într-un tablou începe
întotdeauna de la 0, la fel ca şi în C. Un tablou se declară astfel:
tip_element[ ] nume_tablou;
}
public static void main(String[ ] arg) {
int [ ] tab = new int[10];
//. . .
oFunctie(tab);
//. . .
}
}
Dacă elementele unui tablou sunt, la rândul lor, de tip clasă, elementele respective vor
fi referinţe la obiecte ale acelei clase. La crearea tabloului se rezervă spaţiu DOAR pentru
acele referinţe şi ele sunt iniţializate cu valoarea null.
tip_element[ ] [ ] nume_matrice;
9
Programare Java, Laborator 2
Temă
1. Să se parcurgă exemplele prezentate în laborator şi să se testeze practic (acolo unde
este cazul).
10
Lucrarea 3
Cuprins
Clasa String ..............................................................................................................................................................1
Obiecte String şi tablouri de caractere......................................................................................................................2
Compararea obiectelor..............................................................................................................................................2
Compararea șirurilor de carcatere.............................................................................................................................3
Conversii între tipul String şi tipurile primitive........................................................................................................4
Clase înfăşurătoare ...................................................................................................................................................5
Temă.........................................................................................................................................................................8
Clasa String
Clasa String este una dintre clasele predefinite, fundamentale, care modelează lucrul
cu şiruri de caractere. Modul cel mai simplu de manipulare a obiectelor de tip String îl
constituie constantele String, care sunt şiruri de caractere încadrate de ghilimele. Orice
referire a unei asemenea constante în cadrul unui program Java are ca efect crearea unui
obiect String care conţine secvenţa de caractere respectivă.
char[ ] tc = {'a','b','c'};
String stc = new String(tc);
Clasa String oferă un set de metode pentru prelucrarea unor şiruri existente:
String toUpperCase();
String toLowerCase();
String substring(int);
String substring(int, int);
Metodele clasei String includ şi operaţii care permit consultarea şirurilor de caractere,
respectiv, obţinerea de informaţii despre conţinutul lor:
int length();
Programare Java, Laborator 3
char charAt(int);
int indexOf(char);
int indexOf(String);
int lastIndexOf(char);
int lastIndexOf(String);
O proprietate foarte importantă a metodelor clasei String este aceea că ele nu modifică
NICIODATĂ obiectul receptor, ci creează obiecte noi în care este inclus şirul de caractere
modificat. În Java, operaţia de concatenare se realizează cu ajutorul operatorului „+“ . Va fi
creat unu obiect nou, al cărui conţinut va fi şirul rezultat prin concatenare.
într-o expresie de concatenare pot să apară ca operanzi şi obiecte ale altor clase decât
String, cu condiţia ca în clasele respective să fie definită metoda toString care să
genereze obiecte String.
Compararea obiectelor
Una dintre operaţiile cele mai frecvente de comparare a obiectelor este testarea
egalităţii. În Java această operaţie poate avea două sensuri:
testarea identităţii: în acest caz ceea ce se compară sunt două referinţe de obiect, iar
testul presupune a verifica dacă cele două referinţe indică unul şi acelaşi obiect.
Testarea identităţii se realizează cu ajutorul operatorului ==
testarea echivalenţei: în acest caz operanzii sunt două obiecte propriu-zise şi testul
presupune a verifica dacă cele două obiecte au conţinut asemănător. De regulă, pentru
testarea echivalentei se utilizează o metodă denumită equals(), operanzii fiind un
2
Şiruri de caractere. Compararea obiectelor. Clase înfăşurătoare
obiect receptor şi unul dat ca parametru metodei. Această metodă este definită în clasa
Object şi este moştenită de toate clasele.
Definiţia metodei equals(), aşa cum apare ea în clasa Object, pentru majoritatea
claselor utilizatorului nu este satisfăcătoare. Ca urmare, programatorul va trebui să-şi
definească propriile variante de equals(), acolo unde este cazul. Pentru clasa Punct, o posibilă
implementare a metodei equals() ar fi:
class Punct{
private int x,y;
public Punct(int x, int y){
this.x = x;
this.y = y;
}
public boolean equals(Punct p) {
return ((x==p.x) && (y==p.y));
}
}
class ClientPunct {
public static void main(String []args ) {
Punct p1 = new Punct(1,2);
Punct p2 = new Punct(1,2);
Punct p3 = p1;
boolean t1 = (p1==p2); //test de identitate; rezultat: false
boolean t2 = p1.equals(p2); //test de echivalenta; rezultat: true
boolean t3 = (p1==p3); //test de identitate; rezultat: true
System.out.println(t1);
System.out.println(t2);
System.out.println(t3);.
}
}
class oClasa {
public void oMetoda( ) {
String s1 = new String("ababu");
String s2 = new String("ababu");
String s3 = s1;
boolean t1 = (s1==s2); //test de identitate; rezultat: false
boolean t2 = s1.equals(s2); //test de echivalenta; rezultat: true
3
Programare Java, Laborator 3
String s4 = "ababu";
String s5 = "ababu";
boolean t4 = (s4==s5); //test de echivalenta; rezultat: true
//. . .
}
}
class oClasa {
public void oMetoda( ){
int a = 4;
double b = 13.2;
boolean c = true;
String s1 = String.valueOf(a);
String s2 = String.valueOf(b);
String s3 = String.valueOf(c);
//. . .
}
}
4
Şiruri de caractere. Compararea obiectelor. Clase înfăşurătoare
valueOf() este o metodă statică, supraîncărcată astfel încât să admită ca parametri valori ale
tuturor tipurilor primitive. Efectul metodei este crearea unui obiect String al cărui conţinut
este obţinut prin conversia la şir de caractere a valorii parametrului. Ca rezultat, metoda
returnează o referinţă la obiectul String creat. Pentru a realiza conversiile în sens invers, adică
de la String spre tipurile primitive se utilizează metode ale unor clase speciale, numite clase
înfăşurătoare (wrapper classes).
Clase înfăşurătoare
Tuturor tipurilor primitive din limbajul Java le corespunde câte o clasă înfăşurătoare.
Aceste clase au fost definite din două motive:
să înglobeze metode de conversie între valori ale tipurilor primitive şi obiecte ale altor
clase, precum şi constante speciale legate de tipurile primare;
să permită crearea de obiecte care să conţină valori ale tipurilor primare, şi care apoi
să poată fi utilizate în cadrul unor structuri unde nu pot să apară decât obiecte, nu date
simple.
câte un constructor care acceptă ca parametru o referinţă String (excepţie face clasa
Character care nu are acest constructor). Se presupune că şirul respectiv conţine o
secvenţă compatibilă cu tipul primitiv corespondent.
Integer a = Integer.valueOf("5");
Double b = Double.valueOf("-8.12");
5
Programare Java, Laborator 3
De multe ori este necesar ca datele conţinute de obiecte să fie convertite la şiruri de
caractere în vederea participării obiectelor respective ca operanzi în expresii de manipulare a
şirurilor. De exemplu, funcţiile print() / println() necesită ca parametru o referinţă String.
Convertind un obiect la String, am putea să afişăm acel obiect cu ajutorul funcţiilor
print()/println(). Programatorul trebuie să-si definească în clasele sale câte o metodă
toString(), dacă doreşte să convertească obiectele respective la şiruri.
class Punct {
//. . .
public String toString( ) {
String s = "("+String.valueOf(x)+","+String.valueOf(y)+")";
return s;
}
}
o metodă typeValue(), unde type este numele tipului primitiv corespondent; această
metodă returnează conţinutul obiectului ca valoare a tipului primitiv.
6
Şiruri de caractere. Compararea obiectelor. Clase înfăşurătoare
import java.io.*;
String linie;
boolean sw = true;
for(i=0;i<tab.length;i++){
System.out.println("Dati elementul de pe pozitia "+(i+1));
linie=flux_in.readLine();
tab[i]=Integer.parseInt(linie);
}
while(sw){
sw=false;
for(i=o;i<tab.length-1;i++)
if(tab[i]>tab[i+1]){
aux=tab[i];
tab[i]=tab[i+1];
tab[i+1]=aux;
sw=true;
}
}
System.out.println("Tabloul ordonat este:");
for(i=0;i<tab.length;i++)
System.out.println(tab[i]+" ");
}
}
7
Programare Java, Laborator 3
Temă
1. Fişierul cantec_in.txt conţine versurile unui cântec la alegere. Să se scrie un
program care creează fişierul cantec_out.txt, care conţine versurile cântecului original dar în
plus în dreptul fiecărui rând sunt afişate numărul de cuvinte de pe rând şi numărul de vocale
de pe fiecare rând. În dreptul rândurilor care se încheie cu o grupare de litere aleasă se va
pune o steluţă (*). Rândurile pentru care un număr generat aleator este mai mic decât 0.1 vor
fi scrise cu majuscule (se vor genera aleator numere între 0 şi 1). Se va defini o clasă Vers,
care are o variabilă membră privată un șir de caractere reprezentând versul și se va dezvolta
câte un operator pentru fiecare cerință de mai sus (o metodă care returnează numărul de
cuvinte, o metodă care returnează numărul de vocale, etc).
2. Să se insereze într-o anumită poziție a unui șir de caractere, un alt șir. Datele vor fi
preluate de la tastatură sau din fișier. Să se șteargă o porțiune a unui șir de caractere care
începe dintr-o anumită poziție și are un anumit număr de caractere. Se recomandă utilizarea
clasei StringBuilder.
8
Lucrarea 4
Moştenire şi polimorfism
Cuprins
Relaţia de moştenire în Java .....................................................................................................................................1
Reguli de vizibilitate în contextul relaţiei de moştenire ...........................................................................................2
Constructorii şi moştenirea........................................................................................................................................4
Operatorul instanceof ...............................................................................................................................................4
Redefinirea metodelor ..............................................................................................................................................5
Legarea dinamică şi constructorii.............................................................................................................................7
Temă.........................................................................................................................................................................8
class Poligon {
protected double[ ] laturi;
public Poligon(int n) { laturi = new double[n] }
public double perimetru( ) {
double s=0;
for(int i=0;i<laturi.length;i++) s+=laturi[i];
return s;
}
}
class Dreptunghi extends Poligon {
public Dreptunghi(double L, double h){
super(4);
laturi[0] = laturi[2] = L;
Programare Java, Laborator 4
laturi[1] = laturi[3] = h;
}
public double aria( ){
return laturi[0]*laturi[1];
}
}
Clasa Dreptunghi reutilizează codul definit în clasa Poligon, la care adaugă elemente
proprii. Pe lângă Dreptunghi, am putea defini şi alte clase, cum ar fi Triunghi, Patrat,
Pentagon etc. care să moştenească Poligon. Superclasa este factorul comun al subclaselor sale
sau, altfel spus, codul factorului comun este reutilizat în subclase.
Despre relaţia de moştenire în Java se pot spune următoarele:
• o subclasă poate extinde o singură superclasă (moştenire simplă)
• o superclasă poate fi moştenită de mai multe subclase distincte
• o subclasă poate fi superclasă pentru alte clase
• o clasă de bază împreună cu toate descendentele ei formează o ierarhie de clase.
class SuperClasa {
private int priv;
protected int prot;
public int pub;
}
class SubClasa extends SuperClasa {
private int priv_local;
protected int prot_local;
public int pub_local;
public void metoda(SubClasa p ) {
priv = 1; //eroare
prot = 2; //corect
pub = 3; //corect
priv_local = 4; //corect
prot_local = 5; //corect
pub_local = 6; //corect
p.priv = 1; //eroare
p.prot = 2; //corect
p.pub = 3; //corect
p.priv_local = 4; //corect
2
Moştenire şi polimorfism
p.prot_local = 5; //corect
p.pub_local = 6; //corect
}
}
În metodele specifice ale unei subclase pot fi referiţi acei membri moşteniţi, care în
superclasă au fost precedaţi de modificatorii protected sau public. Membrii moşteniţi, care în
superclasă sunt precedaţi de modificatorul private, deşi fizic fac parte din subclasă, nu sunt
accesibili în metodele acesteia. Referirea membrilor moşteniţi se face direct, folosind numele
lor, la fel ca referirea membrilor specifici.
Acest lucru este foarte normal, deoarece şi membrii moşteniţi sunt conţinuţi în
subclasă, numai că ei nu au fost declaraţi explicit. Includerea lor se face automat, ca efect al
clauzei extends. Acest lucru nu este valabil şi pentru constructori. Revenind la exemplul cu
clasele Poligon — Dreptunghi, trebuie spus că un obiect al clasei Dreptunghi conţine doi
constructori: unul moştenit, responsabil cu iniţializarea porţiunii moştenite, şi unul local,
responsabil cu iniţializarea porţiunii specifice subclasei. Referirea în subclasă la constructorul
moştenit se face folosind cuvântul cheie super, aşa cum se observă în constructorul clasei
Dreptunghi.
Cuvântul super este un omolog al lui this şi reprezintă referinţa la partea moştenită a
unui obiect. În afară de apelul constructorului moştenit, cuvântul super se va utiliza pentru a
distinge între un membru local al subclasei şi un membru moştenit, ambii cu acelaşi nume.
class Client {
public void oFunctie( ) {
SuperClasa sp = new SuperClasa();
SubClasa sb = new SubClasa();
sp.priv = 1; //eroare
sp.prot = 2; //corect, doar dacă Client şi SuperClasa s-ar afla in acelaşi pachet
sp.pub = 3; //corect
sb.priv = 1; //eroare
sb.prot = 2; //corect, doar dacă Client şi SubClasa s-ar afla în acelaşi pachet
sb.pub = 3; //corect
sb.priv_local = 4; //eroare
sb.prot_local = 5; //corect, doar dacă Client şi SubClasa s-ar afla în acelaşi pachet
sb.pub_local = 6; //corect
}
}
În clienţii unei subclase pot fi referiţi acei membri, moşteniţi sau locali, care sunt
precedaţi de modificatorul public. Membrii declaraţi ca protected sunt accesibili numai în
situaţia în care clientul se află în acelaşi pachet cu subclasa respectivă. La referirea membrilor
unei subclase de către client, nu se face deosebire între membrii moşteniţi şi cei locali.
3
Programare Java, Laborator 4
Constructorii şi moştenirea
În exemplul anterior se observă că cele două clase nu au constructori expliciţi,
constructorul SubClasa() fiind de forma:
public SubClasa(. . .) {
super(); //apel implicit
//alte instrucţiuni prevăzute de programator
}
Dacă SuperClasa nu are constructor no-arg, apelul implicit de mai sus ar genera
eroare. Prin urmare, dacă programatorul defineşte constructori expliciţi într-o subclasă, el
trebuie să aibă grijă ca aceşti constructori să apeleze explicit constructorii adecvaţi ai
superclasei:
super (parametri-actuali)
Operatorul instanceof
Prin intermediul unei referinţe de superclasă putem indica şi utiliza şi obiecte ale
subclaselor ei. Operatorul instanceof este util atunci când trebuie să cunoaştem clasa concretă
de care aparţine un obiect referit prin intermediul unei referinţe a unui supertip. Aplicarea
operatorului se face printr-o expresie de forma:
4
Moştenire şi polimorfism
Redefinirea metodelor
Relaţia de moştenire poate fi utilizată atunci când o anumită clasă (subclasă) extinde
comportamentul altei clase (superclase), în sensul că superclasa înglobează aspectele comune
ale unei ierarhii de abstracţiuni, iar subclasele adaugă la această parte comună funcţiuni
specifice. De asemenea, o referinţă la superclasă poate indica şi manipula obiecte ale oricărei
clase descendente din ea. Manipularea se referă la faptul că, prin intermediul acelei referinţe
se pot apela metodele definite în superclasă, indiferent dacă obiectul concret aparţine
superclasei sau uneia dintre subclase. Această facilitate constituie aşa-numitul polimorfism
parţial. Folosind o referinţă a superclasei nu se poate, însă, apela o metodă locală a subclasei,
decât dacă se realizează o conversie explicită (casting) a referinţei, la tipul subclasei. În Java
relaţia de moştenire poate fi aplicată şi în cazul în care se doreşte ca, pe lângă extinderea
comportamentului, să realizăm şi o adaptare (specializare) a lui, în sensul că unele metode
care în superclasă au o anumită implementare, în subclase să aibă o altă implementare,
adaptată la cerinţele locale ale subclasei.
package exemplu1;
class Angajat {
protected String nume;
protected double sal_ora;
5
Programare Java, Laborator 4
class MainApp {
public static void main(String[] args) {
Angajat a1 = new Angajat("Artaxerse Coviltir", 100);
Angajat a2 = new Sef("Al Bundy", 200, 33.2);
final int ore_luna = 160;
Se observă că aceeaşi metodă, calcSalar() apare atât în clasa Angajat, cât şi în clasa
Sef, dar cu implementări diferite. Atunci când într-o subclasă apare o metodă având
semnătura identică cu o metoda din superclasă, se spune că metoda din subclasă o
redefineşte pe omonima ei din superclasa. În acest caz, un obiect al subclasei practic are două
exemplare ale metodei respective, unul moştenit şi unul propriu. Ce se întâmplă la nivelul
clienţilor ierarhiei? Se observă că în metoda main() din clasa MainApp se folosesc două
referinţe la Angajat: una indică un obiect al clasei Angajat, iar cealaltă un obiect al clasei Sef.
Prin intermediul celor două referinţe se apelează metoda calcSalar(). Se pune problema care
dintre cele două forme ale metodei se apelează efectiv? În Java, regula care se aplică în
asemenea cazuri este următoarea: Se va executa întotdeauna acel exemplar de metodă care
este definit în clasa la care aparţine obiectul concret indicat de referinţa utilizată.
Cu alte cuvinte, clasa obiectului „dictează“ şi nu tipul referinţei. Astfel, deşi ambele
referinţe a1 şi a2 din exemplul considerat sunt de tip Angajat, ele indică, de fapt, obiecte ale
unor clase diferite. Deci, apelul a1.calcSalar(...) va declanşa execuţia metodei calcSalar()
definită în clasa Angajat, iar apelul a2.calcSalar(...) va declanşa execuţia metodei calcSalar()
definită în clasa Sef. Polimorfismul permite interschimbarea obiectelor indicate de o
referinţă a superclasei, într-o manieră transparentă pentru clienţi.
În interiorul subclasei se poate realiza distincţia între cele două variante ale unei
metode redefinite, şi anume folosind simbolul super. Astfel, metoda calcSalar() din clasa Sef
se poate folosi de omonima ei din clasa Angajat:
6
Moştenire şi polimorfism
Practic, aceasta este singura situaţie în care nu se aplică legarea dinamică, ci apelul de
forma super.numeMetoda(...) este pus în corespondenţă exact cu implementarea din
superclasa clasei curente.
package exemplu2;
class SuperClasa {
protected int a;
protected int rez;
private int x;
public SuperClasa() {
a = 1;
rez = 2;
x = calcul(); //x=0
}
@Override
public String toString() {
return "SuperClasa [a=" + a + ", rez=" + rez + ", x=" + x + "]";
}
7
Programare Java, Laborator 4
public SubClasa() {
b = 3;
y = calcul();
}
@Override
public String toString() {
return super.toString()+" SubClasa [b=" + b + ", y=" + y + "]";
}
}
8
Moştenire şi polimorfism
Temă
1. Problema propusă încearcă să dea o mână de ajutor în gestionarea produselor unei firme
care comercializează echipamente electronice. Fiecare echipament este înregistrat cu o
denumire, un număr de inventar nr_inv, are un preţ pret şi este plasat într-o anumită zonă din
magazie zona_mag. Orice echipament poate fi într-una din situaţiile:
• achiziţionat (intrat în magazie);
• expus (expus în magazin);
• vândut (transportat şi instalat la client).
Firma comercializează mai multe tipuri de echipamente. Toate echipamentele care
folosesc hârtia drept consumabil sunt caracterizate de numărul de pagini scrise pe minut ppm.
Imprimantele sunt caracterizate de rezoluţie (număr de puncte per inch dpi) şi număr de
pagini/cartuş p_car. Unei imprimante i se poate seta modul de scriere:
• tipărireColor (selectere a modului color de tipărire);
• tipărireAlbNegru (selectere a modului alb-negru de tipărire).
Copiatoarele sunt caracterizate de numărul de pagini/toner p_ton. Se poate seta formatul
de copiere:
• setFormatA4 (setare a formatului A4);
• setFormatA3 (setare a formatului A3).
9
Lucrarea 5
Interfeţe
Cuprins
Interfeţe Java............................................................................................................................................................1
Declararea unei interfeţe în Java...............................................................................................................................1
Utilizarea interfeţelor Java........................................................................................................................................2
Exemplu de lucru cu interfeţe Java...........................................................................................................................3
Asocierea operaţiilor cu obiectele............................................................................................................................4
Temă.........................................................................................................................................................................5
Un obiect include date şi metode (operaţii) care permit modificarea datelor. Obiectul
execută o operaţie atunci când primeşte o cerere (un mesaj) de la un client. Mesajele
reprezintă singura cale prin care un obiect este determinat să execute o operaţie, iar operaţiile
sunt singurul mod de a modifica datele interne ale obiectului. Din cauza acestor restricţii,
starea internă a obiectului se spune că este încapsulată: ea nu poate fi accesată direct, iar
reprezentarea ei este invizibilă dinspre exteriorul obiectului. Pentru fiecare operaţie declarată
într-un obiect se precizează numele, parametrii şi valoarea returnată. Aceste elemente
formează semnătura operaţiei.
Mulţimea tuturor semnăturilor corespunzătoare operaţiilor dintr-un obiect, accesibile
clienţilor, reprezintă interfaţa obiectului. Aceasta descrie complet setul mesajelor care pot fi
trimise spre obiectul respectiv. Un tip este un nume utilizat pentru a referi o anumită interfaţă.
Un obiect este de tipul T dacă el acceptă toate mesajele corespunzătoare operaţiilor definite în
interfaţa numită T.
Interfeţele sunt elemente fundamentale în sistemele OO. Obiectele sunt cunoscute doar
prin intermediul interfeţelor lor. O interfaţa nu dă nici un detaliu relativ la implementarea unui
obiect, iar obiecte distincte pot implementa diferit o aceeaşi cerere.
Interfeţe Java
Interfeţele Java reprezintă o colecţie de metode abstracte (doar semnătura, nu şi
implementarea acestora) şi de constante. Utilizarea unei interfeţe este justificată în cazurile în
care se doreşte ca o clasă să poată fi convertită în mai multe tipuri de bază între care nu există
relaţie de moştenire. Deoarece Java nu suportă moştenirea multiplă, interfeţele reprezintă o
variantă de rezolvare a acestei situaţii.
La fel ca şi o clasă, înainte de a putea utiliza o interfaţă ea trebuie declarată. Deoarece
conţine metode abstracte, interfaţa nu poate fi instanţiată. Cu toate acestea, o variabilă poate fi
declarată ca fiind de tipul interfeţei.
Modificatorul unei interfeţe poate fi public sau abstract. Având în vedere faptul că o
interfaţă este abstractă prin definiţie, utilizarea modificatorului abstract este redundantă. Spre
deosebire de o clasă, o interfaţă poate moşteni mai multe interfeţe. Moştenirea se face prin
clauza extends urmată de lista interfeţelor moştenite (lista_de_interfete) separate prin virgulă.
Prin derivare, o interfaţă moşteneşte de la interfaţa de bază atât metodele, cât şi constantele
acesteia.
Alergator.lg_pista;
În urma compilării unui fişier sursă Java care conţine o interfaţă, va rezulta un fişier cu
extensia .class ataşat interfeţei respective.
Aşa cum se poate observa, o clasă poate implementa mai multe interfeţe. Dacă o clasă
care implementează o interfaţă nu implementează toate metodele declarate în interfaţa
respectivă, va trebui să fie declarată abstractă, altfel se va semnala eroare la compilare. Dacă
o clasă A implementează o interfaţă X, un obiect al clasei A este de tip X, el putând să fie
atribuit unui alt obiect de tip X. Numele unei interfeţe poate fi utilizat la fel ca şi numele unui
clase, mai puţin la instanţierea prin operatorul new.
2
Interfeţe
interface Cititor {
public void citeste();
}
interface Scriitor{
public void scrie();
}
interface Scufundator{
int h=10;
public void scufundare();
}
3
Programare Java, Laborator 5
Folosind referinţa de interfaţă se pot apela metodele enumerate în interfaţă, iar ceea ce
se execută va fi codul corespunzător clasei "implementatoare", la care aparţine obiectul
concret indicat de referinţă.
Obiecte diferite, care pot recepţiona cereri identice, pot avea implementări diferite ale
operaţiilor care vor satisface cererile respective. Practic, prin cerere se identifică serviciul
4
Interfeţe
dorit, iar prin obiectul receptor se alege o anume implementare a acelui serviciu. Asocierea
dintre o operaţie solicitată şi obiectul care va pune la dispoziţie implementarea concretă a
operaţiei se numeşte legare (binding). În funcţie de momentul în care ea se realizează, legarea
poate fi:
• statică: asocierea se realizează la compilare;
• dinamică: asocierea se realizează la execuţie.
Temă
1. Se cere să se modeleze activitatea mai multor ghişee bancare. Sistemul este format
din următoarele entităţi, cu atributele corespunzătoare:
Banca
• denumire_banca (String)
• clienţi (colectie de obiecte de tip List<Client>)
Client
• nume (String)
• adresa (String)
• conturi (colectie de obiecte de tip Set<ContBancar>; un client trebuie să aibă cel
puţin un cont, dar nu mai mult de cinci conturi)
ContBancar
• numarCont (String)
• suma(float)
• moneda (String)
• data_deschiderii (Calendar)
• data_ultimei_operatiuni (Calendar)
5
Programare Java, Laborator 5
Pentru fiecare carte se reține id-ul cărții (număr unic de identificare), titlul cărții,
numele autorului şi anul apariției.
Să se creeze o clasă Carte cu variabile membre titlul, autorul şi anul apariție. Clasa va
dispune de constructor cu parametri, gettere si settere pentru accesarea variabilelor membre şi
va redefini metoda toString() astfel încât aceasta să returneze un String cu valorile variabilelor
membre separate prin virgule.
6
Lucrarea 6
Tratarea excepţiilor
Cuprins
Tratarea clasică a excepţiilor ....................................................................................................................................1
Mecanismul de emitere-captare a excepţiilor ...........................................................................................................3
Instrucţiunea throw....................................................................................................................................................4
Clauza throws............................................................................................................................................................5
Care tipuri de excepţie vor apărea într-o clauză throws?..........................................................................................5
Blocurile try-catch.....................................................................................................................................................5
Secvenţa finally ........................................................................................................................................................9
Excepţii predefinite ale limbajului Java .................................................................................................................10
Temă........................................................................................................................................................................11
Pe parcursul execuţiei unui program pot apărea evenimente deosebite care îi modifică
parcursul normal. Asemenea evenimente pot fi situaţii de eroare (de exemplu încercarea de a
accesa un element de tablou aflat dincolo de limitele tabloului) sau pur şi simplu situaţii care
necesită o altă abordare decât cea obişnuită (de exemplu, la parcurgerea secvenţială a unui
fişier de intrare, la un moment dat se atinge sfârşitul fişierului; acest eveniment, fără a fi o
eroare, va schimba cursul de până atunci al programului). Evenimentele de genul celor
amintite se mai numesc excepţii.
O excepţie este un obiect ce aparţine clasei predefinite Throwable sau unei clase
descendente din Throwable. Clasa Throwable este definită în pachetul java.lang. Limbajul
Java dispune, de fapt, de o întreagă ierarhie de clase predefinite pentru reprezentarea
excepţiilor. Programatorul poate utiliza clasele predefinite sau poate să-şi definească propriile
clase de excepţii, cu condiţia ca ele să descindă direct sau indirect din Throwable. Prin
convenţie, clasele definite de utilizatori pentru reprezentarea excepţiilor vor fi derivate din
clasa Exception.
Definirea unui tip de excepţie de către utilizator se justifică de obicei prin:
• necesitatea reţinerii de date suplimentare şi/sau mesaje mai detaliate despre excepţie;
• necesitatea ca dintr-o clasă mai largă de excepţii să fie captate doar o anumită parte..
class Tabel{
public static boolean fan_err = false;
public static int Increm(int[ ] tab,int indice,int val) {
if(indice>=0 && indice<tab.length){
tab[indice]+=val;
fan_err = false;
return tab[indice];
}
else{
fan_err = true;
Programare Java, Laborator 6
return 0;
}
}
class ClientTabel{
public static void main(String[ ] arg) {
int[ ] tab = new int[10];
//se completeaza tabloul cu valori
int suma=0,indice,val;
boolean gata=false;
do{
//se citesc de la tastatura un indice si o valoare
suma+=Tabel.Increm(tab,indice,val);
if(Tabel.fan_err) //a fost eroare...
else //merg mai departe
if(Tabel.indexOf(tab,val)<0) //valoarea val nu exista in tablou
else //valoarea val exista
//. . .
}while(!gata);
}
}
Metoda Tabel.Increm() se poate confrunta cu situaţia în care unul dintre parametrii săi
(indice) primeşte o valoare necorespunzătoare. În maniera clasică de tratare a erorilor se poate
adopta una dintre următoarele rezolvări:
În exemplul prezentat, metoda indexOf() aplică varianta 2), iar metoda Tabel.Increm()
— varianta 3). Cu privire la varianta 2) trebuie spus ca ea nu este întotdeauna uşor de aplicat.
Dacă pentru funcţia indexOf(), de exemplu, valoarea -1 ca indicator de eşec este satisfăcătoare
(este clar că un indice de tablou nu poate fi negativ în mod normal), în schimb, pentru Increm()
se pune întrebarea ce valoare a tipului int ar putea fi considerată ca „ieşită din comun“? Pentru
2
Tratarea excepţiilor
asemenea funcţii o soluţie ar putea fi aceea că, în loc de int, tipul returnat să fie o structură
compusă din rezultatul propriu-zis şi un fanion de eroare.
Pe de altă parte, chiar şi acolo unde este aplicabilă, opţiunea 2) implică necesitatea
testării de fiecare dată a rezultatului execuţiei funcţiilor respective. Acest lucru poate duce
uşor la dublarea dimensiunii codului. Alternativa 3) prezintă dezavantajul că apelantul
funcţiei în care a apărut eroarea poate să nu „observe“ că s-a întâmplat ceva. De exemplu,
multe funcţii din biblioteca standard C indică apariţia unei erori prin setarea variabilei globale
errno. Dar prea puţine programe ale utilizatorilor testează valoarea lui errno suficient de
sistematic încât să se obţină o tratare consistentă a erorilor.
class Tabel{
public static int Increm(int[ ] tab,int indice,int val) throws IndiceEronat{
if(indice>=0 && indice<tab.length){
tab[indice]+=val;
return tab[indice];
}
else //emitere exceptie
throw new IndiceEronat(tab.length, indice);
} //. . .
}
3
Programare Java, Laborator 6
class ClientTabel{
public static void main(String[ ] arg) {
int[ ] tab = new int[Integer.parseInt(arg[0])];
//se completeaza tabloul cu valori
int suma=0,indice,val;
boolean gata=false;
do{
//se citesc de la tastatura un indice si o valoare
try { //secventa sensibila la aparitia unei exceptii
suma+=Tabel.Increm(tab,indice,val);
}
catch(IndiceEronat e){ //tratare exceptie
System.out.println("Exceptie IndiceEronat: "+e);
}
//. . .
}while(!gata);
}
}
Limbajul Java pune la dispoziţie trei construcţii de bază pentru lucrul cu excepţii:
• instrucţiunea throw pentru emiterea excepţiilor;
• blocul catch pentru definirea secvenţei de captare şi tratare a unei excepţii; o
asemenea secvenţă se mai numeşte handler de excepţii;
• blocul try pentru delimitarea secvenţelor de cod sensibile la apariţia excepţiilor..
Instrucţiunea throw
Ca sintaxă, această instrucţiune este asemănătoare cu return:
throw expresie_exceptie;
4
Tratarea excepţiilor
Dacă instrucţiunea throw nu apare într-un bloc try, efectul ei este asemănător unui
return: se creează o excepţie care va fi „pasată“ spre apelantul funcţiei respective şi se
produce revenirea din funcţie; funcţia însă NU va transmite NICI UN rezultat chiar dacă tipul
returnat care apare în semnătura funcţiei nu este void. De exemplu, dacă funcţia
Tabel.Increm() execută instrucţiunea throw, ea nu va returna nici un rezultat de tip int.
Clauza throws
Această clauză se ataşează la antetul unei funcţii şi ea precizează tipurile de excepţii
care pot fi generate pe parcursul execuţiei funcţiei respective:
Dacă în lista de tipuri din clauza throws există cel puţin două tipuri, tip_exi şi tip_exj,
derivate dintr-o superclasă comună tip_exsup, limbajul permite înlocuirea celor două cu
tip_exsup. Este adevărat că, până la urmă, toate tipurile din lista throws derivă direct sau
indirect din Exception (se poate spune chiar din Throwable sau Object), deci, teoretic clauza
poate conţine doar această clasă. În practică este, însă, nerecomandat acest lucru, deoarece,
aşa cum tip_returnat reprezintă tipul rezultatului returnat de funcţie la o execuţie normală, tot
aşa, clauza throws oferă informaţii referitoare la situaţiile de excepţie care pot apărea în
funcţia respectivă. Dacă în listă se trece doar Exception, informaţia este foarte vagă pentru
cititorul programului.
Blocurile try-catch
Din punct de vedere sintactic un bloc try-catch are forma de mai jos:
5
Programare Java, Laborator 6
try {
//secventa obisnuita de operatii, care poate fi intrerupta de aparitia unei exceptii
}
catch(tip_ex1 e){
//tratare exceptie de tipul tip_ex1
}
catch(tip_ex2 e){
//tratare exceptie de tipul tip_ex2
}
//. . .
catch(tip_exn e){
//tratare exceptie de tipul tip_exn
}
finally {
//secventa optionala (despre finally vom vorbi intrun paragraf urmator)
}
//. . .(*)
Un bloc try este urmat de 0, 1 sau mai multe blocuri catch şi, opţional, de un bloc
finally. Vom presupune deocamdată că nu avem bloc finally. Modul de funcţionare al unei
asemenea construcţii este următorul:
• dacă în decursul desfăşurării secvenţei de operaţii din blocul try este emisă o excepţie,
fie direct (adică prin execuţia unui throw explicit), fie indirect (adică prin apelul unei
funcţii care emite excepţia), secvenţa se întrerupe şi se baleiază lista de blocuri catch
asociate pentru a-l detecta pe cel corespunzător tipului de excepţie emisă;
• dacă un astfel de bloc există, se va lansa în execuţie secvenţa de tratare respectivă.
• dacă această secvenţă nu trece printr-un return sau un throw, la terminarea ei execuţia
programului continuă cu linia care urmează după ultimul bloc catch sau, după caz,
finally ataşate blocului try curent (cea notata cu (*) în secvenţa de mai sus).
• tot de la acea linie se reia execuţia şi dacă secvenţa try a rulat fără să fi apărut vreo
excepţie.
Când spunem bloc catch corespunzător unei excepţii, aceasta înseamnă că tipul
specificat ca parametru după cuvântul catch este fie identic cu tipul excepţiei, fie este o
superclasă a tipului excepţiei. Dacă nu există nici un bloc catch corespunzător excepţiei emise,
aceasta va fi propulsată spre apelanţii funcţiei curente, căutându-se un eventual bloc try
înconjurător. Practic, un bloc catch poate fi asimilat cu o funcţie anonimă, cu un singur
parametru specificat imediat după cuvântul catch.
Apelul unei asemenea funcţii nu se face explicit, ci automat, dacă în secvenţa try
asociată apare o excepţie corespunzătoare. Un bloc catch se poate termina normal (adică prin
epuizarea instrucţiunilor care îl compun) sau printr-un throw care să emită o nouă excepţie
sau tot pe cea primită. În acest din urmă caz are loc retransmisia excepţiei.
Referitor la drumul parcurs de o excepţie din momentul emiterii sale şi până ajunge să
fie tratată, lucrurile stau astfel:
• stiva de apeluri se baleiază dinspre vârf spre bază în căutarea unui bloc try
înconjurător în raport cu instrucţiunea throw emitentă. Un bloc try este înconjurător
faţă de o instrucţiune throw dacă aceasta se găseşte chiar în interiorul acelui bloc try
sau dacă se află într-o funcţie apelată (direct sau indirect) din acel bloc try.
6
Tratarea excepţiilor
• dacă se găseşte un bloc try înconjurător, se caută între blocurile catch ataşate, unul ce
corespunde tipului excepţiei emise. Dacă există un astfel de bloc catch, acesta preia
excepţia. În caz contrar, excepţia este propagată mai departe, repetându-se procesul de
la pasul anterior. Dacă se ajunge cu căutarea până în funcţia main() şi nici aici nu
există un handler adecvat, excepţia este preluată de handler-ul de excepţii al maşinii
virtuale care determină abandonul programului, cu afişarea unui mesaj corespunzător.
• dacă excepţia este preluată de un bloc catch şi acesta nu o retransmite, excepţia
respectivă se consideră a fi tratată, indiferent de modul în care handler-ul operează
efectiv (în particular un handler poate avea corpul de instrucţiuni vid).
class OClasa {
public static void oFunctie( ) throws oExceptie {
//. . .
if(eroare) throw new oExceptie( );
}
public static void altaFunctie( ) throws oExceptie, altaExceptie {
oFunctie( );
}
public static void siIncaUna ( ) throws oExceptie,altaExeceptie{
//. . .
try{ // 1
altaFunctie( );
}
catch(oExceptie e){
if(poti_sa_rezolvi) fa_o( );
else throw e; // retransmisia exceptiei e
}
catch(altaExceptie e){
if(alta_eroare) throw new altaExceptie();
else tratare_normala( );
}
try{ // 2
//presupunem ca aici nu se apeleaza oFunctie( ) si nici altaFunctie( )
}
catch(Exception e){
//capteaza orice exceptie derivata din Exception aparuta in try 2
}
//instructiunea imediat urmatoare blocului trycatch 2
}//end siIncaUna()
public static void main(String[ ] arg) {
7
Programare Java, Laborator 6
//. . .
}
//. . .
}//end class OClasa
Presupunem că la un moment dat lanţul de apeluri este:
8
Tratarea excepţiilor
}
}
}
public static void main(String[ ] arg) {
//. . .
}
//. . .
}//end class OClasa
Secvenţa finally
Dacă este prezentă, se execută întotdeauna după ce s-a terminat secvenţa try sau
secvenţele catch din blocul try-catch curent. Practic, nu există posibilitatea de a determina
desfăşurarea execuţiei unui bloc try prevăzut cu ramura finally în sensul „şuntării“ acestei
secvenţe. Secvenţa finally reprezintă un mecanism prin care se forţează execuţia unei porţiuni
de cod indiferent dacă o excepţie a apărut sau nu. De obicei, ramura finally are rolul de a
„face curat“, în sensul de a elibera resurse de genul fişiere deschise accesate prin intermediul
unor variabile locale.
Primul lucru pe care îl constatăm la programul prezentat este absenţa ramurii catch.
Aceasta înseamnă că programatorul nu are intenţia să trateze excepţiile de tip IOException în
cadrul funcţiei Cautare(). Mai mult, acest program este un exemplu de utilizare a blocului try
nu neapărat pentru a rezolva situaţii de eroare, ci, datorită blocului finally, mai mult pentru a
determina o anumită înlănţuire a operaţiilor. De altfel, trebuie să ne obişnuim cu ideea că o
excepţie nu este întotdeauna un indiciu de eroare, ci, uneori, este pur şi simplu un semn că în
desfăşurarea programului a intervenit ceva deosebit care trebuie tratat altfel.
9
Programare Java, Laborator 6
În secvenţa de mai sus dacă fişierul nu ar fi putut fi deschis (de exemplu nume_fis nu
există) atunci referinţa flux_in ar fi rămas pe null. De aceea s-a prevăzut testul din blocul
finally. Presupunând că deschiderea fişierului ar fi mers cum trebuie, în continuare, indiferent
de modul în care se termină blocul try (pe unul dintre cele două return-uri sau prin apariţia
unei excepţii generate de funcţia readLine()) prezenţa ramurii finally asigură închiderea
fişierului înainte de părăsirea efectivă a funcţiei Cautare(). Ramura finally se mai poate utiliza
şi pentru a forţa execuţia unei porţiuni de cod când în try avem bucle ce conţin combinaţii de
break, continue şi return.
import java.io.*;
10
Tratarea excepţiilor
Temă
11
Lucrarea 7
Aplicațiile cu interfață grafică în Java pot să fie dezvoltate din cod (vezi exemplele din
curs) sau cu ajutorul unui designer grafic. Dezvoltarea aplicațiilor cu interfață grafică din cod
permite construirea de aplicații cu interfață dinamică şi oferă un control deplin asupra a ceea
ce se întâmplă şi cum se întâmplă în cod, dar este lentă. Utilizarea unui designerului grafic
crește viteza de dezvoltare a aplicației prin faptul că permite selectarea şi adăugarea
componentelor în interfața grafică prin click-uri, mutarea componentelor în alte poziţii prin
drag and drop, configurarea proprietăților componentelor într-o interfață grafică, într-un
Property editor. Designer-ul grafic generează codul din spatele acțiunilor realizate în modul
design. Window Builder Pro este un designer grafic care se instalează ca un plugin în Eclipse.
După ce a fost instalat WindowBuilder Pro se creează un proiect nou în Eclipse şi apoi se
creează un JFrame în acesta dând comanda File > New > Other > Window Builder > Swing
designer> JFrame (vezi figura 1).
JFrame-ul creat poate fi vizualizat în modul Design sau în modul Source. Comutarea între
cele două moduri se poate face folosind butoanele din partea stânga jos (vezi figura 2).
Adăugarea componentelor în interfață în modul design se face selectând componenta dorită
prin click în secţiunea Pallete (JLabel, JTextField, JButton, etc) şi apoi făcând click în
poziția dorită pe JFrame. Containerele de componente cum ar fi containerul JFrame-ului sau
JPanel-urile pot utiliza gestionari de componente (LayoutManageri) care decid unde
amplasează controalele în cadrul containerelor, ce dimensiuni le dau în funcție de ordinea
Programare Java, Lucrarea 6
Codul generat pentru JFrame-ul creat, fără a face nici o modificare în designer-ul
grafic este prezentat mai jos:
package exemplu;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
2
Interfeţe grafice
/**
* Create the frame.
*/
public MyTestFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
}
}
S-a creat clasa MyTestFrame care extinde JFrame, prin urmare are acces la toate
proprietățile pe care aceasta le expune. În constructorul clasei se stabilește acțiunea care se va
întâmpla la rulare când se va face click pe X-ul din colţul din dreapta sus şi anume închiderea
aplicaţiei. Metoda setBounds() stabilește locația ferestrei (primii doi parametri) şi
dimensiunea acesteia (ultimii doi parametri). Se instanţiază JPanel-ul numit contentPane. Se
seteză o bordură goală de 5 pixeli faţă de marginile de sus, stânga, jos şi dreapta. Se setează
pentru JPanel gestionarul de componente BorderLayout cu golurile specificate ca şi
parametru între componente pe orizontală şi pe verticală. Se setează JPanel-ul creat ca şi
containăr al ferestrei.
3
Programare Java, Lucrarea 6
Tema
1. Realizați o aplicație cu interfață grafică de tip calculator, similară cu cea din figura 3.
Situațiile de excepție care pot să apară vor fi tratate prin afișarea de mesaje corespunzătoare
(de exemplu: Împărțire la 0, valoare lipsă, valoare necorespunzătoare - dacă în loc de cifre se
introduc litere). După finalizarea aplicației se va crea fișierul jar rulabil, cu ajutorul comenzii
File > Export > Java > Runnable jar file. Se alege pentru opțiunea Launch configuration
clasa main-ului şi se specifica prin Export destination locaţia şi denumirea fișierului jar care
va fi creat. Fișierul jar creat se rulează prin dublu click.
Figura 3 - Calculator
Indicații de rezolvare:
Creați un proiect nou în Eclipse şi în interiorul acestui proiect un JFrame. Deschideți
JFrame-ul în modul Design. Setaţi pentru containerul JFame-ului LayoutManager
AbsoluteLayout (vezi indicaţiile de mai sus). În continuare puteți amplasa în containerul
JFrame-ului componente în ce poziţii doriţi si puteți să le daţi ce dimensiune doriți.
Calculatorul are în containerul JFrame-ului 3 tipuri de componente: JLabel, JTextField şi
JButton. Pentru toate componentele designer-ul grafic creează variabile membre private în
clasa JFrame-ului. Fiecare componentă trebuie selectată si modificate din secțiunea
Properties proprietățile acesteia. Pentru fiecare componentă se recomandă modificarea
proprietății Variable name prin introducerea unui nume sugestiv. Primele 3 litere ar trebui sa
indice tipul de componenta (lbl – label, btn – buton, txt- caseta de text) şi apoi ar trebui
introdusă o denumire care să indice rolul componentei. Câteva exemple de denumiri
recomandate sunt următoarele: lblOperand, txtOperand1, btnAdunare. Cu excepția casetelor
de text, pentru celelalte componente trebuie editată proprietatea text, care reprezintă textul
afișat de componentă.
După construirea interfeței grafice urmează scrierea codului care se va executa când se va
face click pe butoane. Pentru aceasta se face dublu click pe buton în modul Design. Se va
comuta pe modul Source, cursorul fiind poziționat pe metoda actionPerformed(), metodă care
se va executa la rulare atunci când se face click pe buton. Designer-ul grafic generează câte o
clasă anonimă pentru click-ul pe fiecare buton. Extragerea unei valori dintr-o caseta de text
se face cu ajutorul metodei getText().
4
Interfeţe grafice
Figura 4 - formaţii
Numele unei formaţii se introduce în caseta de text şi apoi se apasa tasta enter, acţiune
care determină adăugarea denumirii formaţiei în caseta JList de dedesupt. Acţionarea
butonului de ştergere determină ştergerea formaţiilor selectate în caseta JList (ştergere
multiplă).
Indicaţii de rezolvare:
3. Să se realizeze o aplicaţie care permite introducerea unor filme lansate în ultimii 5 ani
şi afişarea acestora în format tabelar. Aplicaţia va avea o interfaţă grafică similara cu cea din
figura 5:
Figura 5 - filme
5
Programare Java, Lucrarea 6
Indicaţii de rezolvare:
6
Lucrarea 8
• săgeţile vor permite navigarea printre înregistrările din tabelul persoane (poziţionarea
pe prima înregistrare, pe înregistrarea precedentă, pe înregistrarea următoare, respectiv
pe ultima înregistrare). Dacă suntem pe prima înregistrare, butoanele de navigare la
stânga se vor dezactiva. În mod simetric se va proceda cu butoanele de navigare la
dreapta.
• caseta de text din JToolBar, va afişa numărul înregistrării curente şi numărul total de
înregistrări
• ştergerea se va realiza doar după un mesaj suplimentar de confirmare (vezi figura 8.3)
â
Fig. 8.4 – Căutarea unei persoane
2
Lucrarea 9
Apăsarea butonului Open XML, va determina afișarea unei ferestre de tip JFileChooser,
precum cea din Figura 2. Fereastra va fi configurată astfel încât să nu permită deschiderea
decât a documentelor XML şi la apăsarea butonului Open XML va fi afișat implicit conținutul
folder-ului proiectului. Se vor folosi ca fișiere de test fișierele optionale.xml (din slide-ul 3 al
cursului) şi studenti.xml (din slide-ul 17 al cursului).
În fereastra principală, în colțul din dreapta sus, va fi afișată într-o caseta de tip JLabel,
ora citită din sistem în formatul oo:mm:ss. Afișarea va fi de tipul unui ceas, se vor vedea
secundele cum se schimbă, apoi minutele cum se schimbă etc. Pentru aceasta se va folosi un
Timer configurat să genereze câte o întrerupere la fiecare secundă. În rutina de tratare a
întreruperii se citeşte timpul din sistem şi se actualizează în caseta JLabel.
2
Lucrarea 10
Java 8
Fire de execuție
Indicații de rezolvare: Se pot realiza simultan 4 operații: pot intra 3 mașini şi poate ieşi o
mașină în / din parcare. Fiecare operație se va realiza într-un fir de execuție. Se va utiliza
modelul Producator - Consumator, discutat la curs. Producătorul reprezintă o intrare în
parcare, iar consumatorul o ieșire din parcare. Resursa comună este reprezentată de un obiect
de tip Parcare. Așadar se creează clasa Parcare, cu variabile membre număr total de locuri
şi număr de locuri ocupate, variabile care se inițializează prin constructor. Clasa va avea o
metodă sincronizată pentru simularea intrării unei maşini, care acceptă ca şi parametru de
intrare numărul intrării. Cat timp nu sunt locuri disponibile se așteaptă eliberarea unui loc.
Când sunt locuri disponibile, mașina intră în parcare şi creşte numărul locurilor ocupate. Se
afișează un mesaj corespunzător. De asemenea va exista o metodă sincronizata pentru
simularea ieşirii unei maşini, care decrementează numărul de locuri ocupate şi afișează un
mesaj corespunzător. Toate schimbările de număr de locuri ocupate sunt însoțite de notificări
pe care firele de execuţie le transmit. Se creează clasa Intrare care reprezintă producătorul şi
clasa Ieşire care reprezintă consumatorul. Aceste clase corespund firelor de execuţie deci
extind clasa Thread si redefinesc metoda run. Firul de execuție al main-ului creează cele 4
fire de execuție şi le trece în starea gata de rulare.