Curs practic de Java

Cristian Fr˘sinaru a

Cuprins
1 Introducere ˆ Java ın 1.1 Ce este Java ? . . . . . . . . . . . . . . . . . . 1.1.1 Limbajul de programare Java . . . . . 1.1.2 Platforme de lucru Java . . . . . . . . 1.1.3 Java: un limbaj compilat ¸i interpretat s 1.2 Primul program . . . . . . . . . . . . . . . . . 1.3 Structura lexical˘ a limbajului Java . . . . . . a 1.3.1 Setul de caractere . . . . . . . . . . . . 1.3.2 Cuvinte cheie . . . . . . . . . . . . . . 1.3.3 Identificatori . . . . . . . . . . . . . . . 1.3.4 Literali . . . . . . . . . . . . . . . . . . 1.3.5 Separatori . . . . . . . . . . . . . . . . 1.3.6 Operatori . . . . . . . . . . . . . . . . 1.3.7 Comentarii . . . . . . . . . . . . . . . 1.4 Tipuri de date ¸i variabile . . . . . . . . . . . s 1.4.1 Tipuri de date . . . . . . . . . . . . . . 1.4.2 Variabile . . . . . . . . . . . . . . . . . 1.5 Controlul executiei . . . . . . . . . . . . . . . ¸ 1.5.1 Instructiuni de decizie . . . . . . . . . ¸ 1.5.2 Instructiuni de salt . . . . . . . . . . . ¸ 1.5.3 Instructiuni pentru tratarea exceptiilor ¸ ¸ 1.5.4 Alte instructiuni . . . . . . . . . . . . ¸ 1.6 Vectori . . . . . . . . . . . . . . . . . . . . . . 1.6.1 Crearea unui vector . . . . . . . . . . . 1.6.2 Tablouri multidimensionale . . . . . . 1.6.3 Dimensiunea unui vector . . . . . . . . 1.6.4 Copierea vectorilor . . . . . . . . . . . 1 11 11 11 12 13 14 16 16 16 17 17 19 19 20 21 21 22 24 24 25 26 26 26 26 28 28 29

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

2 1.6.5 Sortarea vectorilor - clasa Arrays . . . . . . 1.6.6 Vectori cu dimensiune variabil˘ ¸i eterogeni as Siruri de caractere . . . . . . . . . . . . . . . . . . ¸ Folosirea argumentelor de la linia de comand˘ . . . a 1.8.1 Transmiterea argumentelor . . . . . . . . . . 1.8.2 Primirea argumentelor . . . . . . . . . . . . 1.8.3 Argumente numerice . . . . . . . . . . . . . . . . . . . . . . . . . . .

CUPRINS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 30 30 31 31 32 34 35 35 35 37 38 39 39 40 41 42 46 49 50 50 52 53 56 57 58 59 59 61 62 63 64 64 66 66 67 67

1.7 1.8

2 Obiecte ¸i clase s 2.1 Ciclul de viat˘ al unui obiect . . . . . . . . . . . . . ¸a 2.1.1 Crearea obiectelor . . . . . . . . . . . . . . . 2.1.2 Folosirea obiectelor . . . . . . . . . . . . . . 2.1.3 Distrugerea obiectelor . . . . . . . . . . . . 2.2 Crearea claselor . . . . . . . . . . . . . . . . . . . . 2.2.1 Declararea claselor . . . . . . . . . . . . . . 2.2.2 Extinderea claselor . . . . . . . . . . . . . . 2.2.3 Corpul unei clase . . . . . . . . . . . . . . . 2.2.4 Constructorii unei clase . . . . . . . . . . . . 2.2.5 Declararea variabilelor . . . . . . . . . . . . 2.2.6 this ¸i super . . . . . . . . . . . . . . . . . . s 2.3 Implementarea metodelor . . . . . . . . . . . . . . 2.3.1 Declararea metodelor . . . . . . . . . . . . . 2.3.2 Tipul returnat de o metod˘ . . . . . . . . . a 2.3.3 Trimiterea parametrilor c˘tre o metod˘ . . . a a 2.3.4 Metode cu num˘r variabil de argumente . . a 2.3.5 Supraˆ arcarea ¸i supradefinirea metodelor ınc˘ s 2.4 Modificatori de acces . . . . . . . . . . . . . . . . . 2.5 Membri de instant˘ ¸i membri de clas˘ . . . . . . . ¸a s a 2.5.1 Variabile de instant˘ ¸i de clas˘ . . . . . . . ¸a s a 2.5.2 Metode de instant˘ ¸i de clas˘ . . . . . . . . ¸a s a 2.5.3 Utilitatea membrilor de clas˘ . . . . . . . . a 2.5.4 Blocuri statice de initializare . . . . . . . . . ¸ 2.6 Clase imbricate . . . . . . . . . . . . . . . . . . . . 2.6.1 Definirea claselor imbricate . . . . . . . . . . 2.6.2 Clase interne . . . . . . . . . . . . . . . . . 2.6.3 Identificare claselor imbricate . . . . . . . . 2.6.4 Clase anonime . . . . . . . . . . . . . . . . . 2.7 Clase ¸i metode abstracte . . . . . . . . . . . . . . s

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

CUPRINS 2.7.1 Declararea unei clase abstracte 2.7.2 Metode abstracte . . . . . . . . 2.8 Clasa Object . . . . . . . . . . . . . . 2.8.1 Orice clas˘ are o superclas˘ . . a a 2.8.2 Clasa Object . . . . . . . . . . 2.9 Conversii automate ˆ ıntre tipuri . . . . 2.10 Tipul de date enumerare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3 68 68 71 71 71 74 75 77 77 78 82 85 85 87 89 90 91 92 95 95 95 96 97 98 99 99 100 101 103 105 107 108 109 110 110 111

3 Exceptii ¸ 3.1 Ce sunt exceptiile ? . . . . . . . . . . . . ¸ 3.2 ”Prinderea” ¸i tratarea exceptiilor . . . . s ¸ 3.3 ”Aruncarea” exceptiilor . . . . . . . . . . ¸ 3.4 Avantajele trat˘rii exceptiilor . . . . . . a ¸ 3.4.1 Separarea codului pentru tratarea 3.4.2 Propagarea erorilor . . . . . . . . 3.4.3 Gruparea erorilor dup˘ tipul lor . a 3.5 Ierarhia claselor ce descriu exceptii . . . ¸ 3.6 Exceptii la executie . . . . . . . . . . . . ¸ ¸ 3.7 Crearea propriilor exceptii . . . . . . . . ¸

. . . . . . . . . . . . . . . . . . . . erorilor . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

4 Intr˘ri ¸i ie¸iri a s s 4.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Ce sunt fluxurile? . . . . . . . . . . . . . . . . . 4.1.2 Clasificarea fluxurilor . . . . . . . . . . . . . . . 4.1.3 Ierarhia claselor pentru lucrul cu fluxuri . . . . 4.1.4 Metode comune fluxurilor . . . . . . . . . . . . 4.2 Folosirea fluxurilor . . . . . . . . . . . . . . . . . . . . 4.2.1 Fluxuri primitive . . . . . . . . . . . . . . . . . 4.2.2 Fluxuri de procesare . . . . . . . . . . . . . . . 4.2.3 Crearea unui flux . . . . . . . . . . . . . . . . . 4.2.4 Fluxuri pentru lucrul cu fi¸iere . . . . . . . . . . s 4.2.5 Citirea ¸i scrierea cu buffer . . . . . . . . . . . . s 4.2.6 Concatenarea fluxurilor . . . . . . . . . . . . . . 4.2.7 Fluxuri pentru filtrarea datelor . . . . . . . . . 4.2.8 Clasele DataInputStream ¸i DataOutputStream s 4.3 Intr˘ri ¸i ie¸iri formatate . . . . . . . . . . . . . . . . . a s s 4.3.1 Intr˘ri formatate . . . . . . . . . . . . . . . . . a 4.3.2 Ie¸iri formatate . . . . . . . . . . . . . . . . . . s

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

4 4.4

CUPRINS Fluxuri standard de intrare ¸i ie¸ire . . . . . . . . . . . . . s s 4.4.1 Afisarea informatiilor pe ecran . . . . . . . . . . . . ¸ 4.4.2 Citirea datelor de la tastatur˘ . . . . . . . . . . . . a 4.4.3 Redirectarea fluxurilor standard . . . . . . . . . . . 4.4.4 Analiza lexical˘ pe fluxuri (clasa StreamTokenizer) a Clasa RandomAccesFile (fi¸iere cu acces direct) . . . . . . s Clasa File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 112 112 113 115 117 119

4.5 4.6

5 Interfete ¸ 5.1 Introducere . . . . . . . . . . . . . . . . . . 5.1.1 Ce este o interfat˘ ? . . . . . . . . . ¸a 5.2 Folosirea interfetelor . . . . . . . . . . . . . ¸ 5.2.1 Definirea unei interfete . . . . . . . . ¸ 5.2.2 Implementarea unei interfete . . . . . ¸ 5.2.3 Exemplu: implementarea unei stive . 5.3 Interfete ¸i clase abstracte . . . . . . . . . . ¸ s 5.4 Mo¸tenire multipl˘ prin interfete . . . . . . s a ¸ 5.5 Utilitatea interfetelor . . . . . . . . . . . . . ¸ 5.5.1 Crearea grupurilor de constante . . . 5.5.2 Transmiterea metodelor ca parametri 5.6 Interfata FilenameFilter . . . . . . . . . . ¸ 5.6.1 Folosirea claselor anonime . . . . . . 5.7 Compararea obiectelor . . . . . . . . . . . . 5.7.1 Interfata Comparable . . . . . . . . . ¸ 5.7.2 Interfata Comparator . . . . . . . . . ¸ 5.8 Adaptori . . . . . . . . . . . . . . . . . . . . 6 Organizarea claselor 6.1 Pachete . . . . . . . . . . . . . . . . . . 6.1.1 Pachetele standard (J2SDK) . . . 6.1.2 Folosirea membrilor unui pachet . 6.1.3 Importul unei clase sau interfete . ¸ 6.1.4 Importul la cerere dintr-un pachet 6.1.5 Importul static . . . . . . . . . . 6.1.6 Crearea unui pachet . . . . . . . 6.1.7 Denumirea unui pachet . . . . . . 6.2 Organizarea fi¸ierelor . . . . . . . . . . . s 6.2.1 Organizarea fi¸ierelor surs˘ . . . . s a

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

121 . 121 . 121 . 122 . 122 . 123 . 124 . 129 . 130 . 132 . 132 . 133 . 134 . 137 . 138 . 139 . 141 . 142 145 145 145 146 147 148 149 150 151 152 152

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

CUPRINS 6.2.2 Organizarea unit˘¸ilor de compilare (.class) at 6.2.3 Necesitatea organiz˘rii fi¸ierelor . . . . . . . . a s 6.2.4 Setarea c˘ii de c˘utare (CLASSPATH) . . . . a a Arhive JAR . . . . . . . . . . . . . . . . . . . . . . . 6.3.1 Folosirea utilitarului jar . . . . . . . . . . . . 6.3.2 Executarea aplicatiilor arhivate . . . . . . . . ¸ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5 154 155 156 157 158 159

6.3

7 Colectii ¸ 7.1 Introducere . . . . . . . . . . 7.2 Interfete ce descriu colectii . . ¸ ¸ 7.3 Implement˘ri ale colectiilor . . a ¸ 7.4 Folosirea eficient˘ a colectiilor a ¸ 7.5 Algoritmi polimorfici . . . . . 7.6 Tipuri generice . . . . . . . . 7.7 Iteratori ¸i enumer˘ri . . . . . s a

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

161 . 161 . 162 . 166 . 168 . 170 . 171 . 172 177 177 179 180 180 181 183 183 184 187 188 193 194 196

8 Serializarea obiectelor 8.1 Folosirea serializ˘rii . . . . . . . . . . . . . . . a 8.1.1 Serializarea tipurilor primitive . . . . . 8.1.2 Serializarea obiectelor . . . . . . . . . . 8.1.3 Clasa ObjectOutputStream . . . . . . 8.1.4 Clasa ObjectInputStream . . . . . . . 8.2 Obiecte serializabile . . . . . . . . . . . . . . . 8.2.1 Implementarea interfetei Serializable . ¸ 8.2.2 Controlul serializ˘rii . . . . . . . . . . a 8.3 Personalizarea serializ˘rii obiectelor . . . . . . a 8.3.1 Controlul versiunilor claselor . . . . . . 8.3.2 Securizarea datelor . . . . . . . . . . . 8.3.3 Implementarea interfetei Externalizable ¸ 8.4 Clonarea obiectelor . . . . . . . . . . . . . . . 9 Interfata grafic˘ cu utilizatorul ¸ a 9.1 Introducere . . . . . . . . . . . . . . . . . . . 9.2 Modelul AWT . . . . . . . . . . . . . . . . . . 9.2.1 Componentele AWT . . . . . . . . . . 9.2.2 Suprafete de afi¸are (Clasa Container) ¸ s 9.3 Gestionarea pozition˘rii . . . . . . . . . . . . ¸ a 9.3.1 Folosirea gestionarilor de pozitionare . ¸

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

199 . 199 . 200 . 202 . 204 . 206 . 207

6 9.3.2 Gestionarul FlowLayout . . . . . . . . . . . 9.3.3 Gestionarul BorderLayout . . . . . . . . . . 9.3.4 Gestionarul GridLayout . . . . . . . . . . . 9.3.5 Gestionarul CardLayout . . . . . . . . . . . 9.3.6 Gestionarul GridBagLayout . . . . . . . . . 9.3.7 Gruparea componentelor (Clasa Panel) . . . Tratarea evenimentelor . . . . . . . . . . . . . . . . 9.4.1 Exemplu de tratare a evenimentelor . . . . . 9.4.2 Tipuri de evenimente . . . . . . . . . . . . . 9.4.3 Folosirea adaptorilor ¸i a claselor anonime . s Folosirea ferestrelor . . . . . . . . . . . . . . . . . . 9.5.1 Clasa Window . . . . . . . . . . . . . . . . . 9.5.2 Clasa Frame . . . . . . . . . . . . . . . . . . 9.5.3 Clasa Dialog . . . . . . . . . . . . . . . . . . 9.5.4 Clasa FileDialog . . . . . . . . . . . . . . . Folosirea meniurilor . . . . . . . . . . . . . . . . . . 9.6.1 Ierarhia claselor ce descriu meniuri . . . . . 9.6.2 Tratarea evenimentelor generate de meniuri 9.6.3 Meniuri de context (popup) . . . . . . . . . 9.6.4 Acceleratori (Clasa MenuShortcut) . . . . . Folosirea componentelor AWT . . . . . . . . . . . . 9.7.1 Clasa Label . . . . . . . . . . . . . . . . . . 9.7.2 Clasa Button . . . . . . . . . . . . . . . . . 9.7.3 Clasa Checkbox . . . . . . . . . . . . . . . . 9.7.4 Clasa CheckboxGroup . . . . . . . . . . . . 9.7.5 Clasa Choice . . . . . . . . . . . . . . . . . 9.7.6 Clasa List . . . . . . . . . . . . . . . . . . . 9.7.7 Clasa ScrollBar . . . . . . . . . . . . . . . . 9.7.8 Clasa ScrollPane . . . . . . . . . . . . . . . 9.7.9 Clasa TextField . . . . . . . . . . . . . . . . 9.7.10 Clasa TextArea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

CUPRINS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 210 211 212 214 218 219 221 224 227 232 232 233 236 239 242 243 246 247 250 250 251 252 253 255 257 259 261 262 263 265

9.4

9.5

9.6

9.7

10 Desenarea 10.1 Conceptul de desenare . . . . . . . . . . . . 10.1.1 Metoda paint . . . . . . . . . . . . . 10.1.2 Suprafete de desenare - clasa Canvas ¸ 10.2 Contextul grafic de desenare . . . . . . . . . 10.2.1 Propriet˘¸ile contextului grafic . . . . at

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

269 . 269 . 270 . 271 . 274 . 275

CUPRINS 10.2.2 Primitive grafice . . . . . . . . . . Folosirea fonturilor . . . . . . . . . . . . . 10.3.1 Clasa Font . . . . . . . . . . . . . . 10.3.2 Clasa FontMetrics . . . . . . . . . . Folosirea culorilor . . . . . . . . . . . . . . Folosirea imaginilor . . . . . . . . . . . . . 10.5.1 Afi¸area imaginilor . . . . . . . . . s 10.5.2 Monitorizarea ˆ arc˘rii imaginilor ınc˘ a 10.5.3 Mecanismul de ”double-buffering” . 10.5.4 Salvarea desenelor ˆ format JPEG ın 10.5.5 Crearea imaginilor ˆ memorie . . ın Tip˘rirea . . . . . . . . . . . . . . . . . . . a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7 275 276 277 279 282 286 287 289 291 291 292 293 299 299 299 300 301 304 305 307 310 310 314 316 316 316 319 324 329 332 335 336 336 338 340

10.3

10.4 10.5

10.6

11 Swing 11.1 Introducere . . . . . . . . . . . . . . . . . 11.1.1 JFC . . . . . . . . . . . . . . . . . 11.1.2 Swing API . . . . . . . . . . . . . . 11.1.3 Asem˘n˘ri ¸i deosebiri cu AWT . . a a s 11.2 Folosirea ferestrelor . . . . . . . . . . . . . 11.2.1 Ferestre interne . . . . . . . . . . . 11.3 Clasa JComponent . . . . . . . . . . . . . 11.4 Arhitectura modelului Swing . . . . . . . . 11.5 Folosirea modelelor . . . . . . . . . . . . . 11.5.1 Tratarea evenimentelor . . . . . . . 11.6 Folosirea componentelor . . . . . . . . . . 11.6.1 Componente atomice . . . . . . . . 11.6.2 Componente pentru editare de text 11.6.3 Componente pentru selectarea unor 11.6.4 Tabele . . . . . . . . . . . . . . . . 11.6.5 Arbori . . . . . . . . . . . . . . . . 11.6.6 Containere . . . . . . . . . . . . . . 11.6.7 Dialoguri . . . . . . . . . . . . . . 11.7 Desenarea . . . . . . . . . . . . . . . . . . 11.7.1 Metode specifice . . . . . . . . . . 11.7.2 Consideratii generale . . . . . . . . ¸ 11.8 Look and Feel . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . elemente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . .

8 12 Fire de executie ¸ 12.1 Introducere . . . . . . . . . . . . . . . . . 12.2 Crearea unui fir de executie . . . . . . . . ¸ 12.2.1 Extinderea clasei Thread . . . . . . 12.2.2 Implementarea interfetei Runnable ¸ 12.3 Ciclul de viat˘ al unui fir de executie . . . ¸a ¸ 12.3.1 Terminarea unui fir de executie . . ¸ 12.3.2 Fire de executie de tip ”daemon” . ¸ 12.3.3 Stabilirea priorit˘¸ilor de executie . at ¸ 12.3.4 Sincronizarea firelor de executie . . ¸ 12.3.5 Scenariul produc˘tor / consumator a 12.3.6 Monitoare . . . . . . . . . . . . . . 12.3.7 Semafoare . . . . . . . . . . . . . . 12.3.8 Probleme legate de sincronizare . . 12.4 Gruparea firelor de executie . . . . . . . . ¸ 12.5 Comunicarea prin fluxuri de tip ”pipe” . . 12.6 Clasele Timer ¸i TimerTask . . . . . . . . s

CUPRINS 343 . 343 . 344 . 345 . 347 . 352 . 355 . 357 . 358 . 362 . 362 . 367 . 369 . 371 . 373 . 376 . 378 383 . 383 . 385 . 387 . 388 . 393 . 397 401 . 401 . 402 . 404 . 406 . 408 . 410 . 412 . 416 . 420 . 421 . 421

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

13 Programare ˆ retea ın ¸ 13.1 Introducere . . . . . . . . . . . . . . . . . . 13.2 Lucrul cu URL-uri . . . . . . . . . . . . . . 13.3 Socket-uri . . . . . . . . . . . . . . . . . . . 13.4 Comunicarea prin conexiuni . . . . . . . . . 13.5 Comunicarea prin datagrame . . . . . . . . . 13.6 Trimiterea de mesaje c˘tre mai multi clienti a ¸ ¸ 14 Appleturi 14.1 Introducere . . . . . . . . . . . . . . . 14.2 Crearea unui applet simplu . . . . . . . 14.3 Ciclul de viat˘ al unui applet . . . . . ¸a 14.4 Interfata grafic˘ cu utilizatorul . . . . . ¸ a 14.5 Definirea ¸i folosirea parametrilor . . . s 14.6 Tag-ul APPLET . . . . . . . . . . . . 14.7 Folosirea firelor de executie ˆ appleturi ¸ ın 14.8 Alte metode oferite de clasa Applet . . 14.9 Arhivarea appleturilor . . . . . . . . . 14.10Restrictii de securitate . . . . . . . . . ¸ 14.11Appleturi care sunt ¸i aplicatii . . . . . s ¸

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. 442 . . . at 15. . . . . .1 Interfata DatabaseMetaData . . . .2. . . .1 Inc˘rcarea claselor ˆ memorie . .2 Conectarea la o baz˘ de date . . . . . . .CUPRINS 15 Lucrul cu baze de date 15. . . . 442 . . . . . . .2. . . . .1 Generalit˘¸i despre baze de date . . . . . . . .3. . . . . . . . . . . . . . . . . .2. . 423 . 15. . . 430 . . . . . . . . 434 . . . . . .1 Introducere . . . . . . . .2 Interfata PreparedStatement . . .4.3. .3 Efectuarea de secvente SQL . . . . . 15. . 15. . . . . . . .3. . . a ın 16. . . . . . . . . . . . . . . . . . 460 . . . . . 440 . . ¸ 16 Lucrul dinamic cu clase 16. . . ¸ 15. . . . . . . . . 15. .3 Tipuri de drivere . . . . 432 . . . . 445 . . . . .1 Examinarea claselor ¸i interfetelor s ¸ 16. 426 . ¸ 15.3. 438 . . . . . . . .3 Lucrul dinamic cu vectori . . .1. . . 423 . . . . . . . 9 423 . . 452 . . . . . . . 424 . . . . . . . . . . ¸ 15. . . . . . . . . . . . . . . . 456 . . . 453 . . . . 428 . .3.3 Interfata CallableStatement . . . . . . . .2. . . . .3. . . . . . . .6 Exemplu simplu .1. . . a 16. . . . .2. . . . . . . . . . 443 445 . . . . . . . . . . .4 Lucrul cu meta-date . . . . . . . . . . . . . . . . . . 16. . . . . . . . . . ¸ 15. . . 15. ¸ 15. . . . . . . . .2. . . . . .2 Specificarea unei baze de date . . . . . . . . . . . 437 .4. . .4 Realizarea unei conexiuni . . . . . . . . 431 . . . . . .2 JDBC . . . . . a 15. . . .5 Interfata ResultSet . . . . . 15. . . . . .1 Interfata Statement . . . . . . . 425 . . . . . . . 15. ¸ 15. . . . . . . . . . . . . . . . . . .2 Manipularea obiectelor .2. . . . . . . 427 . 438 .4 Obtinerea ¸i prelucrarea rezultatelor ¸ s 15. . . . . . . . . . . .1 Inregistrarea unui driver . .2 Interfata ResultSetMetaData . 15. . . . .2 Mecanismul reflect˘rii .

10 CUPRINS .

fire de executie. s˘ amın a intim caracteristicile sale principale. ¸ • Simplitate .1. Denumit˘ initial OAK. mo¸tenirea multipl˘ a ınc˘ s a ¸i toate ”facilit˘¸ile” ce pot provoca scrierea unui cod confuz. etc. s at • U¸urint˘ ˆ crearea de aplicatii complexe ce folosesc programarea ˆ s ¸a ın ¸ ın retea. ¸ ¸ ¸a a • Robustete . ¸ 1.elimin˘ sursele frecvente de erori ce apar ˆ programare ¸ a ın prin renuntarea la pointeri. baze de date.1 Limbajul de programare Java Inainte de a prezenta ˆ detaliu aspectele tehnice ale limbajului Java. indiferent de domeniu sau de complexitatea lor.1 Ce este Java ? Java este o tehnologie inovatoare lansat˘ de compania Sun Microsystems ˆ a ın 1995. interfat˘ grafic˘. robustete ¸i nu ˆ ultimul rˆnd portabilitate. impunˆndu-se prin calit˘¸i deosebite cum ar fi sima at plitate.Capitolul 1 Introducere ˆ Java ın 1. care a avut un impact remarcabil asupra ˆ ıntregii comunit˘¸i a dezat voltatorilor de software. ¸ s ın a a ¸ tehnologia Java este format˘ dintr-un limbaj de programare de nivel ˆ a ınalt pe baza c˘ruia sunt construite o serie de platforme destinate implement˘rii de a a aplicatii pentru toate segmentele industriei software. administrarea automat˘ a memoriei ¸i elim¸ a s 11 .elimin˘ supraˆ arcarea operatorilor. care l-au transformat ˆ ıntr-un interval de timp atˆt de scurt ˆ a ıntr-una din cele mai pupulare optiuni pentru dezvoltarea ¸ de aplicatii.

comportamentul unei aplicatii Java nu a ¸ depinde de arhitectura fizic˘ a ma¸inii pe care ruleaz˘. lucru care aduce economii substantiale firmelor ¸ dezvoltatoare de aplicatii. Mac OS. ¸a • Neutralitate arhitectural˘ . C++ la Java a s f˘cˆndu-se foarte u¸or. etc. astfel ˆ at a ¸a a ¸ ıncˆ viteza de lucru putin mai sc˘zut˘ nu va fi un impediment ˆ dezvoltarea ¸ a a ın de aplicatii oricˆt de complexe.elimin˘ complet stilul de programare a procedural. Aceste tehnologii a au fost grupate ˆ a¸a numitele platforme de lucru. animatie. a s a • Portabililtate . ce reprezint˘ seturi de ın s a libr˘rii scrise ˆ limbajul Java.1.este un limbaj de programare foarte sigur. aceea¸i aplicatie rulˆnd f˘r˘ nici o modificare ¸i f˘r˘ a necesita res ¸ a aa s aa compilarea ei pe sisteme de operare diferite cum ar fi Windows. aceasta fiind solutia eficient˘ pentru s ¸ a obtinerea portabilit˘¸ii. etc. INTRODUCERE ˆ JAVA IN inarea pierderilor de memorie printr-o procedur˘ de colectare a obiectelor a care nu mai sunt referite. . etc. precum ¸i diverse programe utilitare. inclusiv grafic˘ 3D. furnizˆnd a mecanisme stricte de securitate a programelor concretizate prin: verificarea dinamic˘ a codului pentru detectarea secventelor periculoase. ¸ a a ¸ • Este modelat dup˘ C ¸i C++. a ın • Complet orientat pe obiecte . Linux. a a s 1. ¸ at • Performant˘ .de¸i mai lent decˆt limbajele de programare care genereaz˘ ¸a s a a executabile native pentru o anumit˘ platform˘ de lucru.12 CAPITOLUL 1. ¸ • Este compilat ¸i interpretat. a ¸ impunerea unor reguli stricte pentru rularea proceselor la distant˘. compilatorul a a Java asigur˘ o performant˘ ridicat˘ a codului de octeti. • Securitate .Java este un limbaj independent de platforma de lucru. Solaris.2 Platforme de lucru Java Limbajul de programare Java a fost folosit la dezvoltarea unor tehnologii dedicate rezolv˘rii unor probleme din cele mai diverse domenii. folosite a ın s pentru dezvoltarea de aplicatii sau componente destinate unei anume cate¸ gorii de utilizatori. ce ruleaz˘ ˆ fundal (”garbage collector”). trecerea de la C.

oferind cea mai comod˘ solutie ın a ¸ pentru distributia ¸i actualizarea aplicatiilor Java. 1.sun.1. a ın cu informatiile memorate ˆ baze de date distribuite. Probabil cel mai cunoscute limbaj interpretat este ¸ a limbajul Basic.5 SDK (Tiger). CE ESTE JAVA ? 13 • J2SE (Standard Edition) Este platforma standard de lucru ce ofer˘ suport pentru crearea de a aplicatii independente ¸i appleturi. • Compilate: codul surs˘ al programelor este transformat de compia lator ˆ ıntr-un cod ce poate fi executat direct de procesor.1. • J2EE (Enterprise Edition) Aceast˘ platform˘ ofer˘ API-ul necesar dezvolt˘rii de aplicatii coma a a a ¸ plexe. programarea dispozitivelor mobile este extrem de simpl˘. Dezavantajul evident este viteza ¸ de executie redus˘.3 Java: un limbaj compilat ¸i interpretat s In functie de modul de executie a aplicatiilor. vom folosi termenul J2SDK pentru a ne referi la distributia ¸ standard J2SE 1. pagini JSP. ¸ s ¸ • J2ME (Micro Edition) Folosind Java. etc. formate din componente ce trebuie s˘ ruleze ˆ sisteme eterogene. numit cod . Avantajul acess ın ¸ s a tei solutii este simplitatea ¸i faptul c˘ fiind interpretat˘ direct sursa ¸ s a a programului obtinem portabilitatea. Toate distributiile Java sunt oferite gratuit ¸i pot fi desc˘rcate de pe ¸ s a Internet de la adresa ”http://java. ¸ s De asemenea. bazate pe componente cum ar fi servleturi. ¸ ın Tot aici g˘sim ¸i suportul necesar pentru crearea de aplicatii ¸i servicii a s ¸ s Web.com”. In continuare. a platforma de lucru J2ME oferind suportul necesar scrierii de programe dedicate acestui scop. aici este inclus˘ ¸i tehnologia Java Web Start ce furnizeaz˘ as a o modalitate extrem de facil˘ pentru lansarea ¸i instalarea local˘ a proa s a gramelor scrise ˆ Java direct de pe Web.1. limbajele de programare se ¸ ¸ ¸ ˆ ımpart ˆ dou˘ categorii: ın a • Interpretate: instructiunile sunt citite linie cu linie de un program ¸ numit interpretor ¸i traduse ˆ instructiuni ma¸in˘. etc.

println("Hello world!"). a ¸ Prin ma¸ina virtual˘ Java (JVM) vom ˆ ¸elege mediul de executie al s a ınt ¸ aplicatiilor Java. a ¸ 1. aa Codurile de octeti sunt seturi de instructiuni care seam˘n˘ cu codul scris ¸ ¸ a a ˆ limbaj de asamblare ¸i sunt generate de compilator independent de mediul ın s de lucru.out. } } . a Limbajul Java combin˘ solutiile amintite mai sus. INTRODUCERE ˆ JAVA IN ma¸in˘. a a s a a Acest lucru este realizat automat de c˘tre distributia J2SDK. dezavantajul fiind s a ¸ a lipsa portabilit˘¸ii. Avantajul este executia extrem de rapid˘. Scriererea codului surs˘ a class FirstApp { public static void main( String args[]) { System. codul compilat ˆ at ıntr-un format de nivel sc˘zut nu a poate fi rulat decˆt pe platforma de lucru pe care a fost compilat. programele Java fiind a ¸ atˆt interpretate cˆt ¸i compilate. Pentru ca un cod de octeti s˘ poat˘ fi executat pe un ¸ ¸ a a anumit calculator.2 Primul program Crearea oric˘rei aplicatii Java presupune efectuarea urm˘torilor pa¸i: a ¸ a s 1.14 CAPITOLUL 1. In timp ce codul ma¸in˘ este executat direct de c˘tre procesor ¸i s a a s poate fi folosit numai pe platforma pe care a fost creat. pe acesta trebuie s˘ fie instalat˘ o ma¸in˘ virtual˘ Java. A¸adar vom avea la dispozitie un compia a s s ¸ lator responsabil cu transformarea surselor programului ˆ a¸a numitul cod ın s de octeti. Codul ma¸in˘ este reprezen¸ s a s a tat de o succesiune de instructiuni specifice unui anumit procesor ¸i unei an¸ s umite platforme de lucru reprezentate ˆ format binar astfel ˆ at s˘ poat˘ ın ıncˆ a a fi executate f˘r˘ a mai necesita nici o prelucrare. precum ¸i un interpretor ce va executa respectivul cod de octeti. codul de octeti este ¸ interpretat de mediul Java ¸i de aceea poate fi rulat pe orice platform˘ pe s a care este instalat˘ mediul de executie Java. ¸ s ¸ Codul de octeti este diferit de codul ma¸in˘.

Acestea au extensia a s a .java. 3.class ¸i implicit sunt plasate ˆ acela¸i director cu fi¸ierele surs˘. Compilatorul creeaz˘ ¸ s s a cˆte un fi¸ier separat pentru fiecare clas˘ a programului. s ın 2.java In cazul ˆ care compilarea a reu¸it va fi generat fi¸ierul FirstApp. S˘ presupunem c˘ am salvat exemplul de mai sus ˆ fi¸ierul a a ın s C:\intro\FirstApp. PRIMUL PROGRAM 15 Toate aplicatiile Java contin o clas˘ principal˘(primar˘) ˆ care trebuie ¸ ¸ a a a ın s˘ se gaseasc˘ metoda main.class ¸i vom apela interpretorul ın ¸ s s astfel: java FirstApp Rularea unei aplicatii care nu folose¸te interfat˘ grafic˘. ¸ Apelul compilatorului se face pentru fi¸ierul ce contine clasa principal˘ a s ¸ a aplicatiei sau pentru orice fi¸ier/fi¸iere cu extensia java. Compilarea aplicatiei ¸ Pentru compilare vom folosi compilatorul javac din distributia J2SDK. Clasele aplicatiei se pot gasi fie ˆ a a ¸ ıntr-un singur fi¸ier. se va face ˆ ¸ s ¸a a ıntr-o fereastr˘ sistem. Salvarea fi¸ierelor surs˘ s a Se va face ˆ fi¸iere care au obligatoriu extensia java. fie ˆ mai multe. Deoarece interpretorul are ca argument de a intrare numele clasei principale ¸i nu numele unui fi¸ier. Este recomandat ca fi¸ierul care contine codul surs˘ a s ¸ a al clasei primare s˘ aib˘ acela¸i nume cu cel al clasei. a . Rularea aplicatiei ¸ Se face cu interpretorul java. de¸i acest lucru nu a a s s este obligatoriu. nici o alt˘ extenın s a sie nefiind acceptat˘. ın s s 4. s ın s s a javac FirstApp.2.class.1. apelat pentru unitatea de compilare corespunz˘toare clasei principale. ne vom pozitiona s s ¸ ˆ directorul ce contine fi¸ierul FirstApp.

Mai jos sunt oferite cˆteva exemple de caractere Unicode. a O alt˘ caracteristic˘ a setului de caractere Unicode este faptul c˘ ˆ a a a ıntreg intervalul de reprezentare a simbolurilor este divizat ˆ subintervale numite ın blocuri.2 Cuvinte cheie Cuvintele rezervate ˆ Java sunt. Greek.16 CAPITOLUL 1. a Currency.9 • \u03B1 . Gothic. Musical.3. Mathematical.org”. a ın Acesta este un standard international care ˆ ¸ ınlocuie¸te vechiul set de caractere s ASCII ¸i care folose¸te pentru reprezentarea caracterelor 2 octeti. Primele 256 caractere a Unicode corespund celor ASCII.\u0039 : cifre ISO-Latin 0 . a • \u0030 . spre deosebire de ASCII.\u22FF : simboluri matematice (∀.class este gre¸it! s 1. Arabic. Arrows. 1.\u03C9 : simboluri grece¸ti α − ω s • \u2200 .unicode.3.) • \u4e00 .9 • \u0660 . Japonez. ∃.3 1. unde a a era posibil˘ reprezentarea a doar 256 de caractere. ceea ce s s ¸ ˆ ınseamn˘ c˘ se pot reprezenta 65536 de semne. ın .\u0669 : cifre arabic-indic 0 . Acestea nu pot fi folosite ca nume de clase. cele din C++ ¸i au fost ın a ¸ s enumerate ˆ tabelul de mai jos. INTRODUCERE ˆ JAVA IN Atentie ¸ Un apel de genul java c:\intro\FirstApp.1 Structura lexical˘ a limbajului Java a Setul de caractere Limbajului Java lucreaz˘ ˆ mod nativ folosind setul de caractere Unicode. a a unde xxxx reprezint˘ codul caracterului. etc. cu cˆteva exceptii. cˆteva exemple de blocuri fiind: Basic Latin. referirea la celelalte f˘cˆndu-se prin \uxxxx.\u9fff : litere din alfabetul Han (Chinez. Coreean) Mai multe informatii legate de reprezentarea Unicode pot fi obtinute la ¸ ¸ adresa ”http://www. ∅. etc.

3. false. baza 16 (ˆ ¸ ıncep cu caracterele 0x) ¸i baza 8 (ˆ s ıncep cu cifra 0) ¸i pot fi de dou˘ tipuri: s a – normali .3 Identificatori Sunt secvente nelimitate de litere ¸i cifre Unicode.3. ˆ ¸ s ıncepˆnd cu o liter˘. STRUCTURA LEXICALA A LIMBAJULUI JAVA 17 interfete.5.se reprezint˘ pe 8 octeti (64 biti) ¸i se termin˘ cu caracterul a ¸ ¸ s a L (sau l). mai exist˘ ¸i cuvˆntul cheie enum.4 Literali Literalii pot fi de urm˘toarele tipuri: a • Intregi Sunt acceptate 3 baze de numeratie : baza 10. Cuvintele marcate prin ∗ ın ¸ sunt rezervate. null nu sunt cuvinte cheie. dar nu sunt folosite.˘ 1. variabile sau metode. 1. . true. Dup˘ a a a cum am mai spus. abstract boolean break byte case catch char class const* continue default do double else extends final finally float for goto* if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw throws transient try void volatile while Incepˆnd cu versiunea 1. a as a 1.se reprezint˘ pe 4 octeti (32 biti) a ¸ ¸ – lungi . identificatorii nu au voie s˘ fie identici cu cuvintele rezera vate. ¸ dar nu pot fi nici ele folosite ca nume ˆ aplicatii.3.

Secventele escape pre¸ definite ˆ Java sunt: ın – ’\b’ : Backspace (BS) – ’\t’ : Tab orizontal (HT) – ’\n’ : Linie nou˘ (LF) a – ’\f’ : Pagin˘ nou˘ (FF) a a – ’\r’ : Inceput de rˆnd (CR) a – ’\"’ : Ghilimele – ’\’’ : Apostrof – ’\\’ : Backslash . • Logici Sunt reprezentati de true . a • Caracter Un literal de tip caracter este utilizat pentru a exprima caracterele codului Unicode. ¸ Exemple: 1. Secventele escape permit specificarea ¸ caracterelor care nu au reprezentare grafic˘ ¸i reprezentarea unor caras actere speciale precum backslash.valoarea logic˘ de adev˘r.18 CAPITOLUL 1.valoarea logic˘ de fals.0.reprezentate pe 32 biti. 3f. etc. 2e2. a Atentie ¸ Spre deosebire de C++. literalii ˆ ıntregi 1 ¸i 0 nu mai au semnificatia s ¸ de adev˘rat. respectiv false ¸ a a . INTRODUCERE ˆ JAVA IN • Flotanti ¸ Pentru ca un literal s˘ fie considerat flotant el trebuie s˘ aib˘ cel putin o a a a ¸ zecimal˘ dup˘ virgul˘. Reprezentarea se face fie folosind o liter˘.reprezentate pe 64 biti. 4D. respectiv fals. apostrof. respectiv D ¸ sau d pentru valorile duble . fie o secvent˘ a ¸a escape scris˘ ˆ a ıntre apostrofuri. s˘ fie ˆ notatie exponential˘ sau s˘ aib˘ sufixul a a a a ın ¸ ¸ a a a F sau f pentru valorile normale .

^ (xor). -. . ++. STRUCTURA LEXICALA A LIMBAJULUI JAVA 19 • Siruri de caractere ¸ Un literal ¸ir de caractere este format din zero sau mai multe caractere s ˆ ıntre ghilimele. --n Evaluarea expresiilor logice se face prin metoda scurtcircuitului: evaluarea se opre¸te ˆ momentul ˆ care valoarea de adev˘r a expresiei este s ın ın a sigur determinat˘. |(or).3. a s ¸a definit˘ ˆ pachetul java. cei din C++: • atribuirea: = • operatori matematici: +. orice ¸ir este de fapt o instant˘ a clasei String. ~ (not) ¸ • operatori de translatie: <<. -. cu mici deosebiri. . ||(or). ==. Caracterele care formeaz˘ ¸irul pot fi caractere grafice as sau secvente escape. ¸ a s a 1. ++x. <=.6 Operatori Operatorii Java sunt. *. <=. a ın 1. !(not) • operatori relationali: <.5 Separatori Un separator este un caracter care indic˘ sfˆr¸itul unei unit˘¸i lexicale ¸i a as at s ınceputul alteia. Este permis˘ notatia prescurtat˘ de forma lval op= rval: x += 2 n a ¸ a -= 3 Exist˘ operatori pentru autoincrementare ¸i autodecrementare (post ¸i a s s pre): x++. >. ¸ Dac˘ ¸irul este prea lung el poate fi scris ca o concatenare de sub¸iruri as s de dimensiune mai mic˘. >>. n--. In Java separatorii sunt urm˘torii: ( ) a [ ] . %.. Sirul vid ın este "". ca ˆ exemplul: "Ana " + " are " + " mere ".3. Dup˘ cum vom vedea. Instructiunile unui program se separ˘ cu punct ¸i virgul˘. a • operatori logici: &&(and). concatenarea ¸irurilor realizˆndu-se cu opera s a atorul +.3. . >>> (shift la dreapta f˘r˘ semn) ¸ a a . /.lang.˘ 1. != ¸ • operatori pe biti: &(and).

System.println(s1 + " are " + x + " " + s2). long l = (long)i. La fel se ˆ ¸ ıntampl˘ cu secventa // ˆ comentarii care a ¸ ın incep cu /* sau */. Textul dintre cele dou˘ secvente este automat mutat ˆ s a ¸ ın documentatia aplicatiei de c˘tre generatorul automat de documentatie ¸ ¸ a ¸ javadoc. . y=1. char c = (char)96. int i = 200. s • Comentarii pe mai multe linii care ¸in de documentatie. INTRODUCERE ˆ JAVA IN • operatorul if-else: expresie-logica ? val-true : val-false • operatorul . • Comentarii pe o singur˘ linie. String s2="mere". • operatorul + pentru concatenarea ¸irurilor: s String s1="Ana". ın • Nu putem introduce comentarii ˆ interiorul literalilor caracter sau ¸ir ın s de caractere. int x=10. care incep cu //.7 Comentarii In Java exist˘ trei feluri de comentarii: a • Comentarii pe mai multe linii.out. //narrowing conversion 1. (virgul˘) folosit pentru evaluarea secvential˘ a operatiilor: a ¸ a ¸ int x=0. ˆ ınchise ˆ ıntre /* ¸i */. • operatori pentru conversii (cast) : (tip-de-data) int a = (int)’a’. int i2 = (int)l2.3. ˆ t ¸ ınchise ˆ ıntre /** ¸i */. z=2.20 CAPITOLUL 1. a Observatii: ¸ • Nu putem scrie comentarii ˆ interiorul altor comentarii. • Secventele /* ¸i */ pot s˘ apar˘ pe o linie dup˘ secventa // dar ˆsi ¸ s a a a ¸ ı¸ pierd semnificatia. //widening conversion long l2 = (long)200.

a Exist˘ trei tipuri de date din limbajul C care nu sunt suportate de lima bajul Java. ¸a s a prin urmare tipurile de date ar trebui s˘ fie de fapt definite de clase ¸i toate a s variabilele ar trebui s˘ memoreze instante ale acestor clase (obiecte). int (4). long (8) – reale: float (4 octeti). struct ¸i union. care sunt cele uzuale : as s • aritmetice –ˆ ıntregi: byte (1 octet). a Vectorii. In Java acest lucru a nu mai este valabil. o referint˘ (adres˘ de ¸a a memorie) c˘tre valoarea sau multimea de valori reprezentat˘ de variabila a ¸ a respectiv˘. clasele ¸i interfetele sunt tipuri referint˘.1. mai a ıns˘ ¸ a exist˘ ¸i a¸a numitele tipurile primitive de date.4. short (2). ˆ a.4 1. In a ¸ principiu acest lucru este adev˘rat. ın . Acestea sunt: pointer. double (8) • caracter: char (2 octeti) ¸ • logic: boolean (true ¸i false) s In alte limbaje de programare formatul ¸i dimensiunea tipurilor primitive de s date pot depinde de platforma pe care ruleaz˘ programul. Pointerii au fost s eliminati din cauz˘ c˘ erau o surs˘ constant˘ de erori. orice dependent˘ de o anumit˘ platform˘ specific˘ fiind ¸a a a a eliminat˘. Valoarea unei variabile s ¸ ¸a de acest tip este. iar struct ¸i union nu ˆsi mai au rostul atˆt timp cˆt tipurile ¸a s ı¸ a a compuse de date sunt formate ˆ Java prin intermediul claselor. spre deosebire de tipurile primitive. Java porne¸te de la premiza c˘ ”orice este un obiect”. pentru usurinta program˘rii. TIPURI DE DATE SI VARIABILE ¸ 21 1. locul lor fiind luat de ¸ a a a a tipul referint˘.1 Tipuri de date ¸i variabile s Tipuri de date In Java tipurile de date se impart ˆ dou˘ categorii: tipuri primitive ¸i ın a s tipuri referint˘.4.

c3=’v’. Evident. char c1=’j’. exist˘ posibilitatea de a declara ¸i initializa mai multe variabile a s ¸ sau constante de acela¸i tip ˆ s ıntr-o singur˘ instructiune astfel: a ¸ Tip variabila1[=valoare1]. MAXIM = 10.4. c2=’a’. long numarElemente = 12345678L. ¸ • Declararea variabilelor: Tip numeVariabila.22 CAPITOLUL 1. In functie de locul ˆ care sunt declarate variabilele se ˆ ¸ ın ımpart ˆ urm˘toatele ın a categorii: a.2 Variabile Variabilele pot fi de tip primitiv sau referinte la obiecte (tip referint˘). pentru a putea fi folosite variabilele trebuie declarate ¸i. atunci a ¸ primele litere ale celorlalti atomi se scriu cu majuscule. ¸ Exemple: final double PI = 3.. declarate ˆ interiorul unei clase. printre altele. INTRODUCERE ˆ JAVA IN 1. final int MINIM=0. int valoare = 100. urm˘toarele ¸ ın a criterii: • variabilele finale (constante) se scriu cu majuscule. String bauturaMeaPreferata = "apa". ¸ • Declararea constantelor: final Tip numeVariabila. • Initializarea variabilelor: Tip numeVariabila = valoare.. Conventia de numire a variabilelor ˆ Java include. • variabilele care nu sunt constante se scriu astfel: prima liter˘ mic˘ iar a a dac˘ numele variabilei este format din mai multi atomi lexicali. . s eventual.. c4=’a’. variabila2[=valoare2]. In¸ ¸a diferent de tipul lor. vizibile pentru ın toate metodele clasei respective cˆt ¸i pentru alte clase ˆ functie de a s ın ¸ nivelul lor de acces (vezi ”Declararea variabilelor membre”).14. initializate. Variabile membre..

ın a 23 c.err.4. } } } Observatii: • Variabilele declarate ˆ ıntr-un for.//incorect • Nu este permis˘ ascunderea unei variabile: a .println(e. i<100. ¸ ¸ class Exemplu { //Fiecare variabila corespunde situatiei data de numele ei //din enumerarea de mai sus int a. vizibili doar ˆ metoda respectiv˘. i++) { //domeniul de vizibilitate al lui i } i = 101. declarate ˆ ıntr-un bloc de cod. } try { a = b/c. a d. declarate ˆ ıntr-o metod˘. e. d++) { c --.getMessage()). Parametrii de la tratarea exceptiilor (vezi ”Tratarea exceptiilor”). TIPURI DE DATE SI VARIABILE ¸ b. r˘mˆn locale corpului ciclului: a a for(int i=0. Variabile locale. int c = 10. vizibile doar ˆ blocul ın respectiv. d < 10. public void metoda(int b) { a = b. for(int d=0. } catch(ArithmeticException e) { System. Parametri metodelor. vizibile doar ˆ metoda rea ın spectiv˘. Variabile locale.1.

switch-case ¸ • Instructiuni de salt: for....24 CAPITOLUL 1. } if (expresie-logica) { . } else { .5 Controlul executiei ¸ Instructiunile Java pentru controlul executiei sunt foarte asem˘n˘toare celor ¸ ¸ a a din limbajul C ¸i pot fi ˆ artite ˆ urm˘toarele categorii: s ımp˘ ¸ ın a • Instructiuni de decizie: if-else. throw ¸ ¸ • Alte instructiuni: break.. break. case valoare2: . continue. while. do-while ¸ • Instructiuni pentru tratarea exceptiilor: try-catch-finally..5. { int x=2.. INTRODUCERE ˆ JAVA IN int x=1.. //incorect } 1. label: ¸ 1..1 if-else Instructiuni de decizie ¸ if (expresie-logica) { . return. } switch-case switch (variabila) { case valoare1: .

5. . ..2 for Instructiuni de salt ¸ for(initializare. a¸ a while while (expresie-logica) { ....5. expresie-logica. j=100 .. break. default: . j--) { .. } Atˆt la initializare cˆt ¸i ˆ pasul de iteratie pot fi mai multe instructiuni a ¸ a s ın ¸ ¸ desp˘rtite prin virgul˘. } do-while do { .1.. i++.. 1... i < 100 && j > 0. } 25 Variabilele care pot fi testate folosind instructiunea switch nu pot fi decˆt ¸ a de tipuri primitive. } while (expresie-logica). pas-iteratie) { //Corpul buclei } for(int i=0... CONTROLUL EXECUTIEI ¸ .

ca ˆ s a a ınexemplul de mai jos: i=0. INTRODUCERE ˆ JAVA IN 1. while (j < 10) { j++.out. j=0. eventual. System. if (j==5) continue eticheta.out. ¸ • return [valoare]: termin˘ o metod˘ ¸i.26 CAPITOLUL 1.println("j="+j). aa s ¸ • continue: termina fortat iteratia curent˘ a unui ciclu ¸i trece la urm˘toarea ¸ ¸ a s a iteratie.6 1. returneaz˘ o valoa as a rare. s a De¸i ˆ Java nu exist˘ goto. se pot defini totu¸i etichete folosite ˆ expresii s ın a s ın de genul: break numeEticheata sau continue numeEticheta.5. } 1. } i++. utile pentru a controla punctul de ie¸ire dintr-o structur˘ repetitiv˘.1 Vectori Crearea unui vector Crearea unui vector presupune realizarea urm˘toarelor etape: a .6. s ın ¸ 1.5.println("i="+i). respectiv ¸ ¸ throw ¸i vor fi tratate ˆ capitolul ”Exceptii”. eticheta: while (i < 10) { System.4 Alte instructiuni ¸ • break: p˘r˘se¸te fortat corpul unei structuri repetitive. • numeEticheta: : Define¸te o etichet˘.3 Instructiuni pentru tratarea exceptiilor ¸ ¸ Instructiunile pentru tratarea exceptiilor sunt try-catch-finally. if (j==7) break eticheta.

Acest lucru se face prin expresii de forma: a Tip[] numeVector. Instantierea unui vector se va face printr-o expresie de ¸ genul: numeVector = new Tip[nrElemente]. • Instantierea ¸ Declararea unui vector nu implic˘ ¸i alocarea memoriei necesare pentru as retinerea elementelor. unde nrElemente reprezint˘ num˘rul maxim de elemente pe care le a a poate avea vectorul. numit˘ ¸i ¸ ¸ a s instantierea vectorului. se realizeaz˘ ˆ ¸ a ıntotdeauna prin intermediul operatorului new. ˆ ınainte de toate. unde ¸ a prin dimensiune(T ip) am notat num˘rul de octeti pe care se reprezint˘ a ¸ a tipul respectiv. sau Tip numeVector[]. . v = new int[10]. Operatiunea de alocare a memoriei. //aloca spatiu pentru 10 intregi: 40 octeti c = new char[10]. String adrese[]. VECTORI 27 • Declararea vectorului .6. ca ˆ exemplele de mai jos: ın int[] intregi.1. In urma instantierii vor fi alocati: nrElemente ∗ ¸ ¸ dimensiune(T ip) octeti necesari memor˘rii elementelor din vector. //aloca spatiu pentru 10 caractere: 20 octeti Declararea ¸i instantierea unui vector pot fi f˘cute simultan astfel: s ¸ a Tip[] numeVector = new Tip[nrElemente]. sa-l declar˘m.Pentru a putea utiliza un vector trebuie.

alocarea memoriei f˘cˆndu-se automat ˆ functie de a a a ın ¸ num˘ rul de elemente cu care se initializeaz˘ vectorul. 2. 6. De exemplu. int []factorial = {1. a ¸ a String culori[] = {"Rosu". "Verde"}.28 CAPITOLUL 1.6. // a. In acest caz instantierea nu mai trebuie a s ¸ facut˘ explicit. int []a = new int[5]. Primul indice al unui vector este 0.length are valoarea 10 Pentru a ˆ ¸elege modalitatea de folosire a lui length trebuie mentionat c˘ ınt ¸ a fiecare vector este de fapt o instant˘ a unei clase iar length este o variabil˘ ¸a a public˘ a acelei clase.length are valoarea 5 int m[][] = new int[5][10]. ˆ care este retinut num˘rul maxim de elemente al a ın ¸ a vectorului.6. alocarea memoriei f˘cˆndu-se doar prin ina a termediul opearatorului new. adic˘ elementele sale pot primi ni¸te valori initiale. // m[0]. deci pozitiile unui vector cu n ele¸ mente vor fi cuprinse ˆ ıntre 0 ¸i n − 1. 1. Nu sunt permise constructii de genul s ¸ Tip numeVector[nrElemente]. "Galben". INTRODUCERE ˆ JAVA IN • Initializarea (optional) Dup˘ declararea unui vector. matrice[i] este linia i a matricii ¸i reprezint˘ un vector cu nrColoane s a elemente iar matrice[i][j] este elementul de pe linia i ¸i coloana j. 120}.2 Tablouri multidimensionale In Java tablourile multidimensionale sunt de fapt vectori de vectori.3 Dimensiunea unui vector Cu ajutorul variabilei length se poate afla num˘rul de elemente al unui a vector. acesta poate fi ¸ ¸ a initializat. . 24. evident ¸ a s ¸ dac˘ este cazul pentru a¸a ceva. int v[10]. crearea ¸i instantierea unei matrici vor fi realizate astfel: s ¸ Tip matrice[][] = new Tip[nrLinii][nrColoane]. //ilegal //corect 1. s 1. int v[] = new int[10].

. 0.5 Sortarea vectorilor . i++) b[i] = a[i]. 2. 0.c˘utarea binar˘ a unei anumite valori ˆ a a ıntr-un vector sortat.sort(v). fie cu ajutorul metodei System. java. 4} • binarySearch . // Varianta 1 for(int i=0. int b[] = new int[4].Arrays ofer˘ diverse metode foarte utile ˆ lucrul cu veca ın tori cum ar fi: • sort . int a[] = {1. Dup˘ cum vom vedea. b.util. 3. 4. 2}.sorteaz˘ ascendent un vector. 1. fie element cu element. // Nu are efectul dorit b = a.arraycopy(a.1.length. folosind un algoritm de tip Quicka Sort performant. // Varianta 2 System. i<a.Arrays.util.6.6. 2. o atribuire de genul b = a are alt˘ a a semnificatie decˆt copierea elementelor lui a ˆ b ¸i nu poate fi folosit˘ ˆ ¸ a ın s a ın acest scop. de complexitate O(n log(n)). int v[]={3. a Clasa java. // Sorteaza vectorul v // Acesta va deveni {1.6.arraycopy. ca ˆ exemın plele de mai jos. a. 1.length). 4}. programs a atorul trebuind s˘ se concentreze pe aspectele specifice problemei abordate. VECTORI 29 1.4 Copierea vectorilor Copierea elementelor unui vector a ˆ ıntr-un alt vector b se poate face.clasa Arrays In Java s-a pus un accent deosebit pe implementarea unor structuri de date ¸i algoritmi care s˘ simplifice proceseul de crearea a unui algoritm. 3.

atribuie fiec˘rui element din vector o valoare specificat˘.testarea egalit˘¸ii valorilor a doi vectori (au acelea¸i num˘r at s a de elemente ¸i pentru fiecare indice valorile corespunz˘toare din cei doi s a vectori sunt egale) • fill . a a 1. delete. cum ar fi: append. ale c˘ror elemente au tipul Object. cea mai folosit˘ modalitate de a lucra cu ¸iruri este prin intermediul a s clasei String. Observati prima variant˘ de declarare a ¸irului s din exemplul de mai sus ¸ a s . un ¸ir de caractere poate fi reprezentat printr-un vector format s din elemente de tip char.care prezint˘ o particularitate a clasei String a a fata de restul claselor Java referitoare la instantierea obiectelor sale.6.util. Exemple echivalente de declarare a unui ¸ir: s String s = "abc". ’c’}. cea mai folosit˘ . String s = new String("abc").30 CAPITOLUL 1. s ¸ ın ¸ 1. Astfel de obiecte descriu vectori eterogeni. insert. String s = new String(data). Dac˘ un ¸ir de caractere este constant (nu se dore¸te schimbarea continutului a s s ¸ s˘ pe parcursul executiei programului) atunci el va fi declarat de tipul String. un obiect de tip String sau un obiect de tip StringBuffer. INTRODUCERE ˆ JAVA IN • equals . Diferenta principal˘ ˆ ¸ a ıntre aceste clase este c˘ StringBuffer pune la dispozitie metode pentru modificarea a ¸ continutului ¸irului. a ¸i vor fi studiati ˆ capitolul ”Colectii”. ¸ s Uzual. Clasa StringBuffer a s va fi utilizat˘ predominant ˆ aplicatii dedicate proces˘rii textelor cum ar fi a ın ¸ a editoarele de texte. ’b’.7 Siruri de caractere ¸ In Java. care are ¸i unele particularit˘¸i fat˘ de restul claselor menite s˘ s at ¸a a simplifice cˆt mai mult folosirea ¸irurilor de caractere. ¸ ¸ .de altfel. reverse. a ¸ altfel va fi declarat de tip StringBuffer. char data[] = {’a’.6 Vectori cu dimensiune variabil˘ ¸i eterogeni as Implement˘ri ale vectorilor cu num˘r variabil de elemente sunt oferite de a a clase specializate cum ar fi Vector sau ArrayList din pachetul java.

ın s String s1 = "abc" + "xyz".print("Vectorul v are" + v.˘ 1.8 1. deoarece unele sisteme de operare. Aceste argumente sunt utile pentru a permite utilizaa torului s˘ specifice diverse optiuni legate de functionarea aplicatiei sau s˘ a ¸ ¸ ¸ a furnizeze anumite date initiale programului.length + " elemente"). String x = "a" + 1 + "b" Pentru a l˘muri putin lucrurile. folosind metoda append.8. Mai jos. ˆ sensul c˘ ın a permite concatenarea ¸irurilor cu obiecte de orice tip care au o reprezentare s de tip ¸ir de caractere.toString() Atentie ˆ a la ordinea de efectuare a operatiilor. Sirul s=1+2+"a"+1+2 ¸ ıns˘ ¸ ¸ va avea valoarea "3a12". ceea ce execut˘ compilatorul atunci cˆnd a ¸ a a ˆ alne¸te o secvent˘ de genul String x = "a" + 1 + "b" este: ıntˆ s ¸a String x = new StringBuffer().append("a").1 Folosirea argumentelor de la linia de comand˘ a Transmiterea argumentelor O aplicatie Java poate primi oricˆte argumente de la linia de comanda ˆ ¸ a ın momentul lans˘rii ei. FOLOSIREA ARGUMENTELOR DE LA LINIA DE COMANDA 31 Concatenarea ¸irurilor de caractere se face prin intermediul operatorului s + sau. In Java.append(1).out. append("b"). cum ar fi Mac OS. primul + fiind operatorul matematic de adunare iar al doilea +. nu au ˆ ın mod normal linie de comand˘.8. s 1. String s2 = "123". ˆ cazul ¸irurilor de tip StringBuffer. cel de concatenare a ¸irurilor. a . sunt cˆteva exemple: s a System. operatorul de concatenare + este extrem de flexibil. String s3 = s1 + s2. ¸ Atentie ¸ Programele care folosesc argumente de la linia de comand˘ nu sunt 100% a pure Java.

32 CAPITOLUL 1. Acesta este primit s de aplicatie ca parametru al metodei main. argumentele trebuie separate prin spatii ın ¸ iar dac˘ unul dintre argumente contine spatii. A¸adar.2 Primirea argumentelor In momentul lans˘rii unei aplicatii interpretorul parcurge linia de comand˘ cu a ¸ a care a fost lansat˘ aplicattia ¸i. formatul general pentru lansarea unei aplicatii care prime¸te argus ¸ s mente de la linia de comand˘ este: a java NumeAplicatie [arg0 arg1 . argn] In cazul ˆ care sunt mai multe. . a ¸ Vectoru args este instantiat cu un num˘r de elemente egal cu num˘rul ar¸ a a gumentelor primite de la linia de comand˘.8. o aplicatie poate s˘ nu primeasc˘ nici un argument sau ¸ a a poate s˘ ignore argumentele primite de la linia de comand˘.txt vectorul args va contine un ¸ singur element pe prima s˘ pozitie: args[0]="persoane. INTRODUCERE ˆ JAVA IN Argumentele de la linia de comand˘ sunt introduse la lansarea unei aplicatii. atunci el trebuie pus ˆ a ¸ ¸ ıntre ghilimele.txt". . Pentru a ordona fi¸ierul "persoane. a ¸ s ¸ s˘ presupunem c˘ aplicatia Sortare ordoneaz˘ lexicografic (alfabetic) liniile a a ¸ a unui fi¸ier ¸i prime¸te ca argument de intrare numele fi¸ierului pe care s˘ s s s s a ˆ sorteze.txt A¸adar. transmite programului a ¸ s ın ın a argumentele specificate sub forma unui vector de ¸iruri. aplicatia va fi lansat˘ ıl s ¸ a astfel: java Sortare persoane. a ¸ fiind specificate dup˘ numele aplicatiei ¸i separate prin spatiu.txt". Reamintim c˘ formatul metodei ¸ a main din clasa principal˘ este: a public static void main (String args[]) Vectorul args primit ca parametru de metoda main va contine toate argu¸ mentele transmise programului de la linia de comand˘. ˆ cazul ˆ care exist˘. a In cazul apelului java Sortare persoane. a a 1. De exemplu. pentru a afla num˘rul de a s a argumente primite de program este suficient s˘ afl˘m dimensiunea vectorului a a args prin intermediul atributului length: . Evident.

//exista sigur String prenume. //termina aplicatia } String nume = args[0]. if (args. ˆ caz contrar. } } Spre deosebire de limbajul C.out. Tratarea a ¸ acestor exceptii este prezentat˘ ˆ capitolul ”Exceptii”.length >= 1) prenume = args[1]. //valoare implicita System.out. i++) System. . ˆ ¸ ¸ ıntrucˆt ˆ Java numele aplicatiei este a ın ¸ chiar numele clasei principale.out.length . FOLOSIREA ARGUMENTELOR DE LA LINIA DE COMANDA 33 public static void main (String args[]) { int numarArgumente = args. s˘ a ¸ s ın a afi¸eze un mesaj de avertizare sau s˘ foloseasc˘ ni¸te valori implicite.8. else prenume = "". i < args.println("Numar insuficient de argumente!").println("Salut " + nume + " " + prenume).length. este necesar s˘ test˘m dac˘ programul a primit argumentele a a a de la linia de comand˘ necesare pentru functionarea sa ¸i. vor a ıns˘ ap˘rea exceptii (erori) de tipul ArrayIndexOutOfBoundsException. adic˘ a clasei ˆ care se gase¸te metoda main.exit(-1). } In cazul ˆ care aplicatia presupune existenta unor argumente de la linia ın ¸ ¸ de comand˘. a ın s S˘ consider˘ ˆ continuare un exemplu simplu ˆ care se dore¸te afi¸area a a ın ın s s pe ecran a argumentelor primite de la linia de comand˘: a public class Afisare { public static void main (String[] args) { for (int i = 0.˘ 1. System. ca ˆ s a a s ın exemplul de mai jos: public class Salut { public static void main (String args[]) { if (args. vectorul primit de metoda main nu contine ¸ pe prima pozitie numele aplicatiei. ˆ a acestea nu au fost transmise programului la lansarea sa.length == 0) { System.println(args[i]). ¸ a ın ¸ Din acest motiv.

System.pow(numar. } } Metodele de tipul parseTipNumeric pot produce exceptii (erori) de tipul ¸ NumberFormatException ˆ cazul ˆ care ¸irul primit ca parametru nu reprezint˘ ın ın s a un numar de tipul respectiv. ın a etc. Double.5 la puterea 2 Conversia celor dou˘ argumente ˆ numere se va face astfel: a ın public class Power { public static void main(String args[]) { double numar = Double. Tratarea acestor exceptii este prezentat˘ ˆ ¸ a ın capitolul ”Exceptii”. S˘ consider˘m.out.34 } } CAPITOLUL 1. INTRODUCERE ˆ JAVA IN Un apel de genul java Afisare Hello Java va produce urm˘torul rezula tat (aplicatia a primit 2 argumente): ¸ Hello Java Apelul java Afisare "Hello Java" va produce ˆ a alt rezultat (aplicatia ıns˘ ¸ a primit un singur argument): Hello Java 1. ¸ . In cazul ˆ care unele dintre acestea reprezint˘ s ın a valori numerice ele vor trebui convertite din ¸iruri ˆ numere.8. argumentele fiind trimise de la linia de comand˘ sub forma: a a java Power "1.parseDouble(args[0]).println("Rezultat=" + Math. Float. Acest lucru s ın se realizeaz˘ cu metode de tipul parseTipNumeric aflate ˆ clasa corespuna ın zatoare tipului ˆ care vrem s˘ facem conversia: Integer.3 Argumente numerice Argumentele de la linia de comand˘ sunt primite sub forma unui vector de a ¸iruri (obiecte de tip String). int putere = Integer. de exemplu.5" "2" //ridica 1. putere)). c˘ aplicatia Power ridic˘ un numar real la o a a a ¸ a putere ˆ ıntreag˘.parseInt(args[1]).

• Instantierea ¸ Se realizeaz˘ prin intermediul operatorului new ¸i are ca efect crearea a s efectiv˘ a obiectului cu alocarea spatiului de memorie corespunz˘tor. a ¸ a numeObiect = new NumeClasa(). ˆ sensul c˘ a ¸ ın a imediat dup˘ alocarea memoriei ca efect al operatorului new este apelat a constructorul specificat. crearea obiectelor ın se realizeaz˘ prin instantierea unei clase ¸i implic˘ urm˘toarele lucruri: a ¸ s a a • Declararea Presupune specificarea tipului acelui obiect. • Initializarea ¸ Se realizeaz˘ prin intermediul constructorilor clasei respective. Parantezele rotunde de dup˘ numele clasei ina dic˘ faptul c˘ acolo este de fapt un apel la unul din constructorii clasei a a ¸i nu simpla specificare a numelui clasei.1 Ciclul de viat˘ al unui obiect ¸a Crearea obiectelor In Java.Capitolul 2 Obiecte ¸i clase s 2. Initializarea a ¸ este de fapt parte integrant˘ a procesului de instantiere. a s ¸a NumeClasa numeObiect. cu alte cuvinte specificarea clasei acestuia (vom vedea c˘ tipul unui obiect poate fi ¸i o interfat˘).1 2.1. ca ˆ orice limbaj de programare orientat-obiect. instantierea ¸i initializarea apar sub forma: ¸ s ¸ 35 . s Mai general.

0). In primul caz Rectangle() este un apel c˘tre constructorul clasei Rectangle a care este responsabil cu initializarea obiectului cu valorile implicite. new Dimension(100. int latime. initializarea se poate face ¸i cu anumiti paraa ın ¸ s ¸ metri. instantierea ¸i initializarea obiectului pot ap˘rea pe aceea¸i ¸ s ¸ a s linie (cazul cel mai uzual): Rectangle patrat = new Rectangle(0. ın˘ ¸ Rectangle r1. cu conditia s˘ existe un constructor al clasei respective care s˘ accepte ¸ a a parametrii respectivi. caz ˆ care etapa de declarare a referintei obiectului ¸ ın ¸ nu mai este prezent˘: a Rectangle patrat = new Rectangle(new Point(0. 200). 100. Obiecte anonime Este posibil˘ ¸i crearea unor obiecte anonime care servesc doar pentru a s initializarea altor obiecte. r2. r1 = new Rectangle(). 0. 0. clasa Rectangle are urm˘torii construca tori: public public public public public public Rectangle() Rectangle(int latime. 100)). OBIECTE SI CLASE ¸ numeObiect = new NumeClasa([argumente constructor]). r2 = new Rectangle(0. int inaltime) Rectangle(Point origine) Rectangle(Point origine. a ¸ definite de coordonatele coltului stˆnga sus (originea) ¸i l˘¸imea. 100. int inaltime) Rectangle(Point origine. Dup˘ ¸ a cum observ˘m ˆ al doilea caz. De exemplu. clas˘ ce descrie suprafete grafice rectangulare. int y. 100). Dimension dimensiune) Declararea.36 CAPITOLUL 2. Fiecare clas˘ are un set de constructori care se ocup˘ cu initializare a a ¸ obiectelor nou create. int latime. int inaltime) Rectangle(int x. ˆ care declar˘m ¸i instantiem dou˘ a a a ın a s ¸ a obiecte din clasa Rectangle. S˘ consider˘m urm˘torul exemplu. . respectiv ¸ a s at ˆ altimea.

Rectangle patrat = new Rectangle(0. 0. 300). //schimba originea Accesul la variabilele unui obiect se face ˆ conformitate cu drepturile de ın acces pe care le ofer˘ variabilele respective celorlalte clase. 200). //Eroare . 0. 20). el poate fi folosit ˆ urm˘toarele sensuri: aflarea unor a ın a informatii despre obiect. Rectangle patrat. //afiseaza 100 patrat. Programarea orientat˘ obiect descurajeaz˘ folosirea a a direct˘ a variabilelor unui obiect deoarece acesta poate fi adus ˆ st˘ri ina ın a consistente (ireale).out. height. origin. System.x = 10. ¸ a ¸ Aceste lucruri se realizeaza prin aflarea sau schimbarea valorilor variabilelor sale. Aflarea valorilor acestor variabile sau schimbarea lor se face prin constructii ¸ de genul: Rectangle patrat = new Rectangle(0. //schimba dimensiunea Se observ˘ c˘ valorile variabilelor pot fi modificate indirect prin intera a mediul metodelor sale. patrat. respectiv prin apelarea metodelor sale. Referirea valorii unei variabile se face prin obiect.setLocation(10.metoda([parametri]). (vezi ”Modificaa tori de acces pentru membrii unei clase”) Apelul unei metode se face prin obiect.variabila De exemplu clasa Rectangle are variabilele publice x. patrat. 200). 100. patrat. width. 100.origin = new Point(10.1.1.2 Folosirea obiectelor Odat˘ un obiect creat. //schimba originea patrat. pentru fiecare variabil˘ care descrie starea a . y.setSize(200. //schimba originea patrat.y = 20. schimbarea st˘rii sale sau executarea unor actiuni. Alocarea memoriei se face doar la apelul operatorului new. In schimb.lipseste instantierea 2.2. CICLUL DE VIATA AL UNUI OBIECT ¸˘ 37 Spatiul de memorie nu este pre-alocat ¸ Declararea unui obiect nu implic˘ sub nici o form˘ alocarea de spatiu a a ¸ de memorie pentru acel obiect. 20).width).println(patrat.x = 10.

Referintele (care sunt de fapt varia ¸a ¸ abile) sunt distruse dou˘ moduri: a • natural. ın a • explicit. atunci cˆnd variabila respectiv˘ iese din domeniul s˘u de viza a a ibilitate.1. OBIECTE SI CLASE ¸ obiectului trebuie s˘ existe metode care s˘ permit˘ schimbarea/aflarea vala a a orilor variabilelor sale.width = -100. ˆ momentul rul˘rii unui program.getter ¸i au numele de forma setVariabila. cele care au r˘mas nemarcate sunt a a eliminate automat din memorie. scaneaz˘ dinamic memoria ocupat˘ de programul Java aflat a a a ˆ executie ¸i marcheaz˘ acele obiecte care au referinte directe sau indirecte.setSize(-100. simultan cu interpretorul a ın a Java. respectiv getVariabila. //stare inconsistenta patrat. s patrat. Acest proces pus la dispozitie de platforma Java de lucru ¸ se nume¸te garbage collector (colector de gunoi). a Cum functioneaz˘ colectorul de gunoaie ? ¸ a Colectorul de gunoaie este un proces de prioritate scazut˘ care se exea cut˘ periodic. prescurtat gc. //metoda setter //metoda setSize poate sa testeze daca noile valori sunt //corecte si sa valideze sau nu schimbarea lor 2. . de exemplu la terminarea metodei ˆ care ea a fost declarat˘. sau metode setter . -200). Acestea se numesc metode de accesare. s Un obiect este eliminat din memorie de procesul de colectare atunci cˆnd a nu mai exist˘ nici o referint˘ la acesta. s a a ın a cu alte cuvinte s˘ administreze singur memoria ocupat˘ de obiectele sale.3 Distrugerea obiectelor Multe limbaje de programare impun ca programatorul s˘ ¸in˘ evidenta obiectelor at a ¸ create ¸i s˘ le distrug˘ ˆ mod explicit atunci cˆnd nu mai este nevoie de ele. dac˘ atribuim variabilei respective valoare null. ¸ a In Java programatorul nu mai are responsabilitatea distrugerii obiectelor sale ˆ ıntrucˆt. ruleaz˘ ¸i un proces care se ocup˘ cu distrugerea obiectelor care nu a s a mai sunt folosite. a a Practica a demonstrat c˘ aceast˘ tehnic˘ este una din principalele furnizoare a a a de erori ce duc la functionarea defectuoas˘ a programelor. ın ¸ s a ¸ Dup˘ ce toate obiectele au fost parcurse.38 CAPITOLUL 2.

Ace¸tia s ¸ a s sunt: . apelˆnd metoda de finalizare a obieca ¸ a a tului respectiv. f˘r˘ a forta ˆ a pornirea procesului. Codul pentru finalizarea unui obiect trebuie scris ˆ ıntr-o metod˘ special˘ a a numita finalize a clasei ce descrie obiectul respectiv. ˆ timpul finaliz˘rii un obiect ˆsi inchide fisierele ¸i ın a ı¸ s socket-urile folosite.1 Crearea claselor Declararea claselor Clasele reprezint˘ o modalitate de a introduce noi tipuri de date ˆ a ıntr-o aplicatie Java.2. etc. aa ¸ ıns˘ Finalizare Inainte ca un obiect s˘ fie eliminat din memorie. CREAREA CLASELOR 39 Apelul metodei gc din clasa System sugereaz˘ ma¸inii virtuale Java s˘ a s a ”depun˘ eforturi” ˆ recuperarea memoriei ocupate de obiecte care nu mai a ın sunt folosite. prima parte a declaratiei o ocup˘ modificatorii clasei. (vezi ”Clasa Object”) Atentie ¸ Nu confundati metoda finalize din Java cu destructorii din C++.. Uzual. cealalt˘ modalitate fiind prin intermediul interfetelor.. ]] { // Corpul clasei } A¸adar. procesul gc d˘ acelui a a obiect posibilitatea ”s˘ curete dup˘ el”.2 2. Metoda finalize nu are rolul de a distruge obiectul ci este apelat˘ automat ˆ a ınainte de eliminarea obiectului respectiv din memorie.2. Declararea ¸ a ¸ unei clase respect˘ urm˘torul format general: a a [public][abstract][final]class NumeClasa [extends NumeSuperclasa] [implements Interfata1 [. Interfata2 .2. distruge referintele c˘tre alte obiecte (pentru a u¸sura ¸ a s sarcina colectorului de gunoaie). 2.

o clas˘ poate fi folosit˘ doar de clasele aflate ˆ acela¸i paa a ın s chet(libr˘rie) cu clasa respectiv˘ (dac˘ nu se specific˘ un anume paa a a a chet. – programare ˆn spririt orientat-obiect: O clasa ”perfect˘” nu treı a buie s˘ mai aib˘ subclase. Object a a a s este singura clas˘ care nu are p˘rinte. Java permite doar mo¸tenirea simpl˘. a ın a s • abstract Declar˘ o clas˘ abstract˘ (¸ablon). de unde rezult˘ c˘ multimea tuturor claselor definite ˆ Java poate fi a a ¸ ın vazut˘ ca un arbore. O clas˘ declarat˘ cu public poate fi folosit˘ din orice alt˘ a a a a clas˘. ceea ce ˆ s a ıneamn˘ c˘ o clas˘ poate avea un singur a a a p˘rinte (superclas˘). ale c˘ror nume trebuie separate a ¸ a prin virgul˘. faptul c˘ respectiva a a a clas˘ este subclas˘ a unei alte clase cu numele NumeSuperclasa sau/¸i c˘ a a s a implementeaz˘ una sau mai multe interfete. (vezi ”Clase ¸i metode abstracte”) s • final Declar˘ c˘ respectiva clas˘ nu poate avea subclase. dac˘ este cazul.40 CAPITOLUL 2. O clas˘ abstract˘ nu poate fi a a a s a a instantiat˘. Declarare claselor a a a finale are dou˘ scopuri: a – securitate: unele metode pot a¸tepta ca parametru un obiect al s unei anumite clase ¸i nu al unei subclase. A¸adar. fiind foarte important˘ ˆ modul de a a a ın lucru cu obiecte si structuri de date ˆ Java. indiferent de pachetul ˆ care se g˘se¸te. OBIECTE SI CLASE ¸ • public Implicit. fiind folosit˘ doar pentru a crea un model comun pentru o ¸ a a serie de subclase.2. a a Dup˘ numele clasei putem specifica. ın ˆ felul acesta nu s-ar mai putea realiza obiectivul limbajului Java ın ca un program care a trecut compilarea s˘ nu mai fie susceptibil a de nici o eroare. ın . toate clasele din directorul curent sunt considerate a fi ˆ acela¸i ın s pachet). Evident. r˘d˘cina acestuia fiind clasa Object. dar tipul exact al unui s obiect nu poate fi aflat cu exactitate decat ˆ momentul executiei.2 Extinderea claselor Spre deosebire de alte limbaje de programare orientate-obiect. a 2. o clas˘ poate avea oricˆti mo¸tenitori (suba a a a s clase).

} // A este superclasa clasei B // B este o subclasa a clasei A 41 O subclas˘ mo¸tene¸te de la p˘rintele s˘u toate variabilele ¸i metodele a s s a a s care nu sunt private. CREAREA CLASELOR Extinderea unei clase se realizeaz˘ folosind cuvˆntul cheie extends: a a class B extends A {. initializarea variabilelor de instant˘ ¸i de clas˘ s ¸ ¸a s a (cunoscute ˆ ımpreun˘ ca variabile membre). urmˆnd ca implementare s˘ fie facut˘ ˆ afara ei. Spre deosebire de C++. Implementarea a a a ın metodelor unei clase trebuie s˘ se fac˘ obligatoriu ˆ corpul clasei. a • Declararea unor clase imbricate (interne).. a • Declararea ¸i implementarea constructorilor. s • Declararea ¸i implementarea metodelor de instanta ¸i de clas˘ (cunoss ¸ s a cute ˆ ımpreun˘ ca metode membre).2.. eventual. Continutul acestuia este format din: ¸ • Declararea ¸i.2. 2. int metoda2() { // Implementare } } A::metoda1() { // Implementare } . a a ın // C++ class A { void metoda1(). nu este permis˘ doar declararea metodei ˆ corpul a ın clasei.3 Corpul unei clase Corpul unei clase urmeaz˘ imediat dup˘ declararea clasei ¸i este cuprins ˆ a a s ıntre acolade.2.

42 // Java class A { void metoda1(){ // Implementare } void metoda2(){ // Implementare } } CAPITOLUL 2. nu returneaz˘ nici o valoare ¸i sunt folositi pentru initializarea a s ¸ ¸ obiectelor acelei clase ˆ momentul instantierii lor. void A() {}.2. s a 2. f˘r˘ a exista posibilitatea aparitiei vreunei ambiguit˘¸i aa ¸ at din punctul de vedere al compilatorului. OBIECTE SI CLASE ¸ Variabilele unei clase pot avea acela¸i nume cu metodele clasei. a a at at dovedind un stil ineficient de progamare. care poate s fi chiar numele clasei. class A { int A. // Corect pentru compilator // Nerecomandat ca stil de programare } Atentie ¸ Variabilele ¸i metodele nu pot avea ca nume un cuvˆnt cheie Java. ın ¸ class NumeClasa { [modificatori] NumeClasa([argumente]) { // Constructor . Acest lucru este ˆ a total nereıns˘ comandat dac˘ ne gˆndim din perspectiva lizibilit˘¸ii (clarit˘¸ii) codului.4 Constructorii unei clase Constructorii unei clase sunt metode speciale care au acela¸i nume cu cel s al clasei.

Aceast˘ metod˘ este folosit˘ atunci cˆnd sunt implementati mai multi a a a a ¸ ¸ constructori pentru o clas˘. double h1) { // Constructor cu doua argumente x=0. y. pentru a nu repeta secventele de cod scrise deja a ¸ la constructorii cu mai multe argumente (mai generali). h=h1. S˘ consider˘m ca exemplu declararea unei clase care descrie notiunea de a a ¸ dreptunghi ¸i trei posibili constructori pentru aceasta clas˘. h. w. Mai eficient. y=0. w=w1. w=w1. ˆ functie de num˘rul para¸ a ın ¸ a metrilor cu care este apelat constructorul. y=0. y=y1.out. } Dreptunghi() { // Constructor fara argumente x=0. System. } Dreptunghi(double w1. h=h1.out. f˘r˘ aa . System. s a class Dreptunghi { double x.println("Instantiere dreptunghi").println("Instantiere dreptunghi"). double w1. care apeleaz˘ constructorul corespunz˘tor (ca argumente) al clasei respeca a tive. double y1. w=0.println("Instantiere dreptunghi"). double h1) { // Cel mai general constructor x=x1. h=0.2. CREAREA CLASELOR } } 43 O clas˘ poate avea unul sau mai multi constructori care trebuie ˆ a s˘ a ¸ ıns˘ a difere prin lista de argumente primite.out. In cazul ¸ ¸ ˆ care dorim s˘ apel˘m explicit constructorul unei clase folosim expresia ın a a this( argumente ).2. System. Dreptunghi(double x1. } } Constructorii sunt apelati automat la instantierea unui obiect. In felul acesta sunt permise diverse tipuri de initializ˘ri ale obiectelor la crearea lor.

double h1) { // Implementam doar constructorul cel mai general x=x1. clasa de mai sus poate fi rescris˘ astfel: a class Dreptunghi { double x. 0.out. w=w1. double y. double d) { super(x. double h1) { this(0. // Apelam constructorul cu 4 argumente } Dreptunghi() { this(0. h=h1. a ¸ .println("Instantiere dreptunghi"). y. S˘ presupunem c˘ dorim s˘ cre˘m clasa Patrat. d. double y1. OBIECTE SI CLASE ¸ a repeta acelea¸i secvente de cod ˆ toti constructorii (cum ar fi afi¸area s ¸ ın ¸ s mesajului ”Instantiere dreptunghi”). System. 0). y=y1. w. h. derivat˘ din clasa Dreptunghi: a a a a a class Patrat extends Dreptunghi { Patrat(double x. // Apelam constructorul cu 2 argumente } } Dintr-o subclas˘ putem apela explicit constructorii superclasei cu expresia a super( argumente ).44 CAPITOLUL 2. d). Dreptunghi(double x1. y. // Apelam constructorul superclasei } } Atentie ¸ Apelul explcit al unui constructor nu poate ap˘rea decˆt ˆ a a ıntr-un alt constructor si trebuie s˘ fie prima instructiune din constructorul respectiv. h1). } Dreptunghi(double w1. w1. double w1.

double y. 100). instantierea unui obiect din clasa extins˘ s ¸ a implic˘ instantierea unui obiect din clasa p˘rinte. // Varianta corecta In cazul mo¸tenirii unei clase. y. } S˘ consider˘m acum dou˘ instantieri ale claselor de mai sus: a a a ¸ Dreptunghi d = new Dreptunghi(). // Corect (a fost generat constructorul implicit) Cerc c. // Constructor cu 3 argumente Cerc(double x.2. r. // Nici un constructor } class Cerc { double x. w. h. }.. S˘ consider˘m. a a a urm˘toarele declaratii de clase: a ¸ class Dreptunghi { double x. y. Din acest motiv. CREAREA CLASELOR 45 Constructorul implicit Constructorii sunt apelati automat la instantierea unui obiect. fiecare a ¸ a constructor al clasei fiu va trebui s˘ aib˘ un constructor cu aceea¸i signatur˘ a a s a ˆ p˘rinte sau s˘ apeleze explicit un constructor al clasei extinse folosind ın a a expresia super([argumente]). Dac˘ ˆ a scriem un constructor pentru o clas˘. sistemul ˆ ın a ıi creeaz˘ automat un constructor implicit. atunci constructorul implicit (f˘r˘ nici un argument) aa nu va mai fi furnizat implicit de c˘tre sistem.2. In cazul ¸ ¸ ˆ care scriem o clas˘ care nu are declarat nici un constructor. ˆ caz contrar fiind semnalat˘ o eroare la ın a compilare. 0. c = new Cerc(). care nu prime¸te nici un argument a s ¸i care nu face nimic. care are mai a ıns˘ a mult de un argument. Deci prezenta constructorilor ˆ corpul unei clase nu s ¸ ın este obligatorie. double r) { . ca exemplu. // Eroare la compilare ! c = new Cerc(0. ..

de¸i acest lucru nu este impus de c˘tre compilator. s a . O asta a ¸ fel de clas˘ poate contine metode publice (numite ”factory methods”) a ¸ care s˘ fie responsabile cu crearea obiectelor. private ¸i cel implicit.x = x.2. s • public In orice alt˘ clas˘ se pot crea instante ale clasei respective.46 class A { int x=1.x = x.} C(int x) {super. OBIECTE SI CLASE ¸ Constructorii unei clase pot avea urm˘torii modificatori de acces: a public.} } CAPITOLUL 2. a a ¸ • protected Doar ˆ subclase pot fi create obiecte de tipul clasei respective. A(int x) { this. controlˆnd ˆ felul acesta a a ın diverse aspecte legate de instantierea clasei respective.} } class C extends A { // Eroare la compilare ! C() {super.x = 2. protected.} B(int x) {super. ¸ • implicit Doar ˆ clasele din acela¸i pachet se pot crea instante ale clasei respecın s ¸ tive.5 Declararea variabilelor Variabilele membre ale unei clase se declar˘ de obicei ˆ a ınaintea metodelor.x = x.} } class B extends A { // Corect B() {super(2). ın • private In nici o alt˘ clas˘ nu se pot instantia obiecte ale acestei clase. 2.

fiind vizibile ˆ toate metodele respectivei clase. final. final static long MAX = 100000L. private Point p = new Point(10. private (vezi ”Modificatori de acces pentru membrii unei clase”) • unul din cuvintele rezervate: static.2. } . protected static int n. unde un modificator poate fi : • un modificator de acces : public.2. protected. Variabilele ın declarate ˆ cadrul unei metode sunt locale metodei respective. volatile Exemple de declaratii de variabile membre: ¸ class Exemplu { double x. o variabil˘ se declar˘ astfel: a a [modificatori] Tip numeVariabila [ = valoareInitiala ]. public String s = "abcd". transient. 10). ın Declararea unei variabile presupune specificarea urm˘toarelor lucruri: a • numele variabilei • tipul de date al acesteia • nivelul de acces la acea variabila din alte clase • dac˘ este constant˘ sau nu a a • dac˘ este variabil˘ de instant˘ sau de clas˘ a a ¸a a • alti modificatori ¸ Generic. CREAREA CLASELOR class NumeClasa { // Declararea variabilelor // Declararea metodelor } 47 Variabilele membre ale unei clase se declar˘ ˆ corpul clasei ¸i nu ˆ corpul a ın s ın unei metode.

ci poate fi specificat˘ ¸i ulterior ˆ ın as ıntr-un constructor.141.14 . Test() { MAX = 100.48 CAPITOLUL 2. altii a a ¸ a ¸ decˆt cei de acces care sunt tratati ˆ a ıntr-o sectiune separata: ”Specificatori ¸ de acces pentru membrii unei clase”. a a class Test { final int MAX. // Eroare la compilare ! } } • transient Este folosit la serializarea obiectelor. PI = 3. dup˘ care ea nu va mai putea fi modificat˘. (vezi ”Serializarea a obiectelor”) . numele variabilelor finale se scriu cu litere mari. ˆ sensul a ın ın c˘ valoarea unei variabile nu trebuie specificat˘ neap˘rat la declararea a a a ei (ca ˆ exemplul de mai sus). • static Prezenta lui declar˘ c˘ o variabil˘ este variabil˘ de clas˘ ¸i nu de ¸ a a a a a s instant˘. static int variabilaClasa. final double PI = 3.. . // Corect MAX = 200.. OBIECTE SI CLASE ¸ S˘ analiz˘m modificatorii care pot fi specificati pentru o variabil˘. // Eroare la compilare ! Prin conventie. • final Indic˘ faptul c˘ valoarea variabilei nu mai poate fi schimbat˘. cu alte a a a cuvinte este folosit pentru declararea constantelor. pentru a specifica ce variabile membre ale unui obiect nu particip˘ la serializare. (vezi ”Membri de instanta ¸i membri de clas˘”) ¸a ¸ s a int variabilaInstanta . Folosirea ¸ lui final aduce o flexibilitate sporit˘ ˆ lucrul cu constante.

Dup˘ cum am v˘zut.2.6 this ¸i super s Sunt variabile predefinite care fac referinta. } B(int x) { super(x). } } class B extends A { B() { this(0). .2. } void metoda() { super. respectiv ai superclasei class A { int x. la obiectul ¸ ın propriu-zis (this).out.2.metoda(). Sunt folosite ¸ a ˆ general pentru a rezolva conflicte de nume prin referirea explicit˘ a unei ın a variabile sau metode membre. } void metoda() { x ++. utilizate sub form˘ de a a a metode au rolul de a apela constructorii corespunz˘tori ca argumente ai clasei a curente. respectiv la instanta p˘rintelui (super). 2.x = x. } A(int x) { this. System. Este o facilitate avansat˘ a a a limbajului Java. A() { this(0).println(x). ˆ cadrul unui obiect. CREAREA CLASELOR 49 • volatile Este folosit pentru a semnala compilatorului s˘ nu execute anumite a optimiz˘ri asupra membrilor unei clase.

} } CAPITOLUL 2. altii a a ¸ a ¸ decˆt cei de acces care sunt tratati ˆ a ¸ ıntr-o sectiune separat˘. OBIECTE SI CLASE ¸ 2.50 System.1 Implementarea metodelor Declararea metodelor Metodele sunt responsabile cu descrierea comportamentului unui obiect. (vezi ”Clase ¸i metode abstracte”) a a s . o metod˘ se declar˘ astfel: a ın a a [modificatori] TipReturnat numeMetoda ( [argumente] ) [throws TipExceptie1. private (vezi ”Specificatori de acces pentru membrii unei clase”) • unul din cuvintele rezervate: static.] { // Corpul metodei } unde un modificator poate fi : • un specificator de acces : public.3.println(x). synchronized S˘ analiz˘m modificatorii care pot fi specificati pentru o metod˘. • abstract Permite declararea metodelor abstracte. final. (vezi ¸ a a a as ¸a ”Membri de instanta ¸i membri de clas˘”) ¸ s a void metodaInstanta()..3 2. metodele a se pot g˘si doar ˆ cadrul claselor. . ¸ a • static Prezenta lui declar˘ c˘ o metod˘ este de clas˘ ¸i nu de instant˘. O metod˘ abstract˘ este o a a metod˘ care nu are implementare ¸i trebuie obligatoriu s˘ fac˘ parte a s a a dintr-o clas˘ abstract˘. native. TipExceptie2. abstract. Generic. protected. static void metodaClasa(). Intrucˆt Java este un limbaj de programare complet orientat-obiect.out..

fiind critic˘ pentru consistenta a a ın a ¸ st˘rii unui obiect. indiferent de facultatea la care sunt. } class StudentInformatica extends Student { float calcMedie(float note[]. IMPLEMENTAREA METODELOR 51 • final Specific˘ faptul c˘ acea metoda nu mai poate fi supradefinit˘ ˆ suba a a ın clasele clasei ˆ care ea este definit˘ ca fiind final˘... ¸ • synchronized Este folosit ˆ cazul ˆ care se lucreaz˘ cu mai multe fire de executie iar ın ın a ¸ metoda respectiv˘ gestioneaz˘ resurse comune. ın ¸ ¸ ˆ aceea¸i manier˘. (vezi ”Fire de executie”) a ¸ . ˆ functie de notele obtinute la examene. De exemplu. } }// Eroare la compilare ! • native In cazul ˆ care avem o libr˘rie important˘ de functii scrise ˆ alt limbaj ın a a ¸ ın de programare. acestea s pot fi refolosite din programele Java.. float ponderi[]) { return 10.3. Acest lucru este ın a a util dac˘ respectiva metod˘ are o implementare care nu trebuie schima a bat˘ sub nici o form˘ ˆ subclasele ei. final float calcMedie(float note[]. Are ca efect construirea a a unui monitor care nu permite executarea metodei. cum ar fi C.. la un moment dat. float ponderi[]) { .. } .2. ın s a class Student { . studentilor unei universit˘¸i trebuie s˘ a ¸ at a li se calculeze media finala. C++ ¸i limbajul de asamblare..00. Tehnologia care permite acest lucru se nume¸te JNI (Java Native Interface) ¸i permite asocierea dintre s s metode Java declarate cu native ¸i metode native scrise ˆ limbajele s ın de programare mentionate. decˆt unui singur fir de executie.

a ¸a In cazul ˆ care o metod˘ nu returneaz˘ nimic atunci trebuie obligatoriu ın a a specificat cuvˆntul cheie void ca tip returnat: a public void afisareRezultat() { System.. // Eroare } int metoda() { . } Dac˘ o metod˘ trebuie s˘ returneze o valoare acest lucru se realizeaz˘ prin a a a a intermediul instructiunii return. ¸ double radical(double x) { if (x >= 0) return Math. OBIECTE SI CLASE ¸ 2. } private void deseneaza(Shape s) { .println("Argument negativ !").3. Tipul returnat a poate fi atˆt un tip primitiv de date sau o referint˘ la un obiect al unei clase.2 Tipul returnat de o metod˘ a Metodele pot sau nu s˘ returneze o valoare la terminarea lor.52 CAPITOLUL 2.out.2. altfel va fi furnizat˘ o eroare la compilare.out. a a orice atribuire care implic˘ pierderi de date este tratat˘ de compilator ca a a eroare.println("rezultat"). In general. // Eroare la compilare // Lipseste return pe aceasta ramura } } In cazul ˆ care ˆ declaratia functiei tipul returnat este un tip primitiv de ın ın ¸ ¸ date. valoarea returnat˘ la terminarea functiei trebuie s˘ aib˘ obligatoriu acel a ¸ a a tip sau un subtip al s˘u. int metoda() { return 1. return. care trebuie s˘ apar˘ ˆ toate situatiile de ¸ a a ın ¸ terminare a functiei. else { System..sqrt(x).

// Corect else return t. if (.) return p. Patrat t = new Patrat(). Tip2 arg2.. // Corect } double metoda() { return (float)1.) return p. if (. // Eroare else return t. atunci a a ¸a clasa obiectului returnat trebuie s˘ coincid˘ sau s˘ fie o subclas˘ a clasei a a a a specificate la declararea metodei.. // Corect } Patrat metoda2( ) { Poligon p = new Poligon().2. atˆt tip primitiv cˆt ¸i tip referint˘. a a s ¸a TipReturnat metoda([Tip1 arg1.3. Poligon metoda1( ) { Poligon p = new Poligon(). IMPLEMENTAREA METODELOR return (int)1. . // Corect } 53 Dac˘ valoarea returnat˘ este o referint˘ la un obiect al unei clase. Tipul de date al unui argument poate fi orice tip valid al a limbajului Java.. // Corect } 2.]) Exemplu: . fie clasa Poligon ¸i subclasa s acesteia Patrat.2.3 Trimiterea parametrilor c˘tre o metod˘ a a Signatura unei metode este dat˘ de numarul ¸i tipul argumentelor primite a s de acea metod˘... Patrat t = new Patrat().3. De exemplu..

float salariu) // String este tip referinta // int si float sunt tipuri primitive Spre deosebire de alte limbaje. ˆ Java nu pot fi trimise ca parametri ai ın unei metode referinte la alte metode (functii). a ¸ a Pˆna la aparitia versiunii 1. ˆ Java o metod˘ nu putea primi un num˘r a ¸ ın a a variabil de argumente. metoda nu poate schimba valoarea a ¸a referintei obiectului. Pot ˆ a s˘ a ıns˘ a coincid˘ cu numele variabilelor membre ale clasei. Cˆnd argumentul este de tip referint˘. Acest lucru ˆ ınseamn˘ c˘ metoda receptioneaz˘ doar valorile variabilelor prima a ¸ a ite ca parametri. modific˘rile f˘cute ˆ cadrul metodei fia a ın ind pierdute. ˆ a poate apela metodele acelui obiect ¸i poate modifica ¸ ıns˘ s orice variabil˘ membr˘ accesibil˘. int y. ˆ a pot fi trimise referinte la ¸ ¸ ıns˘ ¸ obiecte care s˘ contin˘ implementarea acelor metode.54 CAPITOLUL 2.5. public Cerc(int x. raza. metoda nu-i poate schimba vala oarea decˆt local (ˆ cadrul metodei). Cˆnd argumentul are tip primitiv de date. caz ˆ care diferentierea a ın ¸ dintre ele se va face prin intermediul variabile this. Vom anala a s iza ˆ ıntr-o sectiune separat˘ modalitate de specificare a unui num˘r variabil ¸ a a de argumente pentru o metod˘.x = x. a Numele argumentelor primite trebuie s˘ difere ˆ a ıntre ele ¸i nu trebuie s˘ cos a incid˘ cu numele nici uneia din variabilele locale ale metodei. OBIECTE SI CLASE ¸ void adaugarePersoana(String nume. pentru a fi apelate. la revenirea din metod˘ variabila are a ın a aceea¸i valoare ca ˆ s ınaintea apelului. y. int raza) { this. ceea ce ˆ ınseamna c˘ apelul unei metode trebuia s˘ se a a fac˘ cu specificarea exact˘ a numarului ¸i tipurilor argumentelor. } } In Java argumentele sunt trimise doar prin valoare (pass-by-value). a a a A¸adar. a ¸a . this. atunci el trebuie s˘ fie neaparat de tip referint˘. dac˘ dorim ca o metod˘ s˘ schimbe starea (valoarea) unui argus a a a ment primit. class Cerc { int x.raza = raza. int varsta. this.y = y.

Pentru a rezolva lucrul propus trebuie s˘ definim o clas˘ suplimentar˘ a a a care s˘ descrie parametrii pe care dorim s˘-i afl˘m: a a a // Varianta corecta class Param { public int x.x = x. int valr) { // Metoda nu are efectul dorit! valx = x. raza. int valy.y = y. y. a a a // Varianta incorecta: class Cerc { private int x. In concluzie. public void aflaParametri(int valx. valy = y. raza. de¸i nu ˆ schimb˘m valoarea (val¸a s s ıi a oarea sa este adresa de memorie la care se gase¸te ¸i nu poate fi schimbat˘). metoda ıncˆ a a nu realizeaz˘ nimic pentru c˘ nu poate schimba valorile variabilelor primite a a ca argumente.raza = raza. IMPLEMENTAREA METODELOR 55 De exemplu. y. valy ¸i valr ¸i nu referinte la ele (adresele lor s s ¸ de memorie). s s a . astfel ˆ at s˘ le poat˘ modifica valorile. public void aflaParametri(Param param) { param. s˘ consider˘m clasa Cerc descris˘ anterior ˆ care dorim s˘ a a a ın a implement˘m o metod˘ care s˘ returneze parametrii cercului.3. param.2. } class Cerc { private int x. param. } } Aceast˘ metod˘ nu va realiza lucrul propus ˆ a a ıntrucˆt ea prime¸te doar a s valorile variabilelor valx. raza. valr = raza. } } Argumentul param are tip referint˘ ¸i. y.

. Noutatea const˘ a a a a ˆ folosirea simbolului .. args) args reprezint˘ un vector avˆnd tipul specificat ¸i instantiat cu un num˘r a a s ¸ a variabil de argumente.56 CAPITOLUL 2.out. adic˘ informatia propriu-zis˘ continut˘ de a ¸ a ¸ a acesta.. Pentru a afla ˆ a valorile variabilelor care descriu ıns˘ starea unui obiect se folosesc metode de tip getter ˆ ¸ite de metode setter ınsot care s˘ permit˘ schimbarea st˘rii obiectului: a a a class Cerc { private int x.5 a limbajului Java. "Java". i<args. metoda("Hello". i++) System.. metoda("Hello"). } public void setX(int x) { this. Metoda de mai jos afi¸eaz˘ argumentele prim¸a s a ite. . public int getX() { return x. exist˘ posibilitate de a declara a a metode care s˘ primeasc˘ un num˘r variabil de argumente.3. ˆ functie de apelul metodei. Varianta de mai sus a fost dat˘ pentru a clarifica modul de trimitere a a argumentelor unei metode. sintaxa unei astfel de metode fiind: ın [modificatori] TipReturnat metoda(TipArgumente .. } . } .4 Metode cu num˘r variabil de argumente a Incepˆnd cu versiunea 1. } 2. raza. y. OBIECTE SI CLASE ¸ putem schimba starea obiectului. args) { for(int i=0.println(args[i]).....5). care pot fi de orice tip: void metoda(Object .length... 1.x = x. Tipul argumentelor ın ¸ poate fi referint˘ sau primitiv.

2.3. IMPLEMENTAREA METODELOR

57

2.3.5

Supraˆ arcarea ¸i supradefinirea metodelor ınc˘ s

Supraˆ arcarea ¸i supradefinirea metodelor sunt dou˘ concepte extrem de ınc˘ s a utile ale program˘rii orientate obiect, cunoscute ¸i sub denumirea de polimora s fism, ¸i se refer˘ la: s a • supraˆncarcarea (overloading) : ˆ cadrul unei clase pot exista metode ı ın cu acela¸i nume cu conditia ca signaturile lor s˘ fie diferite (lista de s ¸ a argumente primite s˘ difere fie prin num˘rul argumentelor, fie prin a a tipul lor) astfel ˆ at la apelul functiei cu acel nume s˘ se poat˘ stabili ıncˆ ¸ a a ˆ mod unic care dintre ele se execut˘. ın a • supradefinirea (overriding): o subclas˘ poate rescrie o metod˘ a claa a sei p˘rinte prin implementarea unei metode cu acela¸i nume ¸i aceea¸i a s s s signatur˘ ca ale superclasei. a class A { void metoda() { System.out.println("A: metoda fara parametru"); } // Supraincarcare void metoda(int arg) { System.out.println("A: metoda cu un parametru"); } } class B extends A { // Supradefinire void metoda() { System.out.println("B: metoda fara parametru"); } } O metod˘ supradefinit˘ poate s˘: a a a • ignore complet codul metodei corespunz˘toare din superclas˘ (cazul a a de mai sus): B b = new B(); b.metoda(); // Afiseaza "B: metoda fara parametru"

58

CAPITOLUL 2. OBIECTE SI CLASE ¸ • extind˘ codul metodei p˘rinte, executˆnd ˆ a a a ınainte de codul propriu ¸i s functia p˘rintelui: ¸ a class B extends A { // Supradefinire prin extensie void metoda() { super.metoda(); System.out.println("B: metoda fara parametru"); } } . . . B b = new B(); b.metoda(); /* Afiseaza ambele mesaje: "A: metoda fara parametru" "B: metoda fara parametru" */

O metod˘ nu poate supradefini o metod˘ declarat˘ final˘ ˆ clasa p˘rinte. a a a a ın a Orice clas˘ care nu este abstract˘ trebuie obligatoriu s˘ supradefineasc˘ a a a a metodele abstracte ale superclasei (dac˘ este cazul). In cazul ˆ care o clas˘ a ın a nu supradefine¸te toate metodele abstracte ale p˘rintelui, ea ˆ a¸i este abs a ıns˘s stract˘ ¸i va trebui declarat˘ ca atare. as a In Java nu este posibil˘ supraˆ arcarea operatorilor. a ınc˘

2.4

Modificatori de acces

Modificatorii de acces sunt cuvinte rezervate ce controleaz˘ accesul celora late clase la membrii unei clase. Specificatorii de acces pentru variabilele ¸i metodele unei clase sunt: public, protected, private ¸i cel implicit (la s s nivel de pachet), iar nivelul lor de acces este dat ˆ tabelul de mai jos: ın Specificator Clasa Sublasa Pachet Oriunde private X protected X X* X public X X X X implicit X X

˘ 2.5. MEMBRI DE INSTANTA SI MEMBRI DE CLASA ¸˘ ¸

59

A¸adar, dac˘ nu este specificat nici un modificator de acces, implicit s a nivelul de acces este la nivelul pachetului. In cazul ˆ care declar˘m un ın a membru ”protected” atunci accesul la acel membru este permis din subclasele clasei ˆ care a fost declarat dar depinde ¸i de pachetul ˆ care se gase¸te ın s ın s subclasa: dac˘ sunt ˆ acela¸i pachet accesul este permis, dac˘ nu sunt ˆ a ın s a ın acela¸i pachet accesul nu este permis decˆt pentru obiecte de tipul subclasei. s a Exemple de declaratii: ¸ private int secretPersonal; protected String secretDeFamilie; public Vector pentruToti; long doarIntrePrieteni; private void metodaInterna(); public String informatii();

2.5

Membri de instant˘ ¸i membri de clas˘ ¸a s a

O clas˘ Java poate contine dou˘ tipuri de variabile ¸i metode : a ¸ a s • de instant˘: declarate f˘r˘ modificatorul static, specifice fiec˘rei ¸a a a a instante create dintr-o clas˘ ¸i ¸ as • de clas˘: declarate cu modificatorul static, specifice clasei. a

2.5.1

Variabile de instant˘ ¸i de clas˘ ¸a s a

Cˆnd declar˘m o variabil˘ membr˘ f˘r˘ modificatorul static, cum ar fi x ˆ a a a a aa ın exemplul de mai jos: class Exemplu { int x ; //variabila de instanta } se declar˘ de fapt o variabil˘ de instant˘, ceea ce ˆ a a ¸a ınseamn˘ c˘ la fiecare creare a a a unui obiect al clasei Exemplu sistemul aloc˘ o zon˘ de memorie separat˘ a a a pentru memorarea valorii lui x. Exemplu o1 = new Exemplu(); o1.x = 100;

60

CAPITOLUL 2. OBIECTE SI CLASE ¸ Exemplu o2 = new Exemplu(); o2.x = 200; System.out.println(o1.x); // Afiseaza 100 System.out.println(o2.x); // Afiseaza 200

A¸adar, fiecare obiect nou creat va putea memora valori diferite pentru s variabilele sale de instant˘. ¸a Pentru variabilele de clas˘ (statice) sistemul aloc˘ o singur˘ zon˘ de mema a a a orie la care au acces toate instantele clasei respective, ceea ce ˆ ¸ ınseamn˘ c˘ a a dac˘ un obiect modific˘ valoarea unei variabile statice ea se va modifica ¸i a a s pentru toate celelalte obiecte. Deoarece nu depind de o anumit˘ instanta a a ¸˘ unei clase, variabilele statice pot fi referite ¸i sub forma: s NumeClasa.numeVariabilaStatica class Exemplu { int x ; // Variabila de static long n; // Variabila de } . . . Exemplu o1 = new Exemplu(); Exemplu o2 = new Exemplu(); o1.n = 100; System.out.println(o2.n); o2.n = 200; System.out.println(o1.n); System.out.println(Exemplu.n); // o1.n, o2.n si Exemplu.n sunt

instanta clasa

// Afiseaza 100 // Afiseaza 200 // Afiseaza 200 referinte la aceeasi valoare

Initializarea variabilelor de clas˘ se face o singur˘ dat˘, la ˆ arcarea ˆ ¸ a a a ınc˘ ın memorie a clasei respective, ¸i este realizat˘ prin atribuiri obi¸nuite: s a s class Exemplu { static final double PI = 3.14; static long nrInstante = 0; static Point p = new Point(0,0); }

˘ 2.5. MEMBRI DE INSTANTA SI MEMBRI DE CLASA ¸˘ ¸

61

2.5.2

Metode de instant˘ ¸i de clas˘ ¸a s a

Similar ca la variabile, metodele declarate f˘r˘ modificatorul static sunt aa metode de instant˘ iar cele declarate cu static sunt metode de clas˘ (stat¸a a ice). Diferenta ˆ ¸ ıntre cele dou˘ tipuri de metode este urm˘toarea: a a • metodele de instant˘ opereaz˘ atˆt pe variabilele de instant˘ cˆt ¸i pe ¸a a a ¸a a s cele statice ale clasei; • metodele de clas˘ opereaz˘ doar pe variabilele statice ale clasei. a a class Exemplu { int x ; // Variabila de instanta static long n; // Variabila de clasa void metodaDeInstanta() { n ++; // Corect x --; // Corect } static void metodaStatica() { n ++; // Corect x --; // Eroare la compilare ! } } Intocmai ca ¸i la variabilele statice, ˆ s ıntrucˆt metodele de clas˘ nu depind a a de starea obiectelor clasei respective, apelul lor se poate face ¸i sub forma: s NumeClasa.numeMetodaStatica Exemplu.metodaStatica(); // Corect, echivalent cu Exemplu obj = new Exemplu(); obj.metodaStatica(); // Corect, de asemenea Metodele de instant˘ nu pot fi apelate decˆt pentru un obiect al clasei ¸a a respective: Exemplu.metodaDeInstanta(); // Eroare la compilare ! Exemplu obj = new Exemplu(); obj.metodaDeInstanta(); // Corect

62

CAPITOLUL 2. OBIECTE SI CLASE ¸

2.5.3

Utilitatea membrilor de clas˘ a

Membrii de clas˘ sunt folositi pentru a pune la dispozitie valori ¸i metode a ¸ ¸ s independente de starea obiectelor dintr-o anumita clas˘. a

Declararea eficient˘ a constantelor a S˘ consider˘m situatia cˆnd dorim s˘ declar˘m o constant˘. a a ¸ a a a a class Exemplu { final double PI = 3.14; // Variabila finala de instanta } La fiecare instantiere a clasei Exemplu va fi rezervat˘ o zon˘ de memorie ¸ a a pentru variabilele finale ale obiectului respectiv, ceea ce este o risip˘ ˆ a ıntrucˆt a aceste constante au acelea¸i valori pentru toate instantele clasei. Declararea s ¸ corect˘ a constantelor trebuie a¸adar facut˘ cu modificatorii static ¸i final, a s a s pentru a le rezerva o singur˘ zon˘ de memorie, comun˘ tuturor obiectelor: a a a class Exemplu { static final double PI = 3.14; // Variabila finala de clasa }

Num˘rarea obiectelor unei clase a Num˘rarea obiectelor unei clase poate fi f˘cut˘ extrem de simplu folosind a a a o variabil˘ static˘ ¸i este util˘ ˆ situatiile cˆnd trebuie s˘ control˘m diver¸i a as a ın ¸ a a a s parametri legati de crearea obiectelor unei clase. ¸ class Exemplu { static long nrInstante = 0; Exemplu() { // Constructorul este apelat la fiecare instantiere nrInstante ++; } }

˘ 2.5. MEMBRI DE INSTANTA SI MEMBRI DE CLASA ¸˘ ¸

63

Implementarea functiilor globale ¸ Spre deosebire de limbajele de programare procedurale, ˆ Java nu putem ın avea functii globale definite ca atare, ˆ ¸ ıntrucˆt ”orice este un obiect”. Din a acest motiv chiar ¸i metodele care au o functionalitate global˘ trebuie ims ¸ a plementate ˆ cadrul unor clase. Acest lucru se va face prin intermediul ın metodelor de clas˘ (globale), deoarece acestea nu depind de starea partica ular˘ a obiectelor din clasa respectiv˘. De exemplu, s˘ consider˘m functia a a a a ¸ sqrt care extrage radicalul unui num˘r ¸i care se g˘se¸te ˆ clasa Math. Dac˘ a s a s ın a nu ar fi fost functie de clas˘, apelul ei ar fi trebuit f˘cut astfel (incorect, de ¸ a a altfel): // Incorect ! Math obj = new Math(); double rad = obj.sqrt(121); ceea ce ar fi fost extrem de nepl˘cut... Fiind ˆ a metod˘ static˘ ea poate fi a ıns˘ a a apelat˘ prin: Math.sqrt(121) . a A¸adar, functiile globale necesare unei aplicatii vor fi grupate corespunz˘tor s ¸ ¸ a ˆ diverse clase ¸i implementate ca metode statice. ın s

2.5.4

Blocuri statice de initializare ¸

Variabilele statice ale unei clase sunt initializate la un moment care precede ¸ prima utilizare activ˘ a clasei respective. Momentul efectiv depinde de ima plementarea ma¸inii virtuale Java ¸i poart˘ numele de initializarea clasei. Pe s s a ¸ lˆng˘ setarea valorilor variabilelor statice, ˆ aceast˘ etap˘ sunt executate ¸i a a ın a a s blocurile statice de initializare ale clasei. Acestea sunt secvente de cod de ¸ ¸ forma: static { // Bloc static de initializare; ... } care se comport˘ ca o metod˘ static˘ apelat˘ automat de c˘tre ma¸ina vira a a a a s tual˘. Variabilele referite ˆ a ıntr-un bloc static de initializare trebuie s˘ fie ¸ a obligatoriu de clas˘ sau locale blocului: a public class Test { // Declaratii de variabile statice

64 static int x = 0, y, z;

CAPITOLUL 2. OBIECTE SI CLASE ¸

// Bloc static de initializare static { System.out.println("Initializam..."); int t=1; y = 2; z = x + y + t; } Test() { /* La executia constructorului variabilele de clasa sunt deja initializate si toate blocurile statice de initializare au fost obligatoriu executate in prealabil. */ ... } }

2.6
2.6.1

Clase imbricate
Definirea claselor imbricate

O clas˘ imbricat˘ este, prin definitie, o clas˘ membr˘ a unei alte clase, numit˘ a a ¸ a a a ¸i clas˘ de acoperire. In functie de situatie, definirea unei clase interne se s a ¸ ¸ poate face fie ca membru al clasei de acoperire - caz ˆ care este accesibil˘ ın a tuturor metodelor, fie local ˆ cadrul unei metode. ın class ClasaDeAcoperire{ class ClasaImbricata1 { // Clasa membru } void metoda() { class ClasaImbricata2 { // Clasa locala metodei } }

2.6. CLASE IMBRICATE }

65

Folosirea claselor imbricate se face atunci cˆnd o clas˘ are nevoie ˆ ima a ın plementarea ei de o alt˘ clas˘ ¸i nu exist˘ nici un motiv pentru care aceasta a as a din urm˘ s˘ fie declarat˘ de sine st˘t˘toare (nu mai este folosit˘ nic˘ieri). a a a aa a a O clas˘ imbricat˘ are un privilegiu special fat˘ de celelalte clase ¸i anume a a ¸a s acces nerestrictionat la toate variabilele clasei de acoperire, chiar dac˘ aces¸ a tea sunt private. O clas˘ declarat˘ local˘ unei metode va avea acces ¸i la a a a s variabilele finale declarate ˆ metoda respectiv˘. ın a class ClasaDeAcoperire{ private int x=1; class ClasaImbricata1 { int a=x; } void metoda() { final int y=2; int z=3; class ClasaImbricata2 { int b=x; int c=y; int d=z; // Incorect } } } O clas˘ imbricat˘ membr˘ (care nu este local˘ unei metode) poate fi a a a a referit˘ din exteriorul clasei de acoperire folosind expresia a ClasaDeAcoperire.ClasaImbricata A¸adar, clasele membru pot fi declarate cu modificatorii public, protected, s private pentru a controla nivelul lor de acces din exterior, ˆ ıntocmai ca orice variabil˘ sau metod˘ mebr˘ a clasei. Pentru clasele imbricate locale unei a a a metode nu sunt permi¸i acesti modificatori. s ¸ Toate clasele imbricate pot fi declarate folosind modificatorii abstract ¸i s final, semnificatia lor fiind aceea¸i ca ¸i ˆ cazul claselor obi¸nuite. ¸ s s ın s

. Pentru clasele ims ¸ ¸ a bricate aceste unit˘¸i de compilare sunt denumite astfel: numele clasei de at acoperire. urmat de simbolul ’$’ apoi de numele clasei imbricate. ın • o ”clas˘ intern˘” reflect˘ relatia dintre instantele a dou˘ clase. o clas˘ intern˘ este o clas˘ imbricat˘ ale carei instante nu pot s a a a a ¸ exista decˆt ˆ cadrul instantelor clasei de acoperire ¸i care are acces direct a ın ¸ s la toti membrii clasei sale de acoperire. A¸adar. } } Diferentierea acestor denumiri se face deoarece: ¸ • o ”clas˘ imbricat˘” reflect˘ relatia sintactic˘ a dou˘ clase: codul unei a a a ¸ a a clase apare ˆ interiorul codului altei clase. care sunt fi¸iere avˆnd numele clasei respective ¸i extensia ..6..6. OBIECTE SI CLASE ¸ 2.3 Identificare claselor imbricate Dup˘ cum ¸tim orice clas˘ produce la compilare a¸a numitele ”unit˘¸i de coma s a s at pilare”. o clas˘ imbricat˘ poate fi declarat˘ static˘ s a a a a sau nu. ¸ 2.. } static class ClasaImbricataStatica { . class ClasaInterna { . class ClasaDeAcoperire{ class ClasaInterna1 {} class ClasaInterna2 {} } .class s a s ¸i care contin toate informatiile despre clasa respectiv˘..2 Clase interne Spre deosebire de clasele obi¸nuite. ˆ sensul a a a ¸ ¸ a ın c˘ o instanta a unei clase interne nu poate exista decat ˆ cadrul unei a ¸ ın instante a clasei de acoperire. cele mai folosite clase imbricate sunt cele interne. ¸ In general. O clas˘ imbricat˘ nestatic˘ se nume¸te clasa intern˘.66 CAPITOLUL 2.. a a a s a class ClasaDeAcoperire{ .

Intr-un program nu avem ˆ a nevoie de nua ıns˘ mere generice ci de numere de un anumit tip: ˆ ıntregi.. // Eroare Integer intreg = new Integer(10).$n.2. Double.4 Clase anonime Exist˘ posibilitatea definirii unor clase imbricate locale.6. ˆ pachetul java. clasa Number reprezint˘ un concept abstract ¸i nu vom s a s putea instantia obiecte de acest tip . ın a 2.lang exist˘ clasa abstract˘ Number care modeleaz˘ ın a a a conceptul generic de ”num˘r”. a Exemple de folosire a claselor anonime vor fi date ˆ capitolul ”Interfete”. ce implementeaz˘ obiecte pentru descrierea numerelor de un s a anumit tip..7 Clase ¸i metode abstracte s Uneori ˆ proiectarea unei aplicatii este necesar s˘ reprezent˘m cu ajutorul ın ¸ a a claselor concepte abstracte care s˘ nu poat˘ fi instantiate ¸i care s˘ foloseasc˘ a a ¸ s a a doar la dezvoltarea ulterioar˘ a unor clase ce descriu obiecte concrete. reale. Astfel de clase se ¸ numesc clase anonime ¸i sunt foarte utile ˆ situatii cum ar fi crearea unor s ın ¸ obiecte ce implementeaz˘ o anumit˘ interfat˘ sau extind o anumit˘ clas˘ a a ¸a a a abstract˘.class ClasaDeAcoperire$ClasaInterna2. s 2. Float.. s a Long ¸i Short. ın ¸ precum ¸i extensiv ˆ capitolul ”Interfata grafic˘ cu utilizatorul”. A¸adar. Integer. Clasa Number serve¸te ca superclas˘ pentru clasele concrete Byte. s ın ¸ a Fi¸ierele rezultate ˆ urma compil˘rii claselor anonime vor avea numele s ın a de forma ClasaAcoperire. CLASE SI METODE ABSTRACTE ¸ Pentru exemplul de mai sus vor fi generate trei fi¸iere: s ClasaDeAcoperire. De exa emplu. // Corect .$1.class ClasaDeAcoperire$ClasaInterna1. ¸ ın Number numar = new Number().class 67 In cazul ˆ care clasele imbricate au la rˆndul lor alte clase imbricate ın a (situatie mai putin uzual˘) denumirea lor se face dup˘ aceea¸i regul˘: ad˘ugarea ¸ ¸ a a s a a unui ’$’ ¸i apoi numele clasei imbricate.7. ClasaAcoperire. utilizate a aa doar pentru instantierea unui obiect de un anumit tip. etc.vom folosi ˆ schimb subclasele sale.. unde n este num˘rul a de clase anonime definite ˆ clasa respectiv˘ de acoperire. f˘r˘ nume.

furnizˆnd chiar implea a mentarea unor metode comune tuturor claselor ¸i l˘sˆnd explicitarea altora s aa .7. Metodele fara nici o implementare se numesc metode abstracte ¸i pot ap˘rea doar ˆ clase abstracte. o clas˘ abstract˘ poate pune la dispozitia subclaselor sale a a ¸ un model complet pe care trebuie s˘-l implementeze.2 Metode abstracte Spre deosebire de clasele obi¸nuite care trebuie s˘ furnizeze implement˘ri s a a pentru toate metodele declarate. // Corect void metoda(). . dar nu poate specifica modificatorul final. a O clas˘ abstract˘ poate contine acelea¸i elemente membre ca o clas˘ a a ¸ s a obi¸nuit˘.68 CAPITOLUL 2. 2. la care se adaug˘ declaratii de metode abstracte .de altfel.7. accesul implicit fiind a a la nivel de pachet.f˘r˘ nici o ims a a ¸ aa plementare.. Interfata2. In fata unei metode abstracte s a ın ¸ trebuie s˘ apar˘ obligatoriu cuvˆntul cheie abstract. o clas˘ a a declarat˘ astfel nu ar avea nici o utilitate. altfel va fi furnizat˘ o a a a a eroare de compilare. abstract class ClasaAbstracta { abstract void metodaAbstracta()..] { // Declaratii uzuale // Declaratii de metode abstracte } O clas˘ abstract˘ poate avea modificatorul public. OBIECTE SI CLASE ¸ 2. o clas˘ abstract˘ poate contine metode f˘r˘ a a ¸ aa nici o implementare. // Eroare } In felul acesta.1 Declararea unei clase abstracte Declararea unei clase abstracte se face folosind cuvˆntul rezervat abstract: a [public] abstract class ClasaAbstracta [extends Superclasa] [implements Interfata1. combinatia ¸ abstract final fiind semnalat˘ ca eroare la compilare .

. etc. cum ar fi schims barea originii. } public void setY(int y) { this. } public void setColor(Color color) { this. etc a ¸ • Comportament: mutare. CLASE SI METODE ABSTRACTE ¸ 69 fiec˘rei subclase ˆ parte. desenare. } . colorare. curbe Bezier. redimensionare..7. private Color color = Color. Metodele abstracte vor fi folosite pentru ima plementarea comportamentului specific fiec˘rui obiect. Implementarea clasei abstracte GraphicObject ar putea ar˘ta a astfel: abstract class GraphicObject { // Stari comune private int x. culoarea.. a a • Obiecte grafice: linii. y.color = color..black.x = x. // Metode abstracte abstract void draw(). // Metode comune public void setX(int x) { this. dimensiunea. . .2. dreptunghiuri. } . etc • St˘ri comune: pozitia(originea).y = y. Pentru a folosi st˘rile ¸i comportamentele comune acestor obiecte ˆ avana s ın tajul nostru putem declara o clas˘ generic˘ GraphicObject care s˘ fie sua a a perclas˘ pentru celelalte clase. a ın Un exemplu elocvent de folosire a claselor ¸i metodelor abstracte este des scrierea obiectelor grafice ˆ ıntr-o manier˘ orientat˘-obiect. cum ar fi desenarea a iar cele obi¸nuite pentru comportamentul comun tuturor... cercuri.

. Dintre cele mai importante amintim: • Number: superclasa abstract˘ a tipurilor referint˘ numerice a ¸a • Reader. a a a a a a • O metod˘ abstract˘ nu poate ap˘rea decˆt ˆ a a a a ıntr-o clas˘ abstract˘.. Ima ın a plementarea claselor pentru obiecte grafice ar fi: class Circle extends GraphicObject { void draw() { // Obligatoriu implementarea . Writer: superclasele abstracte ale fluxurilor de intrare/ie¸ire s pe caractere • InputStream. a In API-ul oferit de platforma de lucru Java sunt numeroase exemple de ierarhii care folosesc la nivelele superioare clase abstracte. } } class Rectangle extends GraphicObject { void draw() { // Obligatoriu implementarea . AbstractSet. a a • Orice clas˘ care are o metod˘ abstract˘ trebuie declarat˘ ca fiind aba a a a stract˘. OutputStream: superclasele abstracte ale fluxurilor de intrare/ie¸ire pe octeti s ¸ • AbstractList... } } Legat de metodele abstracte.70 CAPITOLUL 2. AbstractMap: superclase abstracte pentru structuri de date de tip colectie ¸ . mai trebuie mentionate urm˘toarele: ¸ a • O clas˘ abstract˘ poate s˘ nu aib˘ nici o metod˘ abstract˘. OBIECTE SI CLASE ¸ O subclas˘ care nu este abstract˘ a unei clase abstracte trebuie s˘ furnizeze a a a obligatoriu implement˘ri ale metodelor abstracte definite ˆ superclas˘.

etc. a s • returnarea clasei din care face parte un obiect. numit˘ superclas˘. Evident. cum ar fi: • posibilitatea test˘rii egalit˘¸ii valorilor obiectelor. CLASA OBJECT 71 • Component : superclasa abstract˘ a componentelor folosite ˆ deza ın voltarea de aplicatii cu interfat˘ grafic˘ cu utilizatorul (GUI). Label. Declaratiile de mai jos sunt echivalente: a a ¸ class Exemplu {} class Exemplu extends Object {} 2. • etc. Fiind p˘rintele tuturor.8.2 Clasa Object Clasa Object este cea mai general˘ dintre clase. Object a define¸te ¸i implementeaz˘ comportamentul comun al tuturor celorlalte clase s s a Java. Button. 2.8 2.8.2. ˆ Java s a ın orice clas˘ are o superclas˘ ¸i numai una. a a ın ¸ a at clauza ”extends” specific˘ faptul c˘ acea clas˘ extinde (mo¸tene¸te) o alt˘ a a a s s a clas˘.8.1 Clasa Object Orice clas˘ are o superclas˘ a a Dup˘ cum am v˘zut ˆ sectiunea dedicat˘ modalit˘¸ii de creare a unei clase. a a ¸ . Aceasta este clasa Object. a at • specificarea unei reprezent˘ri ca ¸ir de caractere a unui obiect . direct a sau indirect. O clas˘ poate avea o singur˘ superclas˘ (Java nu a a a a a a suport˘ mo¸tenirea multipl˘) ¸i chiar dac˘ nu specific˘m clauza ”extends” la a s a s a a crearea unei clase ea totu¸i va avea o superclas˘. Cu alte cuvinte. ¸ s Clasa Object este ¸i superclasa implicit˘ a claselor care nu specific˘ o s a a anumit˘ superclas˘. cum ar ¸ ¸a a fi Frame. • notificarea altor obiecte c˘ o variabil˘ de conditie s-a schimbat. trebuie s˘ existe o exceptie a as a ¸ de la aceast˘ regul˘ ¸i anume clasa care reprezint˘ r˘d˘cina ierarhiei format˘ a as a a a a de relatiile de mo¸tenire dintre clase. descendent al acestei clase. etc. orice obiect fiind.

fiind apelat˘ automat atunci cˆnd este necesar˘ transsa a a a formarea unui obiect ˆ ¸ir de caractere.println("Obiect=" + obj.out. Uzual este redefinit˘ pentru a testa dac˘ st˘rile ¸ a a a obiectelor coincid sau dac˘ doar o parte din variabilele lor coincid. . hashCode Acestea sunt. equals/hashCode.out. • equals. de obicei. at ¸ a Implicit (implementarea din clasa Object).println("Obiect=" + obj). OBIECTE SI CLASE ¸ Fiind subclas˘ a lui Object.72 CAPITOLUL 2. atunci apelul a a metodei hashCode pentru fiecare din cele dou˘ obiecte ar trebui s˘ a a returneze acela¸i intreg.toString()). System. Metodele cel mai uzual supradefinite sunt: clone. //echivalent cu System. s ¸ Dac˘ dou˘ obiecte sunt egale conform metodei equals. aceast˘ metod˘ compar˘ a a a referintele obiectelor. supradefinite ˆ ımpreun˘. Clonarea unui obiect presupune crearea unui nou obiect de acela¸i tip ¸i care s˘ aib˘ aceea¸i stare (acelea¸i valori pentru variabilele s s a a s s sale). finalize. s • finalize In aceast˘ metod˘ se scrie codul care ”cur˘¸˘ dup˘ un obiect” ˆ a a ata a ınainte de a fi eliminat din memorie de colectorul de gunoaie. Este util˘ pentru concatenarea ¸irurilor cu diverse obiecte ˆ a s ın vederea afi¸˘rii. pentru a testa consistenta obiectelor: acela¸i obiect trebuie s˘ returneze ¸ s a acela¸i cod pe durata executiei programului. • clone Aceast˘ metod˘ este folosit˘ pentru duplicarea obiectelor (crearea unor a a a clone). toString. ın s Exemplu obj = new Exemplu(). orice clas˘ ˆ poate supradefini metodele a a ıi care nu sunt finale. a Metoda hashCode returneaza un cod ˆ ıntreg pentru fiecare obiect. (vezi ”Distrugerea obiectelor”) • toString Este folosit˘ pentru a returna o reprezentare ca ¸ir de caractere a unui a s obiect. In metoda equals este a scris codul pentru compararea egalit˘¸ii continutului a dou˘ obiecte.

Listing 2. a + comp . a = a . // partea reala private double b . Complex comp = ( Complex ) obj . } } . b = b . ¸i ˆ care vom supradefini metode ale clasei Object.2.1: Clasa numerelor complexe class Complex { private double a . b == b ) . b ) . CLASA OBJECT 73 S˘ consider˘m urm˘torul exemplu. b . return suma . 0) . } public Complex aduna ( Complex comp ) { Complex suma = new Complex (0 . return ( comp . // partea imaginara public Complex ( double a . vom scrie un mic program TestComplex ˆ care vom testa ın metodele clasei definite. } public Complex () { this (1 . ˆ care implement˘m partial clasa a a a ın a ¸ numerelor complexe. 0) . s ın De asemenea. suma . b = this . suma . } public String toString () { String semn = ( b > 0 ? " + " : " -" ) . } public Object clone () { return new Complex (a . } public boolean equals ( Object obj ) { if ( obj == null ) return false . a . this . double b ) { this . if (!( obj instanceof Complex ) ) return false .8. a = this . b + comp . a == a && comp . return a + semn + b + " i " .

2) . Conversia explicit˘ va fi facut˘ de c˘tre a a a compilator. respectiv auto-unboxing.0 i // false // true 2. OBIECTE SI CLASE ¸ public class TestComplex { public static void main ( String c []) Complex c1 = new Complex (1 . a a ımp˘ ¸ ın s ¸a Pentru fiecare tip primitiv exist˘ o clas˘ corespunz˘toare care permie lucrul a a a orientat obiect cu tipul respectiv. acest mecanism purtˆnd numele de s ¸a a autoboxing. byte short int long float double char boolean Byte Short Integer Long Float Double Character Boolean Fiecare din aceste clase are un constructor ce permite initializarea unui ¸ obiect avˆnd o anumit˘ valoare primitiv˘ ¸i metode specializate pentru cona a as versia unui obiect ˆ tipul primitiv corespunz˘tor.5 a limbajului Java. Incepˆnd cu versiunea 1. . System . clone () . equals ( c3 ) ) . out . int i = obi. Complex c2 = new Complex (2 .3) . atribuirile explicite ˆ a ıntre tipuri primitve ¸i referint˘ sunt posibile. println ( c1 . boolean b = obb. System .0 + 5. Complex c3 = ( Complex ) c1 . out . println ( c1 . } } { // 3.booleanValue(). out . equals ( c2 ) ) . de genul tipPrimitivValue: ın a Integer obi = new Integer(1).intValue(). println ( c1 . Boolean obb = new Boolean(true). aduna ( c2 ) ) . System .9 Conversii automate ˆ ıntre tipuri Dup˘ cum v˘zut tipurile Java de date pot fi ˆ artie ˆ primitive ¸i referint˘.74 CAPITOLUL 2.

..culoare = CuloriSemafor.culoare = CuloriSemafor. Acest˘ a a solutie simplific˘ manevrarea grupurilor de constante. public static final int VERDE = 1..2. 75 2.10 Tipul de date enumerare Incepˆnd cu versiunea 1.ROSU) semafor. VERDE }. public static final int GALBEN = 0. a a . . dup˘ cum reiese din ¸ a a urm˘torul exemplu: a public class CuloriSemafor { public static final int ROSU = -1. . boolean b = obb... // Utilizarea structurii se face la fel . TIPUL DE DATE ENUMERARE // Doar de la versiunea 1.. // Exemplu de utilizare if (semafor. . Clasa de mai sus poate fi rescris˘ astfel: a public enum CuloriSemafor { ROSU.10.culoare = CuloriSemafor. Boolean obb = true..culoare = CuloriSemafor. int i = obi. if (semafor.GALBEN).. exist˘ posibilitatea de a defini a a tipuri de date enumerare prin folosirea cuvˆntului cheie enum. GALBEN.5 a limbajului Java. Compilatorul este responsabil cu transformarea unei astfel de structuri ˆ ıntr-o clas˘ corespunz˘toare. } .ROSU) semafor.5 ! Integer obi = 1..GALBEN)..

76 CAPITOLUL 2. OBIECTE SI CLASE ¸ .

ın ¸ public class Exemplu { public static void main(String args[]) { int v[] = new int[10].. //Exceptie ! System.. programul se va opri a ¸ la instructiunea care a cauzat exceptia ¸i se va afi¸a un mesaj de eroare de ¸ ¸ s s genul: 77 .out.").Capitolul 3 Exceptii ¸ 3. cum ar fi accesarea unui element din afara t spatiului alocat unui vector. ¸ In momentul cˆnd o asemenea eroare se produce ˆ timpul executiei va fi a ın ¸ generat un obiect de tip exceptie ce contine: ¸ ¸ • informatii despre exceptia respectiv˘. ¸ ¸ a • starea programului ˆ momentul producerii acelei exceptii. v[10] = 0. ¸ Exceptiile pot ap˘rea din diverse cauze ¸i pot avea nivele diferite de grav¸ a s itate: de la erori fatale cauzate de echipamentul hardware pˆn˘ la erori ce a a ¸in strict de codul programului.1 Ce sunt exceptiile ? ¸ Termenul exceptie este o prescurtare pentru ”eveniment exceptional” ¸i poate ¸ ¸ s fi definit ca un eveniment ce se produce ˆ timpul executiei unui program ¸i ın ¸ s care provoac˘ ˆ a ıntreruperea cursului normal al executiei acestuia. } } La rularea programului va fi generat˘ o exceptie.println("Aici nu se mai ajunge.

lang.java:4)" Crearea unui obiect de tip exceptie se nume¸te aruncarea unei exceptii ¸ s ¸ (”throwing an exception”).. In ¸ a aproape toate situatile. O secvent˘ de cod care trateaz˘ anumite exceptii s ¸a a ¸ trebuie s˘ arate astfel: a try { // Instructiuni care pot genera exceptii } catch (TipExceptie1 variabila) { // Tratarea exceptiilor de tipul 1 . a Secventa de cod dintr-o metod˘ care trateaz˘ o anumit˘ exceptie se ¸ a a a ¸ nume¸te analizor de exceptie (”exception handler”) iar interceptarea ¸i tratarea s ¸ s ei se nume¸te prinderea exceptiei (”catch the exception”). EXCEPTII ¸ "Exception in thread "main" java.2 ”Prinderea” ¸i tratarea exceptiilor s ¸ Tratarea exceptiilor se realizeaz˘ prin intermediul blocurilor de instructiuni ¸ a ¸ try. s ¸ Cu alte cuvinte. catch ¸i finally.” nu va fi afi¸at). o secvent˘ de cod care poate provoca exceptii trebuie ¸ ¸a ¸ s˘ specifice modalitatea de tratare a acestora. ˆ a a a ıncepˆnd cu a metoda care a generat exceptia ¸i mergˆnd ˆ ¸ s a ınapoi pe linia apelurilor c˘tre a acea metod˘. a 3. la aparitia unei erori este ”aruncat˘” o exceptie iar cineva ¸ a ¸ trebuie s˘ o ”prind˘” pentru a o trata..78 CAPITOLUL 3. atunci programul Java se opre¸te cu un a ¸ s mesaj de eroare (ˆ cazul exemplului de mai sus mesajul ”Aici nu se mai ın ajunge.ArrayIndexOutOfBoundsException :10 at Exceptii. C˘utarea se face recursiv. s Atentie ¸ In Java tratarea erorilor nu mai este o optiune ci o constrˆngere. Dac˘ sistemul nu gase¸te nici un a a a s analizor pentru o anumit˘ exceptie. In momentul ˆ care o metod˘ genereaz˘ (arunc˘) ın a a a o exceptie sistemul de executie este responsabil cu g˘sirea unei secvente de ¸ ¸ a ¸ cod dintr-o metod˘ care s˘ o trateze.main (Exceptii.

3. // Inchidem fisierul System.2.println("\\nInchidem fisierul " + fis). f = new FileReader(fis).close(). } Aceast˘ secvent˘ de cod va furniza erori la compilare deoarece ˆ Java a ¸a ın tratarea erorilor este obligatorie.out.out. finally { // Cod care se executa indiferent // daca apar sau nu exceptii } 79 S˘ consider˘m urm˘torul exemplu: citirea unui fi¸ier octet cu octet ¸i a a a s s afisarea lui pe ecran.print((char)c). Folosind mecanismul exceptiilor metoda ¸ citeste ˆsi poate trata singur˘ erorile care pot surveni pe parcursul executiei ı¸ a ¸ sale.println("Deschidem fisierul " + fis). f. // Deschidem fisierul System. .read()) != -1) System.out. ”PRINDEREA” SI TRATAREA EXCEPTIILOR ¸ ¸ } catch (TipExceptie2 variabila) { // Tratarea exceptiilor de tipul 2 } . Mai jos este codul complte ¸i corect al unui program ce afi¸eaz˘ pe ecran s s a continutul unui fi¸ier al c˘rui nume este primit ca argument de la linia de ¸ s a comand˘. // Citim si afisam fisierul caracter cu caracter int c. Tratarea exceptiilor este realizat˘ complet chiar de c˘tre metoda a ¸ a a citeste. . F˘r˘ a folosi tratarea exceptiilor metoda responsabil˘ aa ¸ a cu citirea fi¸ierului ar ar˘ta astfel: s a public static void citesteFisier(String fis) { FileReader f = null. . while ( (c=f.

// Citim si afisam fisierul caracter cu caracter int c . public class CitireFisier { public static void citesteFisier ( String fis ) { FileReader f = null . out . out . } } } } public static void main ( String args []) { if ( args . e . try { // Deschidem fisierul System . printStackTrace () . f = new FileReader ( fis ) .corect import java . close () . try { f . println ( " Exceptie : " + e . getMessage () ) .*. System . out . } catch ( File Not F o u n d E x c e p t i o n e ) { // Tratam un tip de exceptie System . } catch ( IOException e ) { // Tratam alt tip de exceptie System . System . } finally { if ( f != null ) { // Inchidem fisierul System . print (( char ) c ) . EXCEPTII ¸ Listing 3.1: Citirea unui fisier . err . " ) . println ( " Eroare la citirea din fisier ! " ) . err .80 CAPITOLUL 3. err . e . read () ) != -1) System . printStackTrace () . while ( ( c = f . out . else . exit (1) . println ( " Fisierul nu poate fi inchis ! " ) . println ( " Deschidem fisierul " + fis ) . io . println ( " Fisierul nu a fost gasit ! " ) . } catch ( IOException e ) { System . length > 0) citesteFisier ( args [0]) . println ( " \ nInchidem fisierul .

”PRINDEREA” SI TRATAREA EXCEPTIILOR ¸ ¸ System ..3. ˆ functie de exceptiile provocate de acele ın ¸ ¸ instructiuni sau (optional) de un bloc ”finally”. pentru a avea un cod complet corect trebuie s˘ trat˘m ¸i posibilitatea aparitiei unei exceptii la metoda close. ¸ s ın deoarece acesta este sigur c˘ se va executa F˘r˘ a folosi blocul ”finally”. // A aparut o exceptie la citirea din fisier f. ambele putˆnd produce exceptii. de exemplu atunci cˆnd fi¸ierul mai este folosit ¸i de a a ¸ a s s alt proces ¸i nu poate fi ˆ s ınchis. // cod redundant } O problem˘ mai delicat˘ care trebuie semnalata ˆ aceasta situatie este a a ın ¸ faptul c˘ metoda close. a aa ˆ ınchiderea fi¸ierului ar fi trebuit facut˘ ˆ fiecare situatie ˆ care fi¸ierul ar fi s a ın ¸ ın s fost deschis. ceea ce ar fi dus la scrierea de cod redundant. out .close(). try { . } } 81 Blocul ”try” contine instructiunile de deschidere a unui fi¸ier ¸i de citire ¸ s s dintr-un fi¸ier. // Totul a decurs bine. responsabil˘ cu ˆ a a ınchiderea unui fi¸ier.. catch (IOException e) { . poate provoca s la rˆndul s˘u exceptii. Inchiderea fi¸ierului se face ˆ blocul ”finally”...close(). ¸ ¸ . Exceptiile provocate de s a ¸ ¸ aceste instructiuni sunt tratate ˆ cele dou˘ blocuri ”catch”. cˆte unul pen¸ ın a a tru fiecare tip de exceptie. println ( " Lipseste numele fisierului ! " ) . f.. Deci.. } . a a s ¸ ¸ Atentie ¸ Obligatoriu un bloc de instructiuni ”try” trebuie s˘ fie urmat de unul ¸ a sau mai multe blocuri ”catch”.2.

*. out .. public class CitireFisier { public static void citesteFisier ( String fis ) throws FileNotFoundException . io . EXCEPTII ¸ 3. int c . close () . la rˆndul lor. { . f = new FileReader ( fis ) . In exemplul de mai sus dac˘ nu facem tratarea exceptiilor ˆ cadrul a ¸ ın metodei citeste atunci metoda apelant˘ (main) va trebui s˘ fac˘ acest lucru: a a a Listing 3. print (( char ) c ) . read () ) != -1) System . while ( ( c = f . s˘ a a a a a ”arunce” mai departe exceptiile respective.. ¸ Acest lucru se realizeaz˘ prin specificarea ˆ declaratia metodei a clauzei a ın ¸ throws: [modificatori] TipReturnat metoda([argumente]) throws TipExceptie1. TipExceptie2.2: Citirea unui fisier import java .82 CAPITOLUL 3. urmˆnd ca acestea s˘ implementeze tratarea lor sau. } Atentie ¸ O metod˘ care nu trateaz˘ o anumit˘ exceptie trebuie obligatoriu s˘ o a a a ¸ a ”arunce”. .. } .. f . IOException { FileReader f = null .3 ”Aruncarea” exceptiilor ¸ In cazul ˆ care o metod˘ nu ˆsi asum˘ responsabilitatea trat˘rii uneia sau ın a ı¸ a a mai multor exceptii pe care le pot provoca anumite instructiuni din codul ¸ ¸ s˘u atunci ea poate s˘ ”arunce” aceste exceptii c˘tre metodele care o apea a ¸ a leaz˘.

try { f = new FileReader(numeFisier). println ( " Lipseste numele fisierului ! " ) . out . s s De asemenea. ˆ acest caz. System . println ( " Exceptie : " + e ) . int c. ”ARUNCAREA” EXCEPTIILOR ¸ 83 public static void main ( String args []) { if ( args .read()) != -1) System. } finally { if (f!=null) f. } } Observati c˘.out. err .3. err . } } . inchiderea fi¸ierului nu va mai fi facut˘ ˆ situatia ˆ care s a ın ın apare o exceptie la citirea din fi¸ier. } } else System . Este situatia ˆ care putem folosi blocul ¸ s ¸ ın finally f˘r˘ a folosi nici un bloc catch: aa public static void citesteFisier(String fis) throws FileNotFoundException. println ( " Eroare la citirea din fisier ! " ) . } catch ( IOException e ) { System . } catch ( File NotFo undE x c ep ti on e ) { System .3.close(). IOException { FileReader f = null. while ( (c=f. e . nu mai putem diferentia exceptiile provocate de ¸ a ın ¸ ¸ citirea din fi¸ier s de inchiderea fi¸ierului. printStackTrace () . ambele fiind de tipul IOException. length > 0) { try { citesteFisier ( args [0]) . println ( " Fisierul nu a fost gasit ! " ) . out .print((char)c).

. dac˘ va arunca exceptiile ce pot ap˘rea ˆ corpul ei.. astfel ˆ at codul s˘ fie cˆt mai clar s a ıncˆ a a ¸i identificarea locului ˆ care a ap˘rut exceptia s˘ fie cˆt mai u¸or de f˘cut.. metoda main ar putea fi declarat˘ astfel: a public static void main(String args[]) throws FileNotFoundException.. } public void main throws TipExceptie { metoda1(). } public void metoda2 throws TipExceptie { metoda3(). Pentru s ¸ ¸ exemplul nostru.. . Aceast˘ ˆ antuire se termin˘ cu metoda a a ınl˘ ¸ a main care. } public void metoda1 throws TipExceptie { metoda2()..84 CAPITOLUL 3. } Intotdeauna trebuie g˘sit compromisul optim ˆ a ıntre tratarea local˘ a exceptiilor a ¸ ¸i aruncarea lor c˘tre nivelele superioare.. . IOException { citeste(args[0]). } Tratarea exceptiilor de c˘tre JVM se face prin terminarea programului ¸i ¸ a s afi¸area informatiilor despre exceptia care a determinat acest lucru. va determina a ¸ a ın trimiterea exceptiilor c˘tre ma¸ina virtual˘ Java. EXCEPTII ¸ Metoda apelant˘ poate arunca la rˆndul sˆu exceptiile mai departe c˘tre a a a ¸ a metoda care a apelat-o la rˆndul ei. s ın a ¸ a a s a Aruncarea unei exceptii se poate face ¸i implicit prin instructiunea throw ¸ s ¸ ce are formatul: throw exceptie. ca ˆ exemplele de mai jos: ın throw new IOException("Exceptie I/O"). if (index >= vector. ¸ a s a public void metoda3 throws TipExceptie { .length) throw new ArrayIndexOutOfBoundsException().

a a • Propagarea unei erori pˆn˘ la un analizor de exceptii corespunz˘tor.1 Separarea codului pentru tratarea erorilor In programarea traditional˘ tratarea erorilor se combin˘ cu codul ce poate ¸ a a produce aparitia lor producˆnd a¸a numitul ”cod spaghetti”..4. S˘ consider˘m ¸ a s a a urm˘torul exemplu: o functie care ˆ a ¸ ıncarc˘ un fi¸ier ˆ memorie: a s ın citesteFisier { deschide fisierul. a 3.4. citeste fisierul in memorie. Java are urm˘toarele avantaje ¸ a fat˘ de mecanismul traditional de tratare a erorilor: ¸a ¸ • Separarea codului pentru tratarea unei erori de codul ˆ care ea poate ın s˘ apar˘. } 85 Aceast˘ instructiune este folosit˘ mai ales la aruncarea exceptiilor proprii. } Problemele care pot ap˘rea la aceasta functie. sunt de a ¸ a genul: ”Ce se ˆ ampl˘ dac˘: .out. aloca memorie. aparent simpl˘. AVANTAJELE TRATARII EXCEPTIILOR ¸ catch(Exception e) { System. inchide fisierul. a ¸ a ¸ (vezi ”Crearea propriilor exceptii”) ¸ 3. a a ¸ a • Gruparea erorilor dup˘ tipul lor..4 Avantajele trat˘rii exceptiilor a ¸ Prin modalitatea sa de tratare a exceptiilor. determina dimensiunea fisierului. throw e.˘ 3.println("A aparut o exceptie). ?” ıntˆ a a • fi¸ierul nu poate fi deschis s • nu se poate determina dimensiunea fi¸ierului s .

if (s-a determinat dimensiunea) { aloca memorie. schematizat. EXCEPTII ¸ Un cod traditional care s˘ trateze aceste erori ar ar˘ta astfel: ¸ a a int citesteFisier() { int codEroare = 0. if (fisierul nu s-a inchis && codEroare == 0) { codEroare = -4. } // Cod "spaghetti" Acest stil de progamare este extrem de susceptibil la erori ¸i ˆ s ıngreuneaz˘ a extrem de mult ˆ ¸telegerea sa. astfel: . } } else { codEroare = -5. if (s-a alocat memorie) { citeste fisierul in memorie. In Java. } } else { codEroare = -2. if (fisierul s-a deschis) { determina dimensiunea fisierului. } } else { codEroare = -3. ınt ¸ codul ar arata. deschide fisierul. if (nu se poate citi din fisier) { codEroare = -1. } inchide fisierul.86 • nu poate fi alocat˘ suficient˘ memorie a a • nu se poate face citirea din fi¸ier s • fi¸ierul nu poate fi ˆ s ınchis CAPITOLUL 3. folosind mecansimul exceptiilor. } return codEroare. } else { codEroare = codEroare & -4.

˘ 3.} catch (nu se poate inchide fisierul) {trateaza eroarea. . citeste fisierul in memorie.} } Diferenta de claritate este evident˘... .4. } catch (fisierul nu s-a deschis) {trateaza eroarea.} catch (nu s-a alocat memorie) {trateaza eroarea} catch (nu se poate citi din fisier) {trateaza eroarea. . a a ¸ a S˘ presupunem c˘ apelul la metoda citesteFisier este consecinta unor a a ¸ apeluri imbricate de metode: int metoda1() { metoda2(). ... } int metoda2() { metoda3.2 Propagarea erorilor Propagarea unei erori se face pˆn˘ la un analizor de exceptii corespunz˘tor.4. inchide fisierul.} catch (nu s-a determinat dimensiunea) {trateaza eroarea. determina dimensiunea fisierului.. aloca memorie. a 87 3. } int metoda3 { citesteFisier(). AVANTAJELE TRATARII EXCEPTIILOR ¸ int citesteFisier() { try { deschide fisierul..

if (codEroare != 0) //proceseazaEroare. . o metod˘ poate s˘ nu ˆsi asume responsabila a ı¸ itatea trat˘rii exceptiilor ap˘rute ˆ cadrul ei: a ¸ a ın int metoda1() { try { metoda2(). EXCEPTII ¸ S˘ presupunem de asemenea c˘ dorim s˘ facem tratarea erorilor doar a a a ˆ metoda1. Cu alte cuvinte. } catch (TipExceptie e) { //proceseazaEroare.... } . } int metoda3() { int codEroare = citesteFisier(). . } . } Dup˘ cum am vazut. adic˘ functiilor care o apeleaz˘ a ın a ¸ a sau sistemului.. Traditional.. . if (codEroare != 0) return codEroare.. Java permite unei metode s˘ arunce exceptiile a a ¸ ap˘rute ˆ cadrul ei la un nivel superior. if (codEroare != 0) return codEroare.. acest lucru ar trebui f˘cut prin propagarea erorii ın ¸ a produse de metoda citesteFisier pˆn˘ la metoda1: a a int metoda1() { int codEroare = metoda2(). } int metoda2() { int codEroare = metoda3()..88 } CAPITOLUL 3.

dat’ } // sau . AVANTAJELE TRATARII EXCEPTIILOR ¸ int metoda2() throws TipExceptie { metoda3(). clasa IOException se ˆ a ıncadreaz˘ ˆ a ıntr-o categorie mai larg˘ de a exceptii ¸i anume clasa Exception. clasa IOException se ocup˘ cu a exceptiile ce pot ap˘rea la operatii de intrare/iesire ¸i diferentiaz˘ la rˆndul ¸ a ¸ s ¸ a a ei alte tipuri de exceptii. } 89 3. ¸ s Radacin˘ acestei ierarhii este clasa Throwable (vezi ”Ierarhia claselor ce dea scriu exceptii”). ˆ a. EOFException.4. ¸ Pronderea unei exceptii se poate face fie la nivelul clasei specifice pen¸ tru acea exceptie. ˆ functie de ¸ ın ¸ necesit˘¸ile programului. /* Acest apel poate genera exceptie de tipul FileNotFoundException Tratarea ei poate fi facuta in unul din modurile de mai jos: */ } catch (FileNotFoundException e) { // Exceptie specifica provocata de absenta // fisierului ’input. ¸ ı¸ try { FileReader f = new FileReader("input. cu cˆt clasa folosit˘ este mai generic˘ cu atˆt at ıns˘ a a a a tratarea exceptiilor programul ˆsi pierde din flexibilitate.dat").3 Gruparea erorilor dup˘ tipul lor a In Java exist˘ clase corespunz˘toare tuturor exceptiilor care pot ap˘rea la a a ¸ a executia unui program. De exemplu. ¸ etc... cum ar fi FileNotFoundException. fie la nivelul uneia din superclasele sale.4.˘ 3. Acestea sunt grupate ˆ functie de similarit˘¸ile ¸ ın ¸ at lor ˆ ıntr-o ierarhie de clase. } int metoda3() throws TipExceptie { citesteFisier(). ... La rˆndul ei. .

90 CAPITOLUL 3. a ¸ Erorile. obiecte de tip Error.5 Ierarhia claselor ce descriu exceptii ¸ R˘d˘cina claselor ce descriu exceptii este clasa Throwable iar cele mai impora a ¸ tante subclase ale sale sunt Error. . sunt cazuri speciale de exceptii generate ¸ de functionarea anormal˘ a echipamentului hard pe care ruleaz˘ un pro¸ a a gram Java ¸i sunt invizibile programatorilor. care s sunt la rˆndul lor superclase pentru o serie ˆ a ıntreag˘ de tipuri de exceptii. EXCEPTII ¸ catch (IOException e) { // Exceptie generica provocata de o operatie IO } // sau catch (Exception e) { // Cea mai generica exceptie soft } //sau catch (Throwable e) { // Superclasa exceptiilor } 3. Exception ¸i RuntimeException. Un program Java nu trebuie s˘ s a trateze aparitia acestor erori ¸i este improbabil ca o metod˘ Java s˘ provoace ¸ s a a asemenea erori.

¸ Metodele care sunt apelate uzual pentru un obiect exceptie sunt definite ¸ ˆ clasa Throwable ¸i sunt publice.6. Reamintim ˆ a c˘. astfel ˆ at pot fi apelate pentru orice tip ın s ıncˆ de exceptie.6 Exceptii la executie ¸ ¸ In general. cum ar fi lipsa unui fi¸ier.3. ¸ a a a a tratarea lor nefiind ˆ a ilegal˘. ¸ a s Aceste exceptii au o superclas˘ comun˘ RuntimeException ¸i ˆ acesata ¸ a a s ın categorie sunt incluse exceptiile provocate de: ¸ • operatii aritmetice ilegale (ˆ artirea ˆ ¸ ımpˆ ¸ ıntregilor la zero). obiectele de tip Exception. care furnizeaz˘ reprezentarea a s a a ca ¸ir de caractere a exceptiei. .afi¸eaz˘ informatii complete despre exceptie ¸i los a ¸ ¸ s calizarea ei. ˆ cazul aparitiei oric˘rui ıns˘ a ıns˘ a ın ¸ a tip de exceptie care nu are un analizor corespunz˘tor. NullPointerException • accesarea eronat˘ a elementelor unui vector. compilatorul permite ca aceste exceptii s˘ r˘mˆn˘ netratate. a ArrayIndexOutOfBoundsException Exceptiile la executie pot ap˘rea uriunde ˆ program ¸i pot fi extrem ¸ ¸ a ın s de numeroare iar ˆ ıncercarea de ”prindere” a lor ar fi extrem de anevoioas˘. EXCEPTII LA EXECUTIE ¸ ¸ 91 Exceptiile. Cele mai uzuale sunt: ¸ • getMessage . exceptiile ıns˘ s ¸ ¸ ¸ care provin strict din vina programatorului ¸i nu generate de o anumit˘ s a situatie extern˘. programul va fi termi¸ a nat. ArithmeticException • accesarea membrilor unui obiect ce are valoarea null.afi¸eaz˘ detaliul unei exceptii. • toString . s ¸ 3. De la acest principu se ¸ ın sustrag ˆ a a¸a numitele exceptii la executie sau. a Din acest motiv. Exceptiile care pot ”sc˘pa” ¸ ¸ a ¸ a netratate descind din subclasa RuntimeException ¸i se numesc exceptii la s ¸ executie. sunt exceptiile standard (soft) care ¸ ¸ trebuie tratate de c˘tre programele Java. tratarea exceptiilor este obligatorie ˆ Java.metod˘ mo¸tenit˘ din clasa Object. s a ¸ • printStackTrace . Dup˘ cum am mai zis tratarea acesa a tor exceptii nu este o optiune ci o constrˆngere. cu alte cuvinte.

out. System. ın ¸ O exceptie proprie trebuie s˘ se ˆ ¸ a ıncadreze ˆ a ˆ ierarhia exceptiilor Java.. try { v[10] = 0. // Infinity System. } catch (ArrayIndexOutOfBoundsException e) { System.println(a/b). sau Nan. ci va fi furnizat ca rezultat o constant˘ care poate a ¸ a fi. ın a ¸ sau superclasa Exception. */ System.")..out.println(y/z).println("Aici nu se mai ajunge.7 Crearea propriilor exceptii ¸ Adeseori poate ap˘rea necesitatea cre˘rii unor exceptii proprii pentru a pune a a ¸ ˆ evidenta cazuri speciale de erori provocate de metodele claselor unei libr˘rii. programul continua v[11] = 0.out.println("Atentie la indecsi!"). // NaN 3.printStackTrace(). y=-1. // Exceptie la executie ! double x=1. e. /* Nu apare eroare la compilare dar apare exceptie la executie si programul va fi terminat. Infinity. Imp˘rtirea la 0 va genera o exceptie doar dac˘ tipul numerelor ˆ artite a¸ ¸ a ımp˘ ¸ este aritmetic ˆ ıntreg. preferabil una apropiat˘ ca semnificatie. functie de operatie. // -Infinity System. int b=0. ın ¸ a cazuri care nu au fost prevazute ˆ ierarhia exceptiilor standard Java. -Infinity.println(x/z). .92 CAPITOLUL 3. ıns˘ ın ¸ cu alte cuvinte clasa care o implementeaz˘ trebuie s˘ fie subclas˘ a uneia a a a deja existente ˆ aceasta ierarhie.println(z/z). z=0. EXCEPTII ¸ int v[] = new int[10].out. In cazul tipurilor reale (float ¸i double) nu va fi s generat˘ nici o exceptie.out. System. } // Corect. ¸ int a=1.out.

ˆ care cre˘m o clas˘ ce descrie partial a a a ın a a ¸ o stiv˘ de numere ˆ a ıntregi cu operatiile de ad˘ugare a unui element. ambele operatii pot provoca exceptii. return elemente [n . int n =0. elemente [ n ++] = x . respec¸ a tiv de scoatere a elementului din vˆrful stivei. CREAREA PROPRIILOR EXCEPTII ¸ public class ExceptieProprie extends Exception { public ExceptieProprie(String mesaj) { super(mesaj). } } class Stiva { int elemente [] = new int [100]. Dac˘ presupunem c˘ stiva a a a poate memora maxim 100 de elemente.-].3. a ¸ . // Apeleaza constructorul superclasei Exception } } 93 S˘ consider˘m urm˘torul exemplu.7. } public int scoate () throws ExceptieStiva { if ( n ==0) throw new ExceptieStiva ( " Stiva este goala ! " ) . } } Secventa cheie este extends Exception care specific˘ faptul c˘ noua ¸ a a clas˘ ExceptieStiva este subclas˘ a clasei Exception ¸i deci implementeaz˘ a a s a obiecte ce reprezint˘ exceptii. // numarul de elemente din stiva public void adauga ( int x ) throws ExceptieStiva { if ( n ==100) throw new ExceptieStiva ( " Stiva este plina ! " ) . ¸ ¸ Pentru a personaliza aceste exceptii vom crea o clas˘ specific˘ denumit˘ ¸ a a a ExceptieStiva: Listing 3.3: Exceptii proprii class ExceptieStiva extends Exception { public ExceptieStiva ( String mesaj ) { super ( mesaj ) .

94 CAPITOLUL 3. chiar f˘r˘ nici un cod ˆ ele. EXCEPTII ¸ In general. Exceptiile proprii sunt descrise uzual ı¸ ın ¸ de clase foarte simple. ˆ a aceasta dezvoltare nu ¸ ıns˘ ˆsi are rostul ˆ majoritatea cazurilor. codul ad˘ugat claselor pentru exceptii proprii este nesemnificativ: a ¸ unul sau doi constructori care afi¸eaza un mesaj de eroare la ie¸irea standard. ıns˘ . s s Procesul de creare a unei noi exceptii poate fi dus mai departe prin ad˘ugarea ¸ a unor noi metode clasei ce descrie acea exceptie. cum ar fi: aa ın class ExceptieSimpla extends Exception { } Aceast˘ clas˘ se bazeaz˘ pe constructorul implicit creat de compilator a a a ˆ a nu are constructorul ExceptieSimpla(String s).

ın s sunete. a a ¸ a ¸ a Informatia se poate g˘si oriunde: ˆ ¸ a ıntr-un fi¸ier pe disc. a s a ¸ 95 . ¸ ¸ Indiferent de tipul informatiilor. obiecte. socket. citirea/scrierea de pe/c˘tre un mediu ¸ a extern respect˘ urm˘torul algoritm: a a deschide canal comunicatie while (mai sunt informatii) { citeste/scrie informatie. respectiv consum˘ informatii. un progam Java ¸ trebuie s˘ deschid˘ un canal de comunicatie (flux) de la sursa informatiilor a a ¸ ¸ (fi¸ier.1 4. s s a a ¸ ¸ Similar. etc) ¸i s˘ citeasc˘ secvential informatiile respective. etc. ˆ retea. ˆ memorie s ın ¸ ın sau ˆ alt program ¸i poate fi de orice tip: date primitive. un program poate trimite informatii c˘tre o destinatie extern˘ ¸ a ¸ a deschizˆnd un canal de comunicatie (flux) c˘tre acea destinatie ¸i scriind a ¸ a ¸ s secvential informatiile respective. } inchide canal comunicatie. Pentru a aduce informatii dintr-un mediu extern.1 Introducere Ce sunt fluxurile? Majoritatea aplicatiilor necesit˘ citirea unor informatii care se g˘sesc pe ¸ a ¸ a o surs˘ extern˘ sau trimiterea unor informatii c˘tre o destinatie extern˘. atˆt sursa extern˘ a unor date cˆt ¸i destinatia lor a a a s ¸ sunt v˘zute ca fiind ni¸te procese care produc. Pentru a generaliza. memorie. imagini.1.Capitolul 4 Intr˘ri ¸i ie¸iri a s s 4.

io. ¸ a Fiecare flux are un singur proces produc˘tor ¸i un singur proces consumator. Deci.*. dar pe fluxuri diferite. Un flux care cite¸te date se nume¸te flux de intrare. de la produc˘tor la consumator. orice program care necesit˘ operatii de intrare sau ie¸ire trea ¸ s buie s˘ contin˘ instructiunea de import a pachetului java. orice proces putˆnd fi atˆt proa a a a ducator cˆt ¸i consumator ˆ acela¸i timp. a Un proces care descrie o surs˘ extern˘ de date se nume¸te proces produc˘tor. INTRARI SI IESIRI ¸ ¸ Definitii: ¸ Un flux este un canal de comunicatie unidirectional ˆ ¸ ¸ ıntre dou˘ procese.io: a ¸ a ¸ import java.1. a a s a Un proces care descrie o destinatie extern˘ pentru date se nume¸te proces ¸ a s consumator. s s Un flux care scrie date se nume¸te flux de ie¸ire. Clasele ¸i intefetele standard pentru lucrul cu fluxuri se g˘sesc ˆ pachetul s ¸ a ın java.io.96 ˘ CAPITOLUL 4. ¸ ¸ Fluxurile sunt unidirectionale. 4. a s ın s Consumatorul ¸i producatorul nu comunic˘ direct printr-o interfat˘ de flux s a ¸a ci prin intermediul codului Java de tratare a fluxurilor. a s Intre dou˘ procese pot exista oricˆte fluxuri. s s Observatii: ¸ Fluxurile sunt canale de comunicatie seriale pe 8 sau 16 biti.2 Clasificarea fluxurilor Exist˘ trei tipuri de clasificare a fluxurilor: a • Dup˘ directia canalului de comunicatie deschis fluxurile se ˆ a ¸ ¸ ımpart ˆ ın: – fluxuri de intrare (pentru citirea datelor) – fluxuri de ie¸ire (pentru scrierea datelor) s • Dup˘ tipul de date pe care opereaz˘: a a – fluxuri de octeti (comunicarea serial˘ se realizeaz˘ pe 8 biti) ¸ a a ¸ – fluxuri de caractere (comunicarea serial˘ se realizeaz˘ pe 16 biti) a a ¸ .

BufferedWriter..1.pentru fluxuri de ie¸ire. f˘r˘ ca acest lucru s˘ a s aa a fie obligatoriu. fiec˘rui flux de intrare XInputStream corea spunzˆndu-i uzual un flux de ie¸ire XOutputStream. etc.4. . cum ar fi ˆ exemplele: FileReader. ın ¸ ın BufferedReader.pentru fluxuri de intrare ¸i s • OutputStream. etc.pentru fluxuri de ie¸ire. toate clasele din aceste ierarhii vor avea terminatia a a ¸ Reader sau Writer ˆ functie de tipul lor. faptul c˘ unui flux de intrare XReader ˆ a a a a a ıi corespunde uzual un flux de ie¸ire XWriter.1. BufferedOutputStream. Clasele radacin˘ pentru ierarhia fluxurilor de octeti sunt: a ¸ • InputStream. BufferedInputStream.3 Ierarhia claselor pentru lucrul cu fluxuri Clasele r˘d˘cin˘ pentru ierarhiile ce reprezint˘ fluxuri de caractere sunt: a a a a • Reader. Ca o regul˘ general˘. INTRODUCERE • Dup˘ actiunea lor: a ¸ 97 – fluxuri primare de citire/scriere a datelor (se ocup˘ efectiv cu a citirea/scrierea datelor) – fluxuri pentru procesarea datelor 4. s Acestea sunt superclase abstracte pentru clase ce implementeaz˘ fluxuri a specializate pentru citirea/scrierea datelor pe 8 biti.pentru fluxuri de intrare ¸i s • Writer. se observ˘ ca o alt˘ regul˘ general˘. De asemenea. s Acestea sunt superclase abstracte pentru toate clasele ce implementeaz˘ a fluxuri specializate pentru citirea/scrierea datelor pe 16 biti ¸i vor contine ¸ s ¸ metodele comune tuturor. FileWriter. FileOutputStream. Ca ¸i ˆ cazul flux¸ s ın urilor pe caractere denumirile claselor vor avea terminatia superclasei lor: ¸ FileInputStream. ˆ a acest lucru nu este obligas ıns˘ toriu.

Pentru majoritatea pros ¸ gramelor este recomandat ca scrierea ¸i citirea datelor s˘ se fac˘ prin inters a a mediul fluxurilor de caractere. In cazul ˆ care a a ın aceasta nu este apelat˘ explicit. INTRARI SI IESIRI ¸ ¸ Pˆn˘ la un punct.4 Metode comune fluxurilor Superclasele abstracte Reader ¸i InputStream definesc metode similare pens tru citirea datelor. saltul peste un num˘r de pozitii. deoarece acestea permit manipularea caracterelor Unicode ˆ timp ce fluxurile de octeti permit doar lucrul pe 8 biti ın ¸ caractere ASCII. fluxul va fi automat ˆ a ınchis de c˘tre colectorul a de gunoaie atunci cˆnd nu va mai exista nici o referint˘ la el..98 ˘ CAPITOLUL 4. a datele din memorie vor fi pierdute la ˆ ınchiderea fluxului de c˘tre gc. ˆ a acest lucru a ¸a ıns˘ trebuie evitat deoarece. ambele clase pun la dispozitie metode pentru marcarea ¸ unei locatii ˆ ¸ ıntr-un flux.. Acestea sunt ˆ a mai rar folosite ¸i nu vor fi detaliate. a Metodele referitoare la fluxuri pot genera exceptii de tipul IOException ¸ sau derivate din aceast˘ clas˘.. 4. Reader InputStream int read() int read() int read(char buf[]) int read(byte buf[]) . Inchiderea oric˘rui flux se realizeaz˘ prin metoda close... etc. la lucrul cu fluxrui cu zon˘ tampon de memorie. . exist˘ un paralelism ˆ a a a ıntre ierarhia claselor pentru fluxuri de caractere ¸i cea pentru fluxurile pe octeti. tratarea lor fiind obligatorie. InputStream void write(int c) void write(byte buf[]) . ıns˘ s Superclasele abstracte Writer ¸i OutputStream sunt de asemenea paralele.1. s definind metode similare pentru scrierea datelor: Reader void write(int c) void write(char buf[]) void write(String str) . a a ... resetarea pozitiei a ¸ ¸ curente.. De asemenea.

1 Fluxuri primitive Fluxurile primitive sunt responsabile cu citirea/scrierea efectiv˘ a datelor. precum ¸i a s s modalit˘¸ile de creare ¸i utilizare a fluxurilor.2 Folosirea fluxurilor A¸a cum am v˘zut. ¸ a s • Memorie CharArrayReader.4. fluxurile pot fi ˆ artite ˆ functie de activitatea lor s a ımp˘ ¸ ın ¸ ˆ fluxuri care se ocup˘ efectiv cu citirea/scrierea datelor ¸i fluxuri pentru ın a s procesarea datelor (de filtrare). ByteArrayOutputStream Aceste fluxuri folosesc pentru scrierea/citirea informatiilor ˆ ¸ ın/din memorie ¸i sunt create pe un vector existent deja. CharArrayWriter ByteArrayInputStream. • Pipe PipedReader. at s 4. respectiv a ¸ a a write. permit s tratarea vectorilor ca surs˘/destinatie pentru crearea unor fluxuri de a ¸ intrare/ie¸ire.2. In continuare. s StringReader. a punˆnd la dispozitie implement˘ri ale metodelor de baz˘ read. FileOutputStream Numite ¸i fluxuri fi¸ier. respectiv scrierea datelor ˆ s ıntr-un fi¸ier ¸i vor fi analizate s s ˆ ıntr-o sectiune separat˘ (vezi ”Fluxuri pentru lucrul cu fi¸iere”). definite ˆ superclase. PipedWriter PipedInputStream.2. Cu alte cuvinte. In functie de tipul sursei datelor. vom vedea care sunt cele mai importante clase din cele dou˘ categorii ¸i la ce folosesc acestea. PipedOutputStream Implementeaz˘ componentele de intrare/ie¸ire ale unei conducte de a s . acestea sunt folosite pentru citirea datelor s s dintr-un fi¸ier. StringWriter Permit tratarea ¸irurilor de caractere aflate ˆ memorie ca surs˘/destinatie s ın a ¸ pentru crearea de fluxuri. FileWriter FileInputStream. FOLOSIREA FLUXURILOR 99 4. ele pot fi ın ¸ ˆ artite astfel: ımp˘ ¸ • Fi¸ier s FileReader.

De exemplu.2 Fluxuri de procesare Fluxurile de procesare (sau de filtrare) sunt responsabile cu preluarea datelor de la un flux primitiv ¸i procesarea acestora pentru a le oferi ˆ s ıntr-o alt˘ form˘. a un flux OutputStreamWriter converte¸te caractere ˆ octeti ¸i trimite s ın ¸ s rezutatul c˘tre un flux de tipul OutputStream. OutputStreamWriter Formeaz˘ o punte de legatur˘ ˆ a a ıntre fluxurile de caractere ¸i fluxurile s de octeti. reducˆnd astfel num˘rul de acces˘ri la dispozitivul ce ¸ a a a reprezint˘ sursa/destinatia original˘ a datelor. a . a s • Filtrare FilterReader. a a mai util˘ dintr-un anumit punct de vedere. FileReader nu putea citi decˆt caracter s a cu caracter. FilterWriter FilterInputStream. FilterOutputStream Sunt clase abstracte ce definesc o interfat˘ comun˘ pentru fluxuri care ¸a a filtreaz˘ automat datele citite sau scrise (vezi ”Fluxuri pentru filtrare”). BufferedWriter BufferedInputStream. Fiind primitiv. BufferedReader a poate prelua date de la un flux FileReader ¸i s˘ ofere informatia dintr-un s a ¸ fi¸ier linie cu linie. Un flux de procesare nu poate fi folosit decˆt ˆ a ımpreun˘ cu un a flux primitiv. Similar. BufferedOutputStream Sunt folosite pentru a introduce un buffer ˆ procesul de citire/scriere ın a informatiilor. folosind codificarea stans ıi s dard a caracterelor sau o codificare specificat˘ de program. ¸ a ¸ 4.100 ˘ CAPITOLUL 4. Un flux InputStreamReader cite¸te octeti dintr-un flux ¸ s ¸ InputStream ¸i ˆ converte¸te la caractere. Sunt mult mai eficiente a ¸ a decˆt fluxurile f˘r˘ buffer ¸i din acest motiv se recomand˘ folosirea lor a aa s a ori de cˆte ori este posibil (vezi ”Citirea ¸i scrierea cu zona tampon”). a • Conversie octeti-caractere ¸ InputStreamReader. Pipe-urile sunt folosite pentru a canaliza ie¸irea unui pros gram sau fir de executie c˘tre intrarea altui program sau fir de executie.2. Clasele ce descriu aceste fluxuri pot fi ˆ ımpartite ˆ functie de tipul de ın ¸ procesare pe care ˆ efectueaza astfel: ıl • ”Bufferizare” BufferedReader. INTRARI SI IESIRI ¸ ¸ date (pipe).

3 Crearea unui flux Orice flux este un obiect al clasei ce implementeaz˘ fluxul respectiv. ObjectOutputStream Sunt folosite pentru serializarea obiectelor (vezi ”Serializarea obiectelor”).4. • Citire ˆ avans ın PushbackReader PushbackInputStream Sunt fluxuri de intrare care au un buffer de 1-caracter(octet) ˆ care ın este citit ˆ avans ¸i caracterul (octetul) care urmeaz˘ celui curent citit. • Conversie tipuri de date DataInputStream.2. prin instructiunea a s ¸ new ¸i invocarea unui constructor corespunz˘tor al clasei respective: s a Exemple: . DataOutputStream Folosite la scrierea/citirea datelor de tip primitiv ˆ ıntr-un format binar. a ¸ 4. Crearea a unui flux se realizeaz˘ a¸adar similar cu crearea obiectelor. s • Num˘rare a LineNumberReader LineNumberInputStream Ofer˘ ¸i posibilitatea de num˘rare automat˘ a liniilor citite de la un as a a flux de intrare. FOLOSIREA FLUXURILOR 101 • Concatenare SequenceInputStream Concateneaz˘ mai multe fluxuri de intrare ˆ a ıntr-unul singur (vezi ”Concatenarea fi¸ierelor”). ın s a • Afi¸are s PrintWriter PrintStream Ofer˘ metode convenabile pentru afisarea informatiilor. independent de ma¸ina pe care se lucreaz˘ (vezi ”Folosirea claselor s a DataInputStream ¸i DataOutputStream”).2. s • Serializare ObjectInputStream.

constructorii claselor pentru fluxurile de procesare nu primesc ca argument un dispozitiv extern de memorare a datelor ci o referinta la un flux primitiv responsabil ¸ cu citirea/scrierea efectiv˘ a datelor: a Exemple: //crearea unui flux de intrare printr-un buffer BufferedReader in = new BufferedReader( new FileReader("fisier.txt").txt")).txt"). INTRARI SI IESIRI ¸ ¸ //crearea unui flux de intrare pe caractere FileReader in = new FileReader("fisier. //crearea unui flux de intrare pe octeti FileInputStream in = new FileInputStream("fisier.dat"). Din acest motiv. A¸adar. //crearea unui flux de iesire printr-un buffer BufferedWriter out = new BufferedWriter( new FileWriter("fisier.dat"). //crearea unui flux de iesire pe caractere FileWriter out = new FileWriter("fisier.txt"). BufferedReader in = new BufferedReader(fr). Fluxurile de procesare nu pot exista de sine st˘t˘toare ci se suprapun pe aa un flux primitiv de citire/scriere a datelor.102 ˘ CAPITOLUL 4. crearea unui flux pentru procesarea datelor are formatul general: s . BufferedWriter out = new BufferedWriter(fo). A¸adar.txt"). //echivalent cu FileWriter fo = new FileWriter("fisier.txt"))). //crearea unui flux de iesire pe octeti FileOutputStrem out = new FileOutputStream("fisier. crearea unui flux primitiv de date care cite¸te/scrie informatii de s s ¸ la un dispozitiv extern are formatul general: FluxPrimitiv numeFlux = new FluxPrimitiv(dispozitivExtern). //echivalent cu FileReader fr = new FileReader("fisier.

dat"))). on obiect de tip File s s sau un obiect de tip FileDesciptor (vezi ”Clasa File”). clasele care implementeaz˘ aceste fluxuri sunt a a a urm˘toarele: a FileReader. 4. respectiv scrierea unui caracter sau octet ¸ a dintr-un sau ˆ ıntr-un fi¸ier specificat uzual prin numele s˘u complet sau relativ s a la directorul curent. fluxurile pot fi compuse ˆ succesiuni oricˆt de lungi: ın a DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream("fisier. In general. Dup˘ cum am v˘zut deja. Acesta poate fi un ¸ir de caractere. FileOutputStream . FileWriter . Constructorii clasei FileReader sunt: public FileReader(String fileName) throws FileNotFoundException public FileReader(File file) throws FileNotFoundException public FileReader(FileDescriptor fd) Constructorii clasei FileWriter: public FileWriter(String fileName) throws IOException public FileWriter(File file) throws IOException public FileWriter(FileDescriptor fd) public FileWriter(String fileName. boolean throws IOException append) . ˆ ıntrucˆt a operatia lor de baz˘ este citirea. FOLOSIREA FLUXURILOR 103 FluxProcesare numeFlux = new FluxProcesare(fluxPrimitiv).octeti Constructorii acestor clase accept˘ ca argument un obiect care s˘ specifice a a un anume fi¸ier.caractere FileInputStream.4 Fluxuri pentru lucrul cu fi¸iere s Fluxurile pentru lucrul cu fi¸iere sunt cele mai usor de ˆ s ınteles.2.2.4.

printStackTrace () . while (( c = in . out . in . read () ) != -1) out . txt " ) . Din acest motiv orice ın s a creare a unui flux de acest tip trebuie f˘cut˘ ˆ a a ıntr-un bloc try-catch sau metoda ˆ care sunt create fluxurile respective trebuie s˘ arunce exceptiile ın a ¸ de tipul FileNotFoundException sau de tipul superclasei IOException. a Dac˘ exist˘ fi¸ierul ”in.txt”.104 ˘ CAPITOLUL 4. } } } In cazul ˆ care vom lansa aplicatia iar ˆ directorul curent nu exist˘ un ın ¸ ın a fi¸ier cu numele ”in.txt” ˆ care a a s ¸ s ın va fi copiat continutul primului.1: Copierea unui fisier import java . println ( " Eroare la operatiile cu fisiere ! " ) . int c . close () . S˘ consider˘m ca exemplu un program care copie continutul unui fi¸ier a a ¸ s cu numele ”in. FileWriter out = new FileWriter ( " out . close () . Ambele fi¸iere sunt s s considerate ˆ directorul curent.txt” ˆ ıntr-un alt fi¸ier cu numele ”out. public class Copiere { public static void main ( String [] args ) { try { FileReader in = new FileReader ( " in . Ace¸tia pot provoca exceptii de tipul FileNotFoundException ˆ s s ¸ ın cazul ˆ care fi¸ierul cu numele specificat nu exist˘. txt " ) .txt”. write ( c ) . va fi generat˘ o exceptie de tipul s a ¸ FileNotFoundException. Dac˘ exist˘ deja fi¸ierul ”out. err . aplicatia va crea un nou fi¸ier ”out.txt” el va fi re¸ a a s . INTRARI SI IESIRI ¸ ¸ Cei mai uzuali constructori sunt cei care primesc ca argument numele fi¸ierului.txt”. Aceasta va fi prins˘ de program deoarece. } catch ( IOException e ) { System .*. IOException a este superclas˘ pentru FileNotFoundException. e . ın Listing 4. io .

s s La operatiile de scriere datele scrise nu vor ajunge direct la destinatie. vor fi memorati ˆ buffer ¸i caracterele s a ın s care ˆ urmeaz˘. Dac˘ doream s˘ facem operatia de ad˘ugare(append) ¸i nu de rescriere a a ¸ a s pentru fi¸ierul ”out. Atunci cˆnd se execut˘ o operatie de citire.caractere BufferedInputStream. FOLOSIREA FLUXURILOR 105 scris. BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream("out. BufferedOutputStream . BufferedInputStream functioneaz˘ dup˘ acela¸i ıi a ¸ a a s principiu. In cazul ˆ care buffer-ul este gol. 4. caracterul va fi prea a ¸ luat din buffer. dintre care obligatoriu unul este primitiv. Din acest motiv.2. ¸ ¸ Fluxurile de citire/scriere cu buffer sunt fluxuri de procesare ¸i sunt s folosite prin suprapunere cu alte fluxuri. 1024) //1024 este dimensiunea bufferului Constructorii cei mai folositi ai acestor clase sunt urm˘torii: ¸ a BufferedReader(Reader in) BufferedReader(Reader in.txt". true). odat˘ cu citirea caracterului. reducˆnd astfel numarul de acces˘ri ale ¸ a a dispozitivului ce reprezint˘ sursa/destinatia atelor. Evident. ci vor ¸ ¸ fi memorate jntr-un buffer de o anumit˘ dimensiune. int dim_buffer) BufferedWriter(Writer out) .txt” foloseam: s FileWriter out = new FileWriter("out. citirea se face direct din ın flux ¸i.octeti Sunt folosite pentru a introduce un buffer (zon˘ de memorie) ˆ procea ın sul de citire/scriere a informatiilor.dat"). continutul acestuia va fi transferat automat la destinatie. ¸a a ¸ ¸ Similar lucreaza ¸i clasele BufferedWriter ¸i BufferedOutputStream. a Clasa BufferedReader cite¸te ˆ avans date ¸i le memoreaz˘ ˆ s ın s a ıntr-o zon˘ a tampon. BufferedWriter .4.2. Atunci cˆnd bufferul a a este plin. sunt a ¸ mult mai eficiente decˆt fluxurile f˘r˘ buffer ¸i din acest motiv se recomand˘ a aa s a folosirea lor ori de cˆte ori este posibil.5 Citirea ¸i scrierea cu buffer s Clasele pentru citirea/scrierea cu zona tampon sunt: BufferedReader. singura diferent˘ fiind faptul c˘ sunt cititi octeti.

. ın ¸ BufferedReader br = new BufferedReader(new FileReader("in")) String linie. } . 1024) //am creat un flux cu buffer de 1024 octeti for(int i=0. Pe lˆnga s a acestea. i++) out. clasele pentru scriere prin buffer mai au ¸i metoda flush care gole¸te s s explicit zona tampon.flush(). //proceseaza linie } br. while ((linie = br. i<1000. ın a aceasta prime¸te valoarea implicit˘ de 512 octeti (caractere).close(). int dim_buffer) BufferedOutputStream(OutputStream out) BufferedOutputStream(OutputStream out. a a BufferedWriter out = new BufferedWriter( new FileWriter("out. //bufferul nu este plin.106 ˘ CAPITOLUL 4. in fisier nu s-a scris nimic out. datele se scriu in fisier Metoda readLine Este specific˘ fluxurilor de citire cu buffer ¸i permite citirea linie cu linie a a s datelor de intrare. INTRARI SI IESIRI ¸ ¸ BufferedWriter(Writer out.write(i).readLine()) != null) { .dat"). //bufferul este golit. int dim_buffer) BufferedInputStream(InputStream in) BufferedInputStream(InputStream in. dependent de platforma de lucru.. int dim_buffer) In cazul constructorilor ˆ care dimensiunea buffer-ului nu este specificat˘. chiar dac˘ aceasta nu este plin˘. s a ¸ Metodele acestor clase sunt cele uzuale de tipul read ¸i write. Acesta as este reprezentat ˆ Java prin secventa escape ’\n’. O linie reprezint˘ o succesiune de caractere terminat˘ cu a a simbolul pentru sfˆr¸it de linie.

SequenceInputStream s = new S eq u e nc e I np u tS t r ea m ( f1 .*. Rezultatul concatenarii este afisat pe ecran . Fiecare obiect ˆ enumerarea primit˘ ca parametru trebuie s˘ fie de ın a a tipul InputStream.4. exit ( -1) .2. dup˘ care procesul se ın a repet˘ pˆna la terminarea tuturor fluxurilor de intrare. a a Constructorii acestei clase sunt: SequenceInputStream(Enumeration e) SequenceInputStream(InputStream s1. out . Cel de-al doilea construie¸te un flux de intrare care combin˘ doar dou˘ fluxuri s a a s1 ¸i s2. System . . Citirea datelor dintr-un astfel de flux se face astfel: se cite¸te din s primul flux de intrare specificat pˆna cˆnd se ajunge la sfˆrsitul acestuia. a a a dup˘ care primul flux de intrare este ˆ a ınchis ¸i se deschide automat urm˘torul s a flux de intrare din care se vor citi ˆ continuare datele. read () ) != -1) System . out .2: Concatenarea a dou˘ fi¸iere a s /* Concatenarea a doua fisiere ale caror nume sunt primite de la linia de comanda . print (( char ) c ) . */ import java . FOLOSIREA FLUXURILOR 107 4. InputStream s2) Primul construieste un flux secvential dintr-o multime de fluxuri de in¸ trare. f2 ) . length <= 1) { System .6 Concatenarea fluxurilor Clasa SequenceInputStream permite unei aplicatii s˘ combine serial mai a multe fluxuri de intrare astfel ˆ at acestea s˘ apar˘ ca un singur flux de ıncˆ a a intrare. while (( c = s . primul flux citit fiind s1. s Exemplul cel mai elocvent de folosirea a acestei clase este concatenarea a dou˘ sau mai multor fi¸iere: a s Listing 4. io . } try { FileInputStream f1 = new FileInputStream ( args [0]) . int c . FileInputStream f2 = new FileInputStream ( args [1]) . public class Concatenare { public static void main ( String args []) { if ( args .2. println ( " Argumente insuficiente ! " ) .

close () . BufferedOutputStream LineNumberInputStream PushbackInputStream PrintStream .pentru filtrarea fluxurilor de intrare ¸i s • FilterOutputStream . Clasele pentru filtrarea datelor superclasele a abstracte: • FilterInputStream . 4. FileInputStream f3 = new FileInputStream(args[2]). DataOutputStream BufferedInputStream. INTRARI SI IESIRI ¸ ¸ s .7 Fluxuri pentru filtrarea datelor Un flux de filtrare se ata¸eaz˘ altui flux pentru a filtra datele care sunt s a citite/scrise de c˘tre acel flux. cona catenarea a 3 fi¸iere va construi un flux de intrare astfel: s FileInputStream f1 = new FileInputStream(args[0]). printStackTrace () .108 ˘ CAPITOLUL 4.pentru filtrarea fluxurilor de ie¸ire. f3)). a ¸ • concatenarea pe rˆnd a acestora folosind al 2-lea constructor. SequenceInputStream s = new SequenceInputStream( f1. // f1 si f2 sunt inchise automat } catch ( IOException e ) { e . s Cele mai importante fluxruri pentru filtrarea datelor sunt implementate de clasele: DataInputStream. FileInputStream f2 = new FileInputStream(args[1]). new SequenceInputStream(f2.primul constructor (vezi ”Colectii”). } } } Pentru concatenarea mai multor fi¸iere exist˘ dou˘ variante: s a a • folosirea unei enumer˘ri .2.

a A¸adar. Prin urmare. altele decˆt cele comune tuturor fluxurilor.8 Clasele DataInputStream ¸i DataOutputStream s Aceste clase ofer˘ metode prin care un flux nu mai este v˘zut ca o ˆ a a ınsiruire de octeti.2. urmˆnd ca citirea/scrierea s˘ se a a fac˘ prin intermediu acelui buffer. ele mai fiind numite ¸i fluxuri de procesare. fluxurile de filtrare nu elimin˘ date citite sau scrise de un anumit s a flux. ci de date primitive. clasele de filtrare BufferedInputStream ¸i BufferedOutputStream s colecteaz˘ datele unui flux ˆ a ıntr-un buffer. s s Clasele care ofer˘ un astfel de suport implementeaz˘ interfetele DataInput. FOLOSIREA FLUXURILOR Observati c˘ toate aceste clase descriu fluxuri de octeti. altele decˆt cele a comune tuturor fluxurilor.2. 4. fluxurile de filtrare vor contine s ¸ anumite metode specializate pentru citirea/scrierea datelor. ¸ a ¸ 109 Filtrarea datelor nu trebuie v˘zut˘ ca o metod˘ de a elimina anumiti a a a ¸ octeti dintr-un flux ci de a transforma ace¸ti octeti ˆ date care s˘ poat˘ fi s ¸ ın a a interpretate sub alt˘ form˘. vor furniza metode pentru ¸ citirea ¸i scrierea datelor la nivel de tip primitiv ¸i nu la nivel de octet. De exemplu. sunt date ˆ tabelul de a ın mai jos: . ci introduc o noua modalitate de manipulare a lor. A¸a cum am v˘zut la citirea/scrierea cu zon˘ a a s a a tampon. Cele mai folosite ¸ ın metode. a a ¸ respectiv DataOutput. clasa BufferedInputStream pune la dispozitie metoda readLine pentru citirea unei linii din fluxul de intrare.4. ¸ Folosirea fluxurilor de filtrare se face prin ata¸area lor de un flux care se s ocup˘ efectiv de citirea/scrierea datelor: a FluxFiltrare numeFlux = new FluxFiltrare(referintaAltFlux). Din acest motiv. Acestea definesc metodele pe care trebuie s˘ le pun˘ la a a dispozitie ˆ vederea citireii/scrierii datelor de tip primitiv.

a Transformarea unei valori ˆ format binar se nume¸te serializare. ¸a Scrierea datelor folosind fluxuri de acest tip se face ˆ format binar.5. INTRARI SI IESIRI ¸ ¸ DataOutputStream writeBoolean writeByte writeChar writeDouble writeFloat writeInt writeLong writeShort writeUTF Aceste metode au denumirile generice de readXXX ¸i writeXXX. sau chiar dintr-un ¸ obiect de tip File. 4.Scanner ofer˘ o solutie simpl˘ pentru formatarea unor informatii a ¸ a ¸ citite de pe un flux de intrare fie pe octeti. Denumirile lor sunt sugestive pentru tipul de date pe care ˆ ıl prelucreaz˘. limbajul Java pune la dispozitii modalit˘¸i sima ¸ at plificate pentru afi¸area formatat˘ a unor informatii.in: . cum ar fi ObjectInputStream ¸i a a s ObjectOutputStream (vezi ”Serializarea obiectelor”). Serializarea celorlalte tipuri referint˘ va fi s s ¸a f˘cut˘ prin intermediul altor clase.3.110 DataInputStream readBoolean readByte readChar readDouble readFloat readInt readLong readShort readUTF ˘ CAPITOLUL 4. a 4. specifis cate de interfetele DataInput ¸i DataOutput ¸i pot provoca exceptii de tipul s s ¸ IOException.1 Intr˘ri formatate a Clasa java. Pentru a citi de la tastatur˘ vom specifica ca argument a al constructorului fluxul System. respectiv pentru citirea s a ¸ de date formatate de la tastatur˘.util. Clasele ın s DataInputStream ¸i DataOutputStream permit serializarea tipurilor prims itive ¸i a ¸irurilor de caractere. ceea ın ce ˆ ınseamn˘ c˘ un fi¸ier ˆ care au fost scrise informatii folosind metode a a s ın ¸ writeXXX nu va putea fi citit decˆt prin metode readXXX. fie pe caractere.3 Intr˘ri ¸i ie¸iri formatate a s s Incepˆnd cu versiunea 1. mai putin readUTF ¸i writeUTF care se ocup˘ cu obiecte de tip a ¸ s a String. fiind singurul tip referint˘ permis de aceste clase.

close(). s.out.fluxul standar pentru erori. nume. de tip PrintStream s • System.util. System.out . println care ofereau posibilitatea de a afi¸a un ¸ir de caractere. printf (echivalente) ce permit afi¸area formatat˘ a unor s a variabile. salariu.2 Ie¸iri formatate s Clasele PrintStream ¸i PrintWriter pun la dispozitiile. de tip PrintStream . double salariu = s. pe lˆng˘ metodele s ¸ a a print.create(System.in). de tip InputStream • System.4. s Intrarea ¸i ie¸irea standard sunt reprezentate de obiecte pre-create ce s s descriu fluxuri de date care comunic˘ cu dispozitivele standard ale sistemului.3. s a 4. varsta). 111 4.nextInt().2f %2d %n".4. int varsta = s. FLUXURI STANDARD DE INTRARE SI IESIRE ¸ ¸ Scanner s = Scanner. ¸i s s s metodele format.in .printf("%s %8.next().err . String nume = s. orice program Java a a are : • o intrare standard • o ie¸ire standard s • o ie¸ire standard pentru erori s In general.fluxul standar de ie¸ire.nextDouble().4 Fluxuri standard de intrare ¸i ie¸ire s s Mergˆnd pe linia introdus˘ de sistemul de operare UNIX.fluxul standar de intrare. intrarea standard este tastatura iar ie¸irea standard este ecranul.Formatter. a Aceste obiecte sunt definite publice ˆ clasa System ¸i sunt: ın s • System. Formatarea ¸irurilor de caractere se bazeaz˘ pe clasa java.

System.in)). System. INTRARI SI IESIRI ¸ ¸ 4. System. argumente. a s el fiind folosit la afi¸area oric˘ror rezultate pe ecran (ˆ modul consola): s a ın System. as ¸ a as a a . este acela¸i cu fluxul standard ın ¸ ¸ s de ie¸ire.4.printf (format.1 Afisarea informatiilor pe ecran ¸ Am v˘zut deja numeroase exemple de utilizare a fluxului standard de ie¸ire.print("Introduceti o linie:").. fluxul a a standard de intrare System.out este de tip InputStream.2 Citirea datelor de la tastatur˘ a Uzual.4. deci pentru a-l putea utiliza eficient va trebui sa-l folosim ˆ a ımpreuna cu un flux de procesare(filtrare) care s˘ permit˘ citirea facil˘ a datelor. a a a 4.println("Exceptie:" + e). In schimb.out.out.). In exemplul urm˘tor este prezentat un program care afi¸eaza liniile introa s duse de la tastatur˘ pˆn˘ ˆ momentul ˆ care se introduce linia ”exit” sau a a a ın ın o linie vid˘ ¸i mentioneaz˘dac˘ ¸irul respectiv reprezint˘ un num˘r sau nu. Fluxul standard pentru afi¸area erorilor se folose¸te similar ¸i apare uzual s s s ˆ secventele de tratare a exceptiilor.). String linie = stdin. s catch(Exception e) { System.out.readLine() System. vom dori s˘ folosim metoda readLine pentru citirea datelor de la a tastatura ¸i din acest motiv vom folosi intrarea standard ˆ s ımpreun˘ cu o clas˘ a a de procesare care ofer˘ aceast˘ metod˘. care este o clas˘ a abstract˘.out. Implicit..out. System. argumente.println(linie). clas˘ concret˘ pentru scrierea datelor. } Fluxurile de ie¸ire pot fi folosite a¸adar f˘r˘ probleme deoarece tipul lor s s aa este PrintStream..out.. Exemplul tipic este: a a a BufferedReader stdin = new BufferedReader( new InputStreamReader(System.format (format.println(argument).err.print (argument).112 ˘ CAPITOLUL 4.

4.redirectare erori .redirectare iesire setErr(PrintStream) . length () ==0) break . readLine () . } catch ( Numb erFor ma t E x c e p t i o n e ) { System . out . a 4. print ( s ) . } } } 113 Incepˆnd cu versiunea 1. varianta cea mai comod˘ de citire a datelor a a de la tastatur˘ este folosirea clasei java.5.Scanner. System . out . try { while ( true ) { String s = stdin . FLUXURI STANDARD DE INTRARE SI IESIRE ¸ ¸ Listing 4. parseDouble ( s ) . try { Double . public class EsteNumar { public static void main ( String [] args ) { BufferedReader stdin = new BufferedReader ( new InputStreamReader ( System . println ( " Eroare la intrarea standard ! " ) . printStackTrace () . In clasa System exist˘ urm˘toarele metode statice a s a a care realizeaz˘ acest lucru: a setIn(InputStream) .4. equals ( " exit " ) || s . println ( " : DA " ) .4. respectiv alte destinatii decˆt ecranul pentru ¸ a cele dou˘ fluxuri de ie¸ire. out . System . } } } catch ( IOException e ) { System .*. in ) ) . io . e .3 Redirectarea fluxurilor standard Redirectarea fluxurilor standard presupune stabilirea unei alte surse decˆt a tastatura pentru citirea datelor. err . println ( " : NU " ) . if ( s .util.redirectare intrare setOut(PrintStream) .3: Citirea datelor de la tastatur˘ a /* Citeste siruri de la tastatura si verifica daca reprezinta numere sau nu */ import java .

BufferedReader br = new BufferedReader ( new InputStream Reader ( System . txt " ) ) .114 ˘ CAPITOLUL 4. a Listing 4. Redirectarea intr˘rii poate fi folositoare pentru un program ˆ mod cona ın sol˘ care prime¸te mai multe valori de intrare. System. Pentru a nu le scrie de la a s tastatur˘ de fiecare dat˘ ˆ timpul test˘rii programului. .setErr(fis). Redirectarea erorilor ˆ ıntr-un fi¸ier poate fi de asemenea util˘ ¸i se face ˆ s as ıntr-o manier˘ similar˘: a a PrintStream fis = new PrintStream( new FileOutputStream("erori.4: Exemplu de folosire a redirect˘rii: a import java . PrintStream out = new PrintStream ( new FileOutputStream ( " rezultate . redirectˆnd intrarea standard c˘tre acel fi¸ier. txt " ) ) . Secventa clasic˘ de redirectare a ie¸irii este c˘tre un ¸ ¸ a s a fi¸ier este: s PrintStream fis = new PrintStream( new FileOutputStream("rezultate. Putem redirecta afisarea c˘tre un fi¸ier pe care s˘-l citim dup˘ a s a a executia programului.txt"))).setOut(fis). System. datele fiind a a cerute din nou de la tastatur˘. setIn ( in ) . in ) ) . System . setErr ( err ) .txt"))). PrintStream err = new PrintStream ( new FileOutputStream ( " erori . In momentul cˆnd s a a s a testarea programului a luat sfˆrsit redirectarea poate fi eliminat˘. io . txt " ) ) . INTRARI SI IESIRI ¸ ¸ Redirectarea ie¸irii este util˘ ˆ special atunci cˆnd sunt afi¸ate foarte multe s a ın a s date pe ecran. class Redirectare { public static void main ( String [] args ) { try { BufferedInputS t r ea m in = new B uf f e re d I np u tS t r ea m ( new FileInputStream ( " intrare . System . setOut ( out ) .*. System . ele pot fi puse ˆ a a ın a ıntrun fi¸ier.

4 Analiza lexical˘ pe fluxuri (clasa StreamTokenizer) a Clasa StreamTokenizer proceseaz˘ un flux de intrare de orice tip ¸i ˆ ˆ a s ıl ımparte ˆ ”atomi lexicali”. pe rˆnd. txt */ System . etc. while (( s = br . println ( s ) . ace¸ti separas tori sunt cei obi¸nuti: spatiu. } // Aruncam fortat o exceptie throw new IOException ( " Test " ) .4. out . se vor citi. printStackTrace () . virgul˘. atomii lexicali ai fluxului respectiv. punct ¸i virgula.4. txt si vor fi scrise in fisierul rezultate . } } } 115 4. err . ¸ a Printr-un atom lexical se ˆ ın]elege ˆ general: ın • un identificator (un ¸ir care nu este ˆ s ıntre ghilimele) • un numar • un ¸ir de caractere s • un comentariu • un separator Atomii lexicali sunt desp˘rtiti ˆ a ¸ ıntre ei de separatori. ¸ Constructorii clasei sunt: . ele vor fi scrise in fisierul erori . } catch ( IOException e ) { /* Daca apar exceptii . Implicit. tab.4. txt */ System . readLine () ) != null ) { /* Liniile vor fi citite din fisierul intrare . FLUXURI STANDARD DE INTRARE SI IESIRE ¸ ¸ String s .. println ( " Eroare intrare / iesire ! " ) . e . ˆ a pot fi s ¸ ¸ a s ıns˘ schimbati prin diverse metode ale clasei. Rezultatul va consta ˆ faptul c˘ ˆ loc s˘ se citeasc˘ ın ın a ın a a octeti sau caractere.

// Se citeste primul atom lexical .valoarea unui atom numeric • sval .un fisier specificat si afisarea tipului si valorii lor */ import java .tipul ultimului atom citit din flux • nval.atom ce marcheaz˘ sfˆar¸itul fluxului a a s • TT EOL . a Exemplul tipic de folosire a unui analizor lexical este citirea unei secvente ¸ de numere ¸i ¸iruri aflate ˆ s s ıntr-un fi¸ier sau primite de la tastatur˘: s a Listing 4.*. int tip = st .atom ce marcheaz˘ sfˆr¸itul unei linii a as • TT NUMBER . txt " ) ) . INTRARI SI IESIRI ¸ ¸ public StreamTokenizer(Reader r) public StreamTokenizer(InputStream is) Identificarea tipului ¸i valorii unui atom lexical se face prin intermediul s variabilelor: • TT EOF . nextToken () . public class CitireAtomi { public static void main ( String args []) throws IOException { BufferedReader br = new BufferedReader ( new FileReader ( " fisier .valoarea unui atom de tip cuvˆnt a Citirea atomilor din flux se face cu metoda nextToken().atom de tip cuvˆnt a • ttype.5: Citirea unor atomi lexicali dintr-un fisier /* Citirea unei secvente de numere si siruri dintr .atom de tip num˘r a • TT WORD. io . care returnez˘ a tipul atomului lexical citit ¸i scrie ˆ variabilele nval sau sval valoarea cores ın spunzato˘re atomului. StreamTokenizer st = new StreamTokenizer ( br ) .116 ˘ CAPITOLUL 4.

out . a s a In cazul ˆ care tipul atomilor nu ne intereseaz˘. ın a pˆna se ajunge la sfˆrsitul fluxului (TT EOF). a aa a a • se g˘se¸te ˆ pachetul java. 4. TT_EOF ) { switch ( tip ) { case StreamTokenizer . } tip = st . println ( " Cuvant : " + st .5. CLASA RANDOMACCESFILE (FISIERE CU ACCES DIRECT) ¸ while ( tip != StreamTokenizer . sval ) . break . subclas˘ direct˘ a clasei Object.io. TT_WORD : System . nextToken () . fluxurile sunt procese secventiale de intrare/ie¸ire. ˆ care se citesc atomii unul cˆte unul cu metoda nextToken. a s ın . a Clasa RandomAccesFile are urm˘toarele caracteristici: a • permite accesul nesecvential (direct) la continutul unui fi¸ier. a a ¸ s Acestea sunt adecvate pentru lucrul cu medii secventiale de memorare a ¸ datelor. sau metoda split a clasei ımp˘ ¸ s ın String.5 Clasa RandomAccesFile (fi¸iere cu acces dis rect) Dup˘ cum am v˘zut. TT_NUMBER : System . este mai simplu s˘ ın a a citim fluxul linie cu linie ¸i s˘ folosim clasa StringTokenizer. // Trecem la urmatorul atom } } } 117 A¸adar. In cadrul buclei ”while” se detera a min˘ tipul atomul curent curent (ˆ a ıntors de metoda nextToken) ¸i apoi se afl˘ s a valoarea numeric˘ sau ¸irul de caractere corespunz˘tor atomului respectiv. modul de utilizare tipic pentru un analizor lexical este ˆ s ıntr-o bucla ”while”. cum ar fi banda magnetic˘ sau pentru transmiterea informatiilor a ¸ prin retea.4. care realizeaz˘ s a a ˆ artirea unui ¸ir de caractere ˆ atomi lexicali. println ( " Numar : " + st . out . nval ) . ¸ ¸ s • este o clas˘ de sine st˘t˘toare. case StreamTokenizer . desi sunt foarte utile ¸i pentru dispozitive ˆ care informatia poate ¸ s ın ¸ fi accesat˘ direct.

118 ˘ CAPITOLUL 4. indicˆnd ˆ a ınceputul fi¸ierului. a a s s • permite specificarea modului de acces al unui fi¸ier (read-only. La deschiderea unui fi¸ier a ¸ a ın s s pointerul are valoarea 0. s In plus fat˘de metodele de tip read ¸i write clasa pune la dispozitie ¸i ¸a s s metode pentru controlul pozitiei pointerului de fi¸ier. "rw"). Acestea sunt: ¸ s • skipBytes .fi¸ierul este deschis pentru citire ¸i scriere (read-write) s s Exemple: RandomAccesFile f1 = new RandomAccessFile("fisier. INTRARI SI IESIRI ¸ ¸ • implementeaz˘ interfetele DataInput ¸i DataOutput.txt".returneaz˘ pozitia pointerului de fi¸ier. ceea ce ˆ a ¸ s ınseamna ca sunt disponibile metode de tipul readXXX. s • permite atˆt citirea cˆt ¸i scriere din/in fi¸iere cu acces direct. //deschide un fisier pentru citire RandomAccesFile f2 = new RandomAccessFile("fisier. Constructorii acestei clase sunt: RandomAccessFile(StringnumeFisier. Apeluri la metodele s de citire/scrirere deplaseaz˘ pointerul fi¸ierului cu num˘rul de octeti cititi a s a ¸ ¸ sau scri¸i de metodele respective. StringmodAcces) throws IOException RandomAccessFile(StringnumeFisier. a ¸ s .mut˘ pointerul fi¸ierului ˆ a s ınainte cu un num˘r specificat de a octeti ¸ • seek .fi¸ierul este deschis numai pentru citire (read-only) s • ”rw” . ˆ ıntocmai ca la clasele DataInputStream ¸i DataOutputStream.txt". StringmodAcces) throws IOException unde modAcces poate fi: • ”r” . "r"). reads write). //deschide un fisier pentru scriere si citire Clasa RandomAccesFile suport˘ notiunea de pointer de fi¸ier. writeXXX.pozitioneaza pointerului fi¸ierului ˆ ¸ s ınaintea unui octet specificat • getFilePointer . Acesta este a ¸ s un indicator ce specific˘ pozitia curent˘ ˆ fi¸ier.

Trebuie mentionat ¸i faptul c˘ majoritatea constructorilor fluxurilor care ¸ s a permit accesul la fi¸iere accept˘ ca argument un obiect de tip File ˆ locul s a ın unui ¸ir ce reprezint˘ numele fi¸ierului respectiv. crearea unui director. s a s File f = new File("fisier. Numele directorului este primit ca argument de la linia de comanda . sau este directorul curent . ¸tergerea.6. ˆ aceast˘ clas˘ vom g˘si metode pentru testarea existentei. precum ¸i ¸ s s ¸a s a s punerea la dispozitie a unor metode pentru lucrul cu fisere ¸i directoare la ¸ s nivelul sistemului de operare. Pentru fiecare din ele vor fi afisate diverse informatii . Utilitate clasei File const˘ ˆ furnizarea unei modalit˘¸i de a abstractiza a ın at dependentele cailor ¸i numelor fi¸ierelor fat˘de ma¸ina gazd˘. io . ın a a a ¸ s redenumirea unui fi¸ier sau director. fie multimea fi¸ierelor dintr-un director.6 Clasa File Clasa File nu se refer˘ doar la un fi¸ier ci poate reprezenta fie un fi¸ier a s s anume.txt").6: Listarea continutului unui director ¸ /* Programul listeaza fisierele si subdirectoarele unui director . etc. pentru fiecare din ele afi¸eaz˘ diverse s s a informatii: ¸ Listing 4. s Specificarea unui fi¸ier/director se face prin specificarea c˘ii absolute spre s a acel fi¸ier sau a c˘ii relative fat˘ de directorul curent. listarea fi¸ierelor s s dintr-un director. CLASA FILE 119 4.*. Acestea trebuie s˘ res a ¸a a specte conventiile de specificare a c˘ilor ¸i numelor fi¸ierelor de pe platforma ¸ a s s de lucru. */ import java . Astfel.4. . FileInputStream in = new FileInputStream(f) Cel mai uzual constructor al clasei File este: public File(String numeFisier) Metodele mai importante ale clasei File au denumiri sugestive ¸i vor fi s prezentate prin intermediul exemplului urm˘tor care listeaz˘ fi¸ierele ¸i suba a s s directoarele unui director specificat ¸i.

println ( " Cale absoluta : " + f . isDirectory () ) System . try { File director = new File ( nume ) . i ++) info ( continut [ i ]) . lastModified () ) ) . canWrite () + " \ n Parinte : " + f . length () + " \ n Data ultimei modificari : " + new Date ( f . getParent () + " \ n Cale : " + f .. out . getName () . out ... println ( " Fisier : " + nume ) . System . for ( int i = 0. else if ( f . // directorul curent else nume = args [0]. getPath () + " \ n Lungime : " + f . INTRARI SI IESIRI ¸ ¸ private static void info ( File f ) { // Afiseaza informatii despre un fisier sau director String nume = f . if ( f . listFiles () .. File [] continut = director ... out .. public class ListareDirector { ˘ CAPITOLUL 4. } catch ( Exception e ) { e .. length . isFile () ) System . System . i < continut ." ) . getAbsolutePath () + " \ n Poate citi : " + f .. } public static void main ( String [] args ) { String nume .. if ( args . canRead () + " \ n Poate scrie : " + f .. println ( " Director : " + nume ) . " .120 import java . out . printStackTrace () . util ..*. length == 0) nume = " .. } } } . println ( " .

¸ a 121 . supunˆndu-se a a ¸ a a¸adar unui anumit comportament. punˆnd ˆ practic˘ unul din conceptele a a a ın a program˘rii orientate obiect ¸i anume cel de separare a modelului unui obiect a s (interfat˘) de implementarea sa. Interfetele permit.Capitolul 5 Interfete ¸ 5. definirea unor noi tipuri de date.1 5. A¸adar. al˘turi de clase. O clas˘ care implementeaz˘ o interfat˘ trebuie obligatoa a ¸a riu s˘ specifice implement˘ri pentru toate metodele interfetei. O interfat˘ Java define¸te un set de metode dar nu specific˘ nici o imple¸a s a mentare pentru ele.1. o interfat˘ poate fi privita ca un ¸a s ¸a protocol de comunicare ˆ ıntre obiecte. s Definitie ¸ O interfat˘ este o colectie de metode f˘r˘ implementare ¸i declaratii de ¸a ¸ aa s ¸ constante.1 Introducere Ce este o interfat˘ ? ¸a Interfetele duc conceptul de clas˘ abstract˘ cu un pas ˆ ¸ a a ınainte prin eliminarea oric˘ror implement˘ri de metode.

Constantele unei a ın ¸ ¸a interfete trebuie obligatoriu initializate. ¸ O interfat˘ poate extinde oricˆte interfete.. Acestea se numesc superinterfete ¸a a ¸ ¸ ¸i sunt separate prin virgul˘.1 Folosirea interfetelor ¸ Definirea unei interfete ¸ Definirea unei interfete se face prin intermediul cuvˆntului cheie interface: ¸ a [public] interface NumeInterfata [extends SuperInterfata1. (vezi ”Mo¸tenirea multipl˘ prin intermediul s a s a interfetelor”).122 CAPITOLUL 5. // Incorect. O interfat˘ ¸a s ¸a public˘ este accesibil˘ tuturor claselor. ¸ Corpul unei interfete poate contine: ¸ ¸ • constante: acestea pot fi sau nu declarate cu modificatorii public.2 5. // Incorect. indiferent de pachetul din care fac a a parte.] { /* Corpul interfetei: Declaratii de constane Declaratii de metode abstracte */ } O interfat˘ poate avea un singur modificator ¸i anume public.2. modificator nepermis } . static ¸i final care sunt impliciti. SuperInterfata2. implicit nivelul de acces fiind doar la nivelul pachetului din care face parte interfata. lipseste initializarea private int x = 1. ¸ ¸ interface Exemplu { int MAX = 100. // Echivalent cu: public static final int MAX = 100. int MAX. INTERFETE ¸ 5.. nici un alt modificator neputˆnd s ¸ a ap˘rea ˆ declaratia unei variabile dintr-o interfat˘.

5. s • Metodele unei interfete sunt implicit publice chiar dac˘ nu sunt declarate ¸ a cu modificatorul public. care este implicit. nici un alt modificator nu poate ap˘rea ˆ declaratia unei metode a unei interfete. a 5. .2 Implementarea unei interfete ¸ Implementarea uneia sau mai multor interfete de c˘tre o clas˘ se face prin ¸ a a intermediul cuvˆntului cheie implements: a class NumeClasa implements NumeInterfata sau class NumeClasa implements Interfata1. modificator nepermis Atentie ¸ • Variabilele unei interfete sunt implicit publice chiar dac˘ nu sunt declarate ¸ a cu modificatorul public. . Interfata2. // Echivalent cu: public void metoda(). FOLOSIREA INTERFETELOR ¸ 123 • metode f˘r˘ implementare: acestea pot fi sau nu declarate cu moda a ificatorul public. deoarece atˆt interfata cˆt ¸i metodele sale nu pot fi a ¸ a s altfel decˆt abstracte. // Incorect. protected void metoda2().2. • Variabilele unei interfete sunt implicit constante chiar dac˘ nu sunt ¸ a declarate cu modificatorii static ¸i final.2. ˆ a acest lucru nu ın ¸ s ın ¸ ıns˘ mai este valabil.. a ın ¸ ¸ interface Exemplu { void metoda().. • In variantele mai vechi de Java era permis ¸i modificatorul abstract s ˆ declaratia interfetei ¸i ˆ declaratiile metodelor.

INTERFETE ¸ O clas˘ poate implementa oricˆte interfete sau poate s˘ nu implementeze a a ¸ a nici una. dar orice referint˘ de tip interfat˘ poate primi ¸a a ¸a ¸a ca valoare o referinta la un obiect al unei clase ce implementeaz˘ interfata ¸ a ¸ respectiv˘. Din acest a ¸ motiv. a ¸ s . dac˘ acesta a ¸a a este o instant˘ a unei clase ce implementeaz˘ interfata X.testeaz˘ dac˘ stiva este vid˘ a a a • toString . ¸a a ¸ Implementarea unei interfete poate s˘ fie ¸i o clas˘ abstract˘. Din acest motiv. unde X este o interfat˘. indiferent de implementarea lor. ¸ a s a a 5.3 Exemplu: implementarea unei stive S˘ consider˘m urm˘torul exemplu.124 CAPITOLUL 5.returneaz˘ varful stivei a • empty . care s˘ modeleze notiunea de stiv˘ de obiecte. a ¸a O interfat˘ nu este o clas˘. ˆ sensul c˘ ad˘ugarea unor metode noi sau schima ın a a barea signaturii metodelor existente vor duce la erori ˆ compilarea claselor ın care o implementeaz˘.returneaz˘ continutul stivei sub forma unui ¸ir de caractere. o interfat˘ nu a s a ¸a mai trebuie modificat˘. ın a ın ¸a Atentie ¸ Modificarea unei interfete implic˘ modificarea tuturor claselor care im¸ a plementeaz˘ acea interfat˘. o clas˘ poate avea ¸i alte metode ¸i variabile a a s s membre ˆ afar˘ de cele definite ˆ interfat˘. Evident.elimin˘ elementul din vˆrful stivei a a • peek . interfetele pot fi privite ca tipuri de date ¸i vom a ¸ s spune adesea c˘ un obiect are tipul X. Obiectele a ¸ a de tip stiv˘.2. atunci treın a a a ¸a buie obligatoriu s˘ specifice cod pentru toate metodele interfetei.adaug˘ un nou element in stıv˘ a a • pop . vor trebui s˘ contin˘ metodele: a a ¸ a • push . odat˘ creata ¸i folosit˘ la implementarea unor clase. Dorim s˘ implement˘m un nou tip de a a a a a date numit Stack. In cazul ˆ care o clas˘ implementeaz˘ o anumit˘ interfat˘.

Vom vedea imediat avantajele acestei ¸ abord˘ri. ambele solutii avˆnd avantaje ¸i a ınl˘ ¸ a ¸ a s dezavantaje.1: Interfata ce descrie stiva ¸ public interface Stack { void push ( Object item ) throws StackException . sau a ın a s a ˆ ıncerc˘m s˘ acces˘m vˆrful stivei ¸i aceasta este vid˘. } Pentru a trata situatiile anormale care pot ap˘rea atunci cˆnd ˆ ¸ a a ıncerc˘m a s˘ punem un element ˆ stiv˘ ¸i nu este posibil din lips˘ de memorie. boolean empty () . // Vectorul ce contine obiectele .5. ˆ vom a a a a ıl defini prin intermediul unei interfete. String toString () . Object peek () throws StackException . } } D˘m ˆ continuare prima implementare a stivei. void pop () throws StackException . } public StackException ( String msg ) { super ( msg ) .2. public class StackImpl1 implements Stack { private Object items []. Deoarece nu dorim a s˘ leg˘m tipul de date Stack de o anumit˘ implementare structural˘. a Listing 5. folosind un vector: a ın Listing 5. vom defini o exceptie a a a a s a ¸ proprie StackException: Listing 5.2: Tipul de exceptie generat de stiv˘ ¸ a public class StackException extends Exception { public StackException () { super () . o stiv˘ poate fi implementat˘ a a folosind un vector sau o list˘ ˆ antuit˘. Prima solutie este mai simplu de ˆ ¸eles.3: Implementarea stivei folosind un vector // Implementarea stivei folosind un vector de obiecte . ˆ timp ce a doua este ¸ ınt ın mai eficient˘ din punctul de vedere al folosirii memoriei. FOLOSIREA INTERFETELOR ¸ 125 Din punctul de vedere al structurii interne.

items [ .. a Trebuie remarcat ¸i faptul c˘ metoda toString este definit˘ deja ˆ clasa s a a ın Object. for ( int i =n -1. } public void pop () throws StackException { if ( empty () ) throw new StackException ( " Stiva este vida ! " ) . de¸i ˆ interfat˘ metodele nu sunt declarate explicit cu ¸ a s ın ¸a modificatorul public.126 CAPITOLUL 5. } public boolean empty () { return ( n ==0) . items [ n ++] = item . ele sunt totu¸i publice ¸i trebuie declarate ca atare ˆ s s ın clas˘. deci clasa noastr˘ o are deja implementat˘ ¸i nu am fi obtinut nici a as ¸ o eroare la compilare dac˘ nu o implementam explicit. } public Object peek () throws StackException { if ( empty () ) throw new StackException ( " Stiva este vida ! " ) . } public StackImpl1 () { this (100) . return s . length ) throw new StackException ( " Stiva este plina ! " ) . } public String toString () { String s = " " . i >=0. INTERFETE ¸ private int n =0. } public void push ( Object item ) throws StackException { if ( n == items . Ceea ce facem acum a este de fapt supradefinirea ei. // Numarul curent de elemente din stiva public StackImpl1 ( int max ) { // Constructor items = new Object [ max ].n ] = null . return items [n -1]. i . } } Remarcati c˘.-) s += items [ i ]. . toString () + " " .

link . // informatia din nod Node link . item . top = top .5. return top . item = item . public class StackImpl2 implements Stack { class Node { // Clasa interna ce reprezinta un nod al listei Object item . // Referinta la varful stivei public void push ( Object item ) { Node node = new Node ( item . Node node = top .2. } public Object peek () throws StackException { if ( empty () ) throw new StackException ( " Stiva este vida ! " ) . S˘ vedem acum modalitatea de implementare a stivei folosind o list˘ a a ˆ antuit˘: ınl˘ ¸ a Listing 5. } public boolean empty () { return ( top == null ) .4: Implementarea stivei folosind o list˘ a // Implementarea stivei folosind o lista inlantuita . FOLOSIREA INTERFETELOR ¸ 127 O alt˘ observatie important˘ se refer˘ la faptul c˘ trebuie s˘ declar˘m ˆ a ¸ a a a a a ın cadrul interfetei ¸i exceptiile aruncate de metode. // legatura la urmatorul nod Node ( Object item . Node link ) { this . top = node . while ( node != null ) { . this . } } private Node top = null . } public String toString () { String s = " " . link = link . } public void pop () throws StackException { if ( empty () ) throw new StackException ( " Stiva este vida ! " ) . top ) . ce trebuie obligatoriu ¸ s ¸ tratate.

println ( " Eroare la lucrul cu stiva ! " ) . de¸i metoda push din ¸ a s interfat˘ declar˘ aruncarea unor exceptii de tipul StackException. Metoda a ın a . s2 . toString () + " " . } catch ( StackException e ) { System . e . } } } Observati folosirea interfetei Stack ca un tip de date. s2 . ce aduce flexibilitate ¸ ¸ sporit˘ ˆ manevrarea claselor ce implementeaz˘ tipul respectiv. push ( " b " ) . out . a ¸ ıns˘ In continuare este prezentat˘ o mic˘ aplicatie demonstrativ˘ care folose¸te a a ¸ a s tipul de date nou creat ¸i cele dou˘ implement˘ri ale sale: s a a Listing 5. err . push ( new Double (3. nu este ¸a a ¸ obligatoriu ca metoda din clas˘ s˘ specifice ¸i ea acest lucru. Stack s2 = new StackImpl2 () . afiseaza ( s1 ) . s1 .128 CAPITOLUL 5. } public static void main ( String args []) { try { Stack s1 = new StackImpl1 () . INTERFETE ¸ s += ( node .5: Folosirea stivei public class TestStiva { public static void afiseaza ( Stack s ) { System .14) ) . } } Singura observatie pe care o facem aici este c˘. afiseaza ( s2 ) . s1 . item ) . printStackTrace () . node = node . push ( " a " ) . link . println ( " Continutul stivei este : " + s ) . atˆt timp cˆt a a s a a nu genereaz˘ exceptii de acel tip. push ( new Integer (1) ) . } return s . Invers este ˆ a obligatoriu.

a . a a • clasa abstract˘ AbstractList care implementeaz˘ interfata List ¸i a a ¸ s ofer˘ implement˘ri concrete pentru metodele comune tuturor tipurilor a a de list˘. 5. • implementarea unei interfete specific˘ doar necesitatea implement˘rii ¸ a a unor anumie metode. La nivel conceptual.3 Interfete ¸i clase abstracte ¸ s La prima vedere o interfat˘ nu este altceva decˆt o clas˘ abstract˘ ˆ care ¸a a a a ın toate metodele sunt abstracte (nu au nici o implementare). Observatie ¸ In pachetul java. aceasta va fi folosit˘ ˆ aplicatiile ce au nevoie de acest s a ın ¸ tip de date. o clas˘ abstract˘ nu ar putea ˆ s a a ınlocui o interfat˘ ? ¸a Raspunsul la intrebare depinde de situatie. ¸ a exist˘: a • interfata List care impune protocolul pe care trebuie s˘ ˆ respecte o ¸ a ıl clas˘ de tip list˘. In multe situatii interfetele ¸i clasele abstracte sunt folosite ˆ ¸ ¸ s ımpreun˘ a pentru a implementa cˆt mai flexibil ¸i eficient o anumit˘ ierarhie de clase.5. diferenta const˘ ˆ ¸ a ın: • extinderea unei clase abstracte forteaz˘ o relatie ˆ ¸ a ¸ ıntre clase. ˆ a ˆ general este ’Nu’. A¸adar. Exemplu oferit de noi nu are leg˘tur˘ cu aceast˘ clas˘ ¸i are rol a a a as pur demonstrativ. INTERFETE SI CLASE ABSTRACTE ¸ ¸ 129 afiseaza accept˘ ca argument orice obiect al unei clase ce implementeaz˘ a a Stack.util exist˘ clasa Stack care modeleaz˘ notiune de stiv˘ a a ¸ a de obiecte ¸i. evident. Fara folosirea interfetelor nu am putea forta clasa respectiv˘ s˘ ¸ ¸ a a respecte diverse tipuri de protocoale.3. deoarece ˆ Java nu exista decˆt mo¸tenire a a a ın a s simpla. Ca sa particulariz˘m. Un a s a exemplu sugestiv este dat de clasele ce descriu colectii. ¸ ıns˘ ın Deosebirea const˘ ˆ faptul c˘ unele clase sunt fortate s˘ extind˘ o anumit˘ a ın a ¸ a a a clas˘ (de exemplu orice applet trebuie s˘ fie subclasa a clasei Applet) ¸i nu ar a a s mai putea sa extind˘ o alt˘ clas˘.

. Din acest motiv. Zburator. . } interface Luptator { void lupta(). 5. } class Erou implements Inotator. . O interfat˘ mosteneste atˆt constantele cˆt ¸i declaratiile de metode de la ¸a a a s ¸ superinterfetele sale. . O clas˘ mo¸teneste doar constantele unei interfete ¸i ¸ a s ¸ s responsabilitatea implement˘rii metodelor sale.4 Mo¸tenire multipl˘ prin interfete s a ¸ Interfetele nu au nici o implementare ¸i nu pot fi instantiate.. Interfata2. a S˘ consider˘m un exemplu de clasa care implementeaza mai multe interfete: a a ¸ interface Inotator { void inoata(). Luptator { public void inoata() {} public void zboara() {} public void lupta() {} } Exemplu de interfat˘ care extinde mai multe interfete: ¸a ¸ interface Monstru { void ameninta().. ¸ s ¸ nu reprezint˘ nici o problem˘ ca anumite clase s˘ implementeze mai multe a a a interfete sau ca o interfat˘ s˘ extind˘ mai multe interfete (s˘ aib˘ mai multe ¸ ¸a a a ¸ a a superinterfete) ¸ class NumeClasa implements Interfata1. INTERFETE ¸ • clase concrete. interface NumeInterfata extends Interfata1..130 CAPITOLUL 5. } interface MonstruPericulos extends Monstru { void distruge(). ArrayList care extind AbstractList. } interface Zburator { void zboara(). Interfata2. cum ar fi LinkedList.

println(x).x).println(I2. cum ar fi situatia cˆnd au aceea¸i list˘ de argumente dar ¸ a s a tipuri returnate incompatibile. compilatorul ıntˆ a nu va furniza eroare decˆt dac˘ se ˆ a a ıncearc˘ referirea constantelor ambigue a f˘r˘ a le prefixa cu numele interfetei sau dac˘ metodele cu acela¸i nume nu aa ¸ a s pot fi deosbite. pot ap˘rea situatii de ambiguitate. //corect System.out. deoarece scrierea unui cod care poate fi confuz este un stil prost de programare. MOSTENIRE MULTIPLA PRIN INTERFETE ¸ ¸ } interface Mortal { void omoara(). I2 { public void metoda() { System. interface I1 { int x=1.x). //ambiguitate . void metoda(). //corect System. atunci cˆnd exist˘ constante a ¸ a a sau metode cu acelea¸i nume ˆ mai multe interfete. void metoda().println(I1. } interface Vampir extends void beaSange(). } //corect //incorect class C implements I1. //int metoda(). } class Dracula implements public void ameninta() public void distruge() public void omoara()() public void beaSange() } 131 MonstruPericulos. } interface I2 { int x=2. ˆ a acest lucru trebuie s ın ¸ ıns˘ ˆ ıntotdeauna evitat. In cazul in care acest lucru se ˆ ampl˘. Mortal { Vampir { {} {} {} {} Evident.4.out.˘ 5.out.

Interfetele a ¸ sunt utile pentru: • definirea unor similaritati ˆ ıntre clase independente f˘r˘ a forta artificial aa ¸ o legatur˘ ˆ a ıntre ele.132 } } CAPITOLUL 5. a • Ierarhia interfetelor este independent˘ de ierarhia claselor care le im¸ a plementeaz˘. o interfat˘ define¸te un protocol ce poate fi implementat a a ¸a s de orice clas˘. indiferent de ierarhia de clase din care face parte. a ¸ a static si final. 5. a 5.1 Crearea grupurilor de constante Deoarece orice variabil˘ a unei interfete este implicit declarat˘ cu public.5 Utilitatea interfetelor ¸ Dup˘ cum am v˘zut.de aici rezult˘ posibilitatea impleın ¸a a ment˘rii unor clase prin mai multe modalit˘¸i ¸i folosirea lor ˆ a at s ıntr-o manier˘ unitar˘. a a ¸ • O clas˘ trebuie obligatoriu s˘ trateze metodele din interfetele pe care a a ¸ la implementeaz˘. • transmiterea metodelor ca parametri. • asigur˘ c˘ toate clasele care implementeaz˘ o interfat˘ pun la dipozitie a a a ¸a ¸ metodele specificate ˆ interfat˘ . INTERFETE ¸ S˘ recapitul˘m cˆteva lucruri legate de clase ¸i interfete: a a a s ¸ • O clas˘ nu poate avea decˆt o superclas˘. a a a • O clas˘ poate implementa oricˆte interfete. a a • definirea unor grupuri de constante. interfetele reprezint˘ o metod˘ convenabil˘ de creare a unor ¸ a a a grupuri de constante care s˘ fie folosite global ˆ a ıntr-o aplicatie: ¸ .5.

este extrem de folosit˘ ˆ Java a a a s a ın ¸i trebuie neap˘rat ˆ ¸eleas˘.2 Transmiterea metodelor ca parametri Deoarece nu exist˘ pointeri propriu-zi¸i.5. DEC=12. ¸˘ a interface Functie { public void executa(Nod u). vom defini o ¸ interfata Functie care va specifica metoda trimis˘ ca parametru.IAN. void explorare(Functie f) { //.. Primul exemplu se refer˘ la explorarea nodurilor unui graf.constanta. a a a ¸ Aceast˘ tehnic˘. FEB=2. . transmiterea metodelor ca parametri a s este realizat˘ ˆ Java prin intermediul interfetelor.. . ca ˆ exemplul de mai jos: ın if (luna < Luni.DEC) luna ++ else luna = Luni. 133 5. } Folosirea acestor constante se face prin expresii de genul NumeInterfata. a ¸ as ¸ s ¸ aceasta urmˆnd s˘ fie apelat˘ normal pentru a obtine rezultatul dorit. atunci argua ¸ a ¸ mentul respectiv va fi declarat de tipul unei interfete care contine metoda ¸ ¸ respectiv˘. } class Graf { //.. Atunci cˆnd o metod˘ a ın ¸ a a trebuie s˘ primeasc˘ ca argument de intrare o referint˘ la o alt˘ functie a a ¸a a ¸ necesar˘ executiei sale. La executie metoda va putea primi ca parametru orice obiect ce a ¸ implementeaz˘ interfata respectiv˘ ¸i deci contine ¸i codul functiei respective...5.5. S˘ consider˘m mai multe exemple pentru a s a ınt a a a clarifica lucrurile. In fiecare a nod trebuie s˘ se execute prelucrarea informatiei din nodul respectiv prin a ¸ intermediul unei functii primite ca parametru. cunoscut˘ doar la momentul executiei. Pentru aceasta. UTILITATEA INTERFETELOR ¸ public interface Luni { int IAN=1. denumit˘ ¸i call-back...

a a s . a s 5.out.6 Interfata FilenameFilter ¸ Instantele claselor ce implementeaz˘ aceasta interfat˘ sunt folosite pentru a ¸ a ¸a crea filtre pentru fi¸iere ¸i sunt primite ca argumente de metode care listeaz˘ s s a continutul unui director. INTERFETE ¸ if (explorarea a ajuns in nodul v) { f. ¸ A¸adar. G.explorare(new AfisareEn()). } } } //Definim doua functii class AfisareRo implements Functie { public void executa(Nod v) { System. prin intermediul s ın ¸a s˘u.. ¸i alte tehnici de programare.out. } } public class TestCallBack { public static void main(String args[]) { Graf G = new Graf()..println("Current node is: " + v). G. } } Al doilea xemplu va fi prezentat ˆ sectiunea urm˘toare. } } class AfisareEn implements Functie { public void executa(Nod v) { System. //.explorare(new AfisareRo()). cum ar fi metoda list a clasei File. putem spune c˘ metoda list prime¸te ca argument o alt˘ functie s a s a ¸ care specific˘ dac˘ un fi¸ier va fi returnat sau nu (criteriul de filtrare).134 CAPITOLUL 5. ˆ ın ¸ a ıntrucˆt face a parte din API-ul standard Java ¸i vor fi puse ˆ evident˘.println("Nodul curent este: " + v).executa(v).

¸ ın .5. orice clas˘ de specificare a unui filtru care implementez˘ interfata s a a ¸ FilenameFilter trebuie s˘ implementeze metoda accept a acestei interfete. } // Implementarea metodei accept public boolean accept(File dir. } } Metodele cele mai uzuale ale clasei String folosite pentru filtrarea fi¸ierelor s sunt: • endsWith . String numeFisier).testeaz˘ dac˘ un ¸ir are o anumit˘ terminatie a a s a ¸ • indexOf .testeaz˘ dac˘ un ¸ir contine un anumit sub¸ir. In general. // Constructorul FiltruFisiere(String filtru) { this. s ¸ Definitia interfetei este: ¸ ¸ public interface FilenameFilter { public boolean accept(File dir. INTERFATA FILENAMEFILTER ¸ 135 Interfata FilenameFilter are o singur˘ metod˘: accept care specific˘ ¸ a a a criteriul de filtrare ¸i anume.filtru = filtru. sau 0 ˆ caz contrar.6. else return false. testeaz˘ dac˘ numele fi¸ierului primit ca paras a a s metru ˆ ındepline¸te conditiile dorite de noi. de exemplu un constructor care s˘ s a primeasca criteriul de filtrare. String nume) { if (filtrul este indeplinit) return true. o clas˘ de specificare a unui filtru a are urm˘torul format: a class FiltruFisiere implements FilenameFilter { String filtru. a ¸ Aceste clase mai pot avea ¸i alte metode. returnˆnd a a s ¸ s a pozitia acestuia. } A¸adar.

length . extensie = extensie . " ) . i < list . list () . list ( new Filtru ( args [0]) ) . Filtru ( String extensie ) { this . printStackTrace () . out . i ++) System . O astfel de metod˘ este list din ¸ a clasa File: String[] list (FilenameFilter filtru) Observati c˘ aici interfata este folosit˘ ca un tip de date. } catch ( Exception e ) { e . Acesta este un exemplu tipic de a a a transmitere a unei functii (functia de filtrare accept) ca argument al unei ¸ ¸ metode. . */ import java .136 CAPITOLUL 5. } } } class Filtru implements FilenameFilter { String extensie . ea fiind substia ¸ a tuit˘ cu orice clas˘ care o implementeaz˘. println ( list [ i ]) . Daca nu se primeste nici un argument . io . length > 0) list = director . vor fi listate toate . INTERFETE ¸ Instantele claselor pentru filtrare sunt primite ca argumente de metode ¸ de listare a continutului unui director. for ( int i = 0. a Listing 5. else list = director . class Listare { public static void main ( String [] args ) { try { File director = new File ( " . String [] list . if ( args .6: Listarea fi¸ierelor cu o anumit˘ extensie s a /* Listarea fisierelor din directorul curent care au anumita extensie primita ca argument .*. S˘ consider˘m exemplul complet ˆ care dorim s˘ list˘m fi¸ierele din dia a ın a a s rectorul curent care au o anumit˘ extensie.

if ( args . " + extensie ) ) .*. for ( int i = 0. list = director . } else list = director .7: Folosirea unei clase anonime /* Listarea fisierelor din directorul curent folosind o clasa anonima pentru filtru . class Listare { public static void main ( String [] args ) { try { File director = new File ( " .1 Folosirea claselor anonime In cazul ˆ care nu avem nevoie de clasa care reprezint˘ filtrul pentru listarea ın a fi¸ierelor dintr-un director decˆt o singur˘ dat˘. i < list . String [] list . length . String nume ) { return ( nume .6.6. endsWith ( " . endsWith ( " . String nume ) { return ( nume . io . INTERFATA FILENAMEFILTER ¸ } public boolean accept ( File dir . " + extensie ) ) . pentru a evita crearea unei s a a a noi clase de sine st˘t˘toare care s˘ fie folosit˘ pentru instantierea unui singur aa a a ¸ obiect. println ( list [ i ]) . list () . i ++) System . } } 137 5. list ( new FilenameFilter () { // Clasa interna anonima public boolean accept ( File dir . out . } catch ( Exception e ) { e . Listing 5. } . aceast˘ situatie fiind un exemplu a a a a ¸ tipic de folosire a acestora. putem folosi clas˘ intern˘ anonim˘.5. } }) . " ) . */ import java . printStackTrace () . length > 0) { final String extensie = args [0].

ˆ care dorim a a a ın s˘ sort˘m un vector format din instante ale clasei Persoana.Arrays. public Persoana ( int cod . java. String nume .sort(v). ca in exemın plul de mai sus.Arrays. nu exist˘ nici o problem˘ ˆ a determina ordinea fireasc˘ a a ın a a elementelor. String nume ) { this . int v[]={3.138 } } CAPITOLUL 5.8: Clasa Persoana (f˘r˘ suport pentru comparare) aa class Persoana { int cod . 2}. INTERFETE ¸ A¸adar. 3. } } . nume = nume . 4. // Sorteaza vectorul v // Acesta va deveni {1. 5. Ce se ˆ ampl˘ ˆ a atunci cˆnd vectorul contine referinte la ınt˘ a ıns˘ a ¸ ¸ obiecte de un anumit tip ? S˘ consider˘m urm˘torul exemplu. 1. cod = cod . o modalitate uzual˘ de folosire a claselor anonime pentru instantierea s a ¸ unui obiect care trebuie s˘ respecte o interfat˘ este: a ¸a metoda(new Interfata() { // Implementarea metodelor interfetei }). } public String toString () { return cod + " \ t " + nume . 4} In cazul ˆ care elementele din vector sunt de tip primitiv.7 Compararea obiectelor Am v˘zut ˆ primul capitol c˘ o solutie facil˘ ¸i eficient˘ de sortare a unui a ın a ¸ as a vector este folosirea metodei sort din clasa java. definit˘ mai jos: a a ¸ a Listing 5.util. this .util. 2.

System . ˆ ıntr-un fel sau altul. } } 139 La executia acestei aplicatii va fi obtinut˘ o exceptie.5.7. util . p [3] = new Persoana (4 . println ( p [ i ]) . p [2] = new Persoana (2 . sort ( p ) . a a 5. length . s˘ specific˘m acest lucru. println ( " Persoanele ordonate dupa cod : " ) . " Popescu " ) . Definitia interfetei este: a ¸ ¸ public interface Comparable { int compareTo(Object o). " Georgescu " ) . " Ionescu " ) . a a . a • zero: dac˘ obiectul curent este egal decˆ obiectul primit ca argument. Aceast˘ ordine se nume¸te ordinea natural˘ a clasei ¸i este a a s a s specificat˘ prin intermediul metodei compareTo. deoarece metoda ¸ ¸ ¸ a ¸ sort nu ¸tie care este ordinea natural˘ a obiectelor de tip Persoana. java . for ( int i =0. " Vasilescu " ) . i < p . o clas˘ ale c˘rei instante trebuie s˘ fie comparabil va implementa s a a ¸ a metoda compareTo care trebuie s˘ returneze: a • o valoare strict negativ˘: dac˘ obiectul curent (this) este mai mic a a decˆ obiectul primit ca argument. Va s a trebui.9: Sortarea unui vector de tip referint˘ ¸a class Sortare { public static void main ( String args []) { Persoana p [] = new Persoana [4]. p [1] = new Persoana (1 . COMPARAREA OBIECTELOR Programul urm˘tor ar trebui s˘ sorteze un vector de persoane: a a Listing 5. p [0] = new Persoana (3 .7. out . out . } A¸adar. i ++) System . Arrays .1 Interfata Comparable ¸ Interfata Comparable impune o ordine total˘ asupra obiectelor unei clase ce ¸ a o implementeaz˘.

String nume .compareTo((Object)e2) == 0) are aceeas¸i valoare logic˘ cu a s a e1. mo¸tenit˘ din Object de toate clasele. e2 instante ale lui C. cod ) && ( nume .10: Clasa Persoana cu suport pentru comparare class Persoana implements Comparable { int cod . a S˘ presupunem c˘ dorim ca ordinea natural˘ a persoanelor s˘ fie dup˘ a a a a a codul lor intern.equals((Object)e2. return ( cod == p . ¸ null nu este instant˘ a nici unei clase ¸i e. nume ) ) . nume = nume .equals(null) ¸ a returneaz˘ false. } public boolean equals ( Object o ) { if (!( o instanceof Persoana ) ) return false . public Persoana ( int cod . Reamintim c˘ metoda equals. } public int compareTo ( Object o ) { if ( o == null ) throw new Null P o i n t e r E x c e p t i o n () . Spunem c˘ a a a s a ordinea natural˘ a unei clase C este consitent˘ cu equals dac˘ ¸i numai a a a s dac˘ (e1. } public String toString () { return cod + " \ t " + nume . pentru orice e1. cod = cod . . equals ( p . String nume ) { this .compareTo(null) trebuie s˘ ¸a s a arunce o exceptie de tip NullPointerException chiar dac˘ e.140 CAPITOLUL 5. Persoana p = ( Persoana ) o . this . if (!( o instanceof Persoana ) ) throw new Clas sCas tExce ptio n ( " Nu pot compara ! " ) . Persoana p = ( Persoana ) o . Listing 5. INTERFETE ¸ • o valoare strict pozitiv˘: dac˘ obiectul curent este mai mare decˆ a a a obiectul primit ca argument. a s a determin˘ dac˘ dou˘ obiecte sunt egale (au aceea¸i valoare).

util . . Metoda equals va returna. " Vasilescu " ) . " Ionescu " ) .7. class Sortare { public static void main ( String args []) { Persoana p [] = new Persoana [4]. " Popescu " ) .*. p [3] = new Persoana (4 . compareTo ( p2 . vom transmite ın ın a a un argument de tip Comparator care s˘ specifice modalitatea de comparare a a elementelor.2 Interfata Comparator ¸ In cazul ˆ care dorim s˘ sort˘m elementele unui vector ce contine referinte ın a a ¸ ¸ dup˘ alt criteriu decˆt ordinea natural˘ a elemenetelor.11: Sortarea unui vector folosind un comparator import java .Comparator contine metoda compare.util.5. sort (p . " Georgescu " ) . return ( p1 . Interfata java. Aceasta returneaz˘ un ˆ a ¸ a ıntreg cu aceea¸i semnificatie ca la metoda compareTo a interfetei Comparator ¸i s ¸ ¸ s are urm˘toarea definitie: int compare(Object o1. a a Listing 5. new Comparator () { public int compare ( Object o1 . nume . Arrays . cod ) . p [1] = new Persoana (1 . COMPARAREA OBIECTELOR return ( cod . care impune ¸ ¸ o ordine total˘ asupra elementelor unei colectii. pur ¸i s simplu.p . avem nevoie de o alt˘ a a a a solutie. p [2] = new Persoana (2 . Metoda compareTo va arunca o exceptie ¸a ¸ de tipul ClassCastException dac˘ se ˆ a ıncearc˘ compararea unui obiect de a tip Persoana cu un obiect de alt tip. a ¸ S˘ presupunem c˘ dorim s˘ sort˘m persoanele ordonate dup˘ numele lor. Persoana p2 = ( Persoana ) o2 . p [0] = new Persoana (3 . nume ) ) . pe lˆng˘ vectorul ce trebuie sortat. } } 141 Observati folosirea operatorului instanceof. Object o2 ) { Persoana p1 = ( Persoana ) o1 . ¸ a dar ˆ varianta ˆ care. 5.Arrays. a a a a a Pentru definirea comparatorului vom folosi o clas˘ anonim˘. false.7.util. care verific˘ dac˘ un obiect ¸ a a este instant˘ a unei anumite clase. Aceasta este oferit˘ tot de metoda sort din clasa java. Object o2).

.. length . a ¸ 5. . public void metoda_n() {} . avem nevoie de un obiect care implementeaz˘ interfata respectiv dar nu a ¸ specific˘ cod decˆt pentru o singur˘ metod˘. System . } . void metoda_n(). i ++) System .8 Adaptori In cazul ˆ care o interfat˘ contine mai multe metode ¸i. void metoda_2().. chiar dac˘ nu specific˘ nici un cod. el trebui totu¸i s˘ implementeze a a a a s a toate metodele interfetei.. clasa String implemenˆnd interfata Comparable. out .. println ( p [ i ]) . } // Trebuie sa apara si celelalte metode // chiar daca nu au implementare efectiva public void metoda_2() {} public void metoda_3() {} . // Avem nevoie de un obiect de tip X // ca argument al unei functii functie(new X() { public void metoda_1() { // Singura metoda care ne intereseaza .. for ( int i =0. println ( " Persoanele ordonate dupa nume : " ) . out . } } Observati cum compararea a dou˘ ¸iruri de caractere se face tot cu metoda ¸ as compareTo. la un moment ın ¸a ¸ s dat.. i < p ..142 CAPITOLUL 5. ¸ a a interface X { void metoda_1(). INTERFETE ¸ } }) .

Mai multe exemple de folosire a adaptorilor vor fi date ˆ capitolul ”Interfata ın ¸ grafic˘ cu utilizatorul”. Definitie ¸ Un adaptor este o clas˘ abstract˘ care implementeaz˘ o anumit˘ interfat˘ a a a a ¸a f˘r˘ a specifica cod nici unei metode a interfetei.. 143 Aceast˘ abordare poate fi nepl˘cut˘ dac˘ avem frecvent nevoie de obiecte a a a a ale unor clase ce implementeaz˘ interfata X. } }).. Solutia la aceast˘ problem˘ este a ¸ ¸ a a folosirea adaptorilor.. ADAPTORI }). a . supradefinind doar metoda care ne intereseaz˘: a a functie(new XAdapter() { public void metoda_1() { // Singura metoda care ne intereseaza .5.8.. aa ¸ public abstract class XAdapter implements X { public void metoda_1() {} public void metoda_2() {} . public void metoda_n() {} } In situatia cˆnd avem nevoie de un obiect de tip X vom folosi clasa ¸ a abstract˘.

INTERFETE ¸ .144 CAPITOLUL 5.

intr˘ri/ie¸iri.applet .io . Exist˘ deci un a a ¸ a set de clase deja implementate care modeleaz˘ structuri de date. a 6. algoritmi sau a diverse notiuni esentiale ˆ dezvoltarea unui program.lang .Capitolul 6 Organizarea claselor 6.clase ¸i interfete utile s ¸ • java.1.1 Pachete Definitie ¸ Un pachet este o colectie de clase ¸i interfete ˆ ¸ s ¸ ınrudite din punctul de vedere al functionalit˘¸ii lor.1 Pachetele standard (J2SDK) Platforma standard de lucru Java se bazeaz˘ pe o serie de pachete cu ajutorul a c˘rora se pot construi ˆ a ıntr-o manier˘ simplificat˘ aplicatiile. pentru a evita conflictele de nume ¸i pentru a controla s a s accesul la anumite clase.util . In alte limbaje de programare pachetele se mai numesc libr˘rii sau bibilioteci. Sunt folosite pentru g˘sirea ¸i utilizarea mai ¸ at a s u¸oar˘ a claselor.dezvoltarea de appleturi 145 . Cele mai importante ¸ ¸ ın pachete ¸i suportul oferit de lor sunt: s • java. lucrul cu fi¸iere a s s • java.clasele de baz˘ ale limbajului Java a • java.

beans ..2 Folosirea membrilor unui pachet Conform specificatiilor de acces ale unei clase ¸i ale mebrilor ei. Pentru a folosi o clas˘ public˘ dintr-un anumit pachet.1.net . autentificare • java.security .scrierea de componente reutilizabile • java. ın a s .operatii matematice cu numere mari ¸ • java. 6.programare de retea ¸ • java. sau pentru a apela a a o metod˘ public˘ a unei clase publice a unui pachet.sql .event .awt .executie la distant˘ Remote Message Interface ¸ ¸a • java. doar clasele ¸ s publice ¸i membrii declarati publici ai unei clase sunt accesibili ˆ afara pas ¸ ın chetului ˆ care se g˘sesc.awt.reflect .interfata grafic˘ cu utilizatorul ¸ a • java.interfata grafic˘ cu utilizatorul..math .lucrul cu texte.lang. ORGANIZAREA CLASELOR • java.text .introspectie ¸ • javax. date ¸i numere independent de limb˘ s a • java.swing .146 CAPITOLUL 6. • . Dup˘ cum am v˘zut ˆ sectiunea ”Specificatori ın a a a ın ¸ de acces pentru membrii unei clase”. accesul implicit ˆ Java este la nivel de ın pachet.mecanismele de tratare e evenimentelor generate de utilizator • java.lucrul cu baze de date • java.rmi .mecanisme de securitate: criptare. exist˘ trei solutii: a a a ¸ • specificarea numelui complet al clasei • importul clasei respective • importul ˆ ıntregului pachet ˆ care se g˘se¸te clasa. mult ˆ ¸ a ımbog˘¸it˘ fat˘ de at a ¸a AWT.

tf1 = new TextField("Placut"). vom putea folosi ˆ clasele fi¸ierului ˆ care am plasat ın s ın instructiunea de import numele scurt al claselor Button ¸i TextField: ¸ s Button b1 Button b2 TextField TextField = new Button("OK"). = new java.NumeClasa.numeClasa.awt java.6. Acest lucru se realizeaz˘ prin instructiunea a ¸ import.3 Importul unei clase sau interfete ¸ Se face prin instructiunea import ˆ care specific˘m numele complet al clasei ¸ ın a sau interfetei pe care dorim s˘ o folosim dintr-un anumit pacehet: ¸ a import numePachet. ar fi extrem de nepl˘cut s˘ scriem de fiecare dat˘ cˆnd vrem a a a a s˘ declar˘m un obiect grafic secvente de genul: a a ¸ java.Button.awt.awt.Button b1 java. = new Button("Cancel").TextField.numele complet al clasei Aceast˘ metod˘ este recomandat˘ doar pentru cazul ˆ care folosirea a a a ın acelei clase se face o singur˘ dat˘ sau foarte rar. import java. In aceste situatii.TextField("Neplacut").Button .awt.awt. tf1 = new java. ¸ 6.1.awt.awt. . care trebuie s˘ apar˘ la ˆ a a ınceputul fi¸ierelor surs˘.1.awt.pachetul din care face parte .TextField java. tf2 = new java.Button b2 java.Button("Cancel").numele scurt al clasei .awt. ˆ s a ınainte de declararea vreunei clase sau interfete.awt. vom importa ˆ aplicatia noastr˘ clasa respectiv˘. Button java.awt. PACHETE 147 Specificarea numelui complet al clasei se face prin prefixarea numelui scurt al clasei cu numele pachetului din care face parte: numePachet. sau ¸ ın ¸ a a ˆ ıntreg pachetul din care face parte.TextField = new java. tf2 = new TextField("Foarte placut"). Din acest moment.TextField("Tot neplacut").awt.Button("OK"). //Pentru exemplul nostru: import java. a a De exemplu.

urmat de simbolul *. java.*.awt. . s a ın 6. Se nume¸te import la cerere deoarece ˆ arcarea s ınc˘ claselor se face dinamic. java.Button. ˆ momentul apel˘rii lor. ar trebui s˘ s a avem cˆte o instructiune de import pentru fiecare dintre ele: a ¸ import import import import import import java.awt.4 Importul la cerere dintr-un pachet Importul la cerere dintr-un anumit pachet se face printr-o instructiune import ¸ ˆ care specific˘m numele pachetului ale c˘rui clase ¸i interfete dorim s˘ le ın a a s ¸ a folosim. 0). //Pentru exemplul nostru: import java. Point. va produce a o eroare de compilare.awt.Point. ORGANIZAREA CLASELOR Aceast˘ abordare este eficient˘ ¸i recomandat˘ ˆ cazul ˆ care nu avem a as a ın ın nevoie decˆt de cˆteva clase din pachetul respectiv.TextField. Point p = new Point(0. vom putea folosi ˆ clasele fi¸ierului ˆ care am plasat ın s ın instructiunea de import numele scurt al tuturor claselor pachetului importat: ¸ Button b = new Button("OK"). Polygon. ın a import numePachet. Rectangle.awt.awt.1. java. Atentie ¸ * nu are semnificatia uzual˘ de la fi¸iere de wildcard (masc˘) ¸i nu poate fi ¸ a s a s folosit decˆt ca atare.Line.Rectangle.awt.*. java. O expresie de genul import java. Din acest moment.awt. Dac˘ ˆ exemplul nostru a a a ın am avea nevoie ¸i de clasele Line. In aceast˘ situatie ar fi mai simplu s˘ folosim importul la cerere din ˆ a ¸ a ıntregul pachet ¸i nu al fiec˘rei clase ˆ parte.148 CAPITOLUL 6.awt.Polygon. java.C*.

permite referirea cona stantelor statice ale unei clase f˘r˘ a mai specifica numele complet al acesaa teia ¸i este implementat˘ prin ad˘ugarea cuvˆntului cheie static dup˘ cel de s a a a a import: import static numePachet.*.1.1.. • pachetul curent • pachetul implicit (f˘r˘ nume) aa 6.*. //corect java. introdus˘ ˆ a a ıncepˆnd cu versiunea 1. ˆ loc s˘ ne referim la constantele clasei cu expresii de tipul ın a NumeClasa. //Declaratie ambigua java.List b = new ArrayList(). // Contine interfata List .*. atunci referirea la ele trebuie f˘cut˘ doar ¸ s a a folosind numele complet.lang import java.util..lang.. PACHETE 149 In cazul ˆ care sunt importate dou˘ sau mai multe pachete care contin ın a ¸ clase (interfete) cu acela¸i nume.. urm˘toarele s a a pachete: • pachetul java. List x.awt. ˆ caz contrar fiind semnalat˘ o ambiguitate de ın a c˘tre compilator.5. //corect Sunt considerate importate automat. a import java.CONSTANTA.List().awt.util. putem folosi doar numele constantei. // Poate sau nu sa apara // Mai bine nu.*. Astfel. .awt.6. pentru orice fi¸ier surs˘.List a = new java.5 Importul static Aceast˘ facilitate.NumeClasa. // Contine clasa List import java.

.5 import java.1.java package grafuri. ORGANIZAREA CLASELOR // Inainte de versiuna 1... clasele pentru a s ın interfata grafic˘ ˆ java. class Graf {.BorderLayout..5 import java.awt.awt.java package grafuri. ın 6. etc.io.java a a a a s a ¸i Arbore.lang.. Dup˘ cum am v˘zut clasele de baz˘ se g˘sesc ˆ pa¸ a a a a ın chetul java. import static java. s //Fisierul Graf..add(new Button().150 CAPITOLUL 6.awt.} //Fisierul Arbore. ¸ a ın Crearea unui pachet se realizeaz˘ prin scriere la ˆ a ınceputul fi¸ierelor surs˘ s a ce contin clasele ¸i interfetele pe care dorim s˘ le grup˘m ˆ ¸ s ¸ a a ıntr-un pachet a instructiunii: package numePachet.BorderLayout.. BorderLayout. grupate dup˘ s ¸ a functionalitatea lor. CENTER).BorderLayout.*.awt. nu ¸i a a s clasa ˆ sine..*. .} . class Arbore {.6 Crearea unui pachet Toate clasele ¸i interfetele Java apartin la diverse pachete. fereastra. clasele pentru intr˘ri/ie¸iri sunt ˆ java. // Incepand cu versiunea 1.. .java. fereastra.*.add(new Button(). Atentie ¸ Importul static nu import˘ decˆt constantele statice ale unei clase.} class GrafPerfect extends Graf {. ¸ S˘ consider˘m un exemplu: presupunem c˘ avem dou˘ fi¸iere surs˘ Graf..CENTER).

¸ 6. ele fiind diferentiate prin prefixarea lor cu numele ın ¸ pachetelor. Acest lucru este posibil atˆt timp cˆt clasele cu acela¸i nume a a s se gasesc ˆ pachete diferite. De asemenea. ArboreBinar vor face parte din acela¸i pachet grafuri.companie..numePachet. s ¸ Este recomandat ˆ a ca toate clasele ¸i intefetele s˘ fie plasate ˆ pachete.1. iar altele altui pachet. In general.7 Denumirea unui pachet Exist˘ posibilitatea ca doi programatori care lucreaz˘ la un proiect comun a a s˘ foloseasc˘ acela¸i nume pentru unele din clasele lor.} 151 Clasele Graf. programatorul cu numele Ion al companiei XSoft. se a a s poate ca una din clasele unei aplicatii s˘ aib˘ acela¸i nume cu o clas˘ a ¸ a a s a mediului Java. cum ın ın ar fi ro. Cu alte cuvinte nu putem specifica faptul c˘ anumite clase a a dintr-un fi¸ier surs˘ apartin unui pachet.ion. ˆsi va prefixa pachetele cu ro. GrafPerfect. ın s De exemplu. conflictele de nume vor fi rezolvate prin diverse conventii de uz intern. Arbore. indiferent de contextul ˆ care acestea ın ın vor fi integrate. . ce se gasesc ˆ pachete cu acela¸i nume s ın s ? Pentru a evita acest lucru. pachetul implicit este format din toate clasele ¸i intefetele directorului curent de lucru. companiile folosesc inversul domeniului lor Internet ˆ denumirea pachetelor implementate ˆ cadrul companiei. avˆnd contul a ion@xsoft. clasele unui fi¸ier surs˘ vor face a s a parte din pachetul implicit (care nu are nici un nume)..xsoft.ro. cum ar fi folosirea ¸ numelui de cont al programatorilor ˆ denumirea pachetelor create de ace¸tia.6. Ce se ˆ ampl˘ ˆ a cˆnd doi programatori care lucreaz˘ la un proiect ıntˆ a ıns˘ a a comun folosesc clase cu acela¸i nume. s Instructiunea package actioneaz˘ asupra ˆ ¸ ¸ a ıntregului fi¸ier surs˘ la ˆ s a ınceputul c˘ruia apare. PACHETE class ArboreBinar extends Arbore {. In cadrul aceleiasi companii. s a ¸ Dac˘ nu este specificat un anumit pachet. ıns˘ s a ın pachetul implicit fiind folosit doar pentru aplicatii mici sau prototipuri. pentru a permite ı¸ identificarea ˆ mod unic a claselor sale.1.

a ¸ O prim˘ variant˘ ar fi s˘ construim cˆte o clas˘ pentru fiecare ¸i s˘ le plas˘m a a a a a s a a . algebr˘.2. un director va contine surse pentru clase ¸i interfete ¸ s ¸ din acela¸i pachet iar numele directorului va fi chiar numele pachetus lui. a ¸ cum ar fi geometrie. a ¸ • Fi¸ierele surs˘ trebuie s˘ se g˘seasc˘ ˆ directoare care s˘ reflecte nus a a a a ın a mele pachetelor ˆ care se g˘sesc clasele ¸i interfetele din acele fi¸iere. poliedru.152 CAPITOLUL 6. Pentru a simplifica lucrurile. Din acest motiv. a s a a Atentie ¸ Este obligatoriu ca o clas˘/interfat˘ public˘ s˘ se gaseasc˘ ˆ a ¸a a a a ıntr-un fi¸ier avˆnd numele clasei(interfetei) ¸i extenisa . Pentru clasele care nu sunt publice a ¸ acest lucru nu este obligatoriu. s˘ a a a presupunem c˘ dorim s˘ cre˘m clase care s˘ descrie urm˘toarele notiuni: a a a a a poligon. grup. cerc.java. etc. sfer˘. Intr-un fi¸ier surs˘ s a pot exista oricˆte clase sau interfete care nu sunt publice.2 6. sau compilatorul s a ¸ s va furniza o eroare.java. ˆ ıntr-un fi¸ier surs˘ nu pot exista s a dou˘ clase sau interfete publice. atunci acestea trebuie de asemenea s˘ corespund˘ a a unor directoare ce vor descrie calea spre fi¸ierele surs˘ ale c˘ror clase s a a ¸i interfete fac parte din pachetele respective. s ¸ Vom clarifica modalitatea de organizare a fi¸ierelor surs˘ ale unei aplicatii s a printr-un exemplu concret. ci doar recomandat. S˘ presupunem c˘ dorim crearea unor compoa a nente care s˘ reprezinte diverse notiuni matematice din domenii diferite. ın a s ¸ s Cu alte cuvinte. Este recomandat ca strategia de organizare a a fi¸ierelor surs˘ s˘ respecte urm˘toarele conventii: s a a a ¸ • Codul surs˘ al claselor ¸i interfetelor s˘ se gaseasc˘ ˆ fi¸iere ale c˘ror a s ¸ a a ın s a nume s˘ fie chiar numele lor scurt ¸i care s˘ aib˘ extensia .1 Organizarea fi¸ierelor s Organizarea fi¸ierelor surs˘ s a Orice aplicatie nebanal˘ trebuie s˘ fie construit˘ folosind o organizare ier¸ a a a arhic˘ a componentelor sale. functie. ORGANIZAREA CLASELOR 6. Dac˘ numele pachetelor sunt formate din mai multe unit˘¸i lexicale a at separate prin punct. analiz˘.

java package geometrie. . . public class Cerc { .6. public class Poligon { .java /spatiu Poliedru. s ın s Ierarhia fi¸ierelor sursa ar fi: s /matematica /surse /geometrie /plan Poligon.java package geometrie.java Matematica.plan. . } . a a O abordare elegant˘ ar fi aceea ˆ care clasele care descriu notiuni din a ın ¸ acela¸i domeniu sa se gaseasca ˆ pachete separate ¸i directoare separate. .java /algebra Grup. aceast˘ abordare ar fi ineficient˘. ORGANIZAREA FISIERELOR ¸ 153 ˆ acela¸i director ˆ ın s ımpreuna cu un program care s˘ le foloseasca. avˆnd a ıns˘ a ˆ vedere posibila extindere a aplicatiei cu noi reprezent˘ri de notiuni matemın ¸ a ¸ atice. } // Poliedru. ˆ a.java Sfera. .plan. public class Poliedru { . } // Cerc.java Cerc.java /analiza Functie. .java package geometrie.spatiu.2.java Clasele descrise ˆ fi¸ierele de mai sus trebuie declarate ˆ pachete denuın s ın mite corespunzator cu numele directoarelor ˆ care se gasesc: ın // Poligon.

. numele lung al unei clase trebuie s˘ descrie calea spre a a a acea clas˘ ˆ cadrul fi¸ierelor surs˘. ˆ urma compil˘rii fi¸ierele surs˘ ¸i unit˘¸ile de compilare se ın a s a s at g˘sesc ˆ acela¸i director.class ¸i numele scurt al clasei sau interfetei respective. . public class Sfera { .2.java package analiza.java este clasa principal˘ a aplicatiei. ORGANIZAREA CLASELOR // Sfera. ˆ a ele pot fi apoi organizate separat.class) at In urma compil˘rii fi¸ierelor surs˘ vor fi generate unit˘¸i de compilare pentru a s a at fiecare clas˘ ¸i interfat˘ din fi¸ierele surs˘. public class Grup { .class trebuie s˘ se s a gaseasca ˆ ıntr-o ierarhie de directoare care s˘ reflecte numele pachetului din a care face parte clasa respectiv˘. ¸ 6.java package geometrie.154 CAPITOLUL 6.class /spatiu . Este recoa ın s ıns˘ mandatˆ a ca aceast˘ separare s˘ fie f˘cut˘ automat la compilare. } // Functie. a ¸ Dup˘ cum se observ˘. . ıns˘ a a a a Revenind la exemplul de mai sus. public class Functie { . } Matematica. Dup˘ cum ¸tim acestea au extensia as ¸a s a a s . relativ la directorul ˆ care se g˘se¸te a ın s a ın a s aplicatia. a Implicit. } // Grup. vom avea urm˘toarea organizare: a /matematica /clase /geometrie /plan Poligon.spatiu. un fi¸ier .2 Organizarea unit˘¸ilor de compilare (.java package algebra. . s ¸ Spre deosebire de organizarea surselor. . .class Cerc.

In lipsa ¸ a a a a lui.class Matematica. In cazul ˆ care dorim s˘ ın a compil˘m explicit toate fi¸ierele java dintr-un anumit director.3 Necesitatea organiz˘rii fi¸ierelor a s Organizarea fi¸ierelor surs˘ este necesar˘ deoarece ˆ momentul cˆnd compis a a ın a latorul ˆ alneste un nume de clas˘ el trebuie s˘ poat˘ identifica acea clas˘.class /algebra Grup.class. a Deoarece compil˘m clasa principal˘ a plicatiei. vor fi compilate ˆ cascad˘ a a ¸ ın a toate clasele referite de aceasta.2. ORGANIZAREA FISIERELOR ¸ Poliedru.java -d clase 6. a a In directorul aplicatiei (matematica) cre˘m subdirectorul clase ¸i d˘m coa s a manda: javac -sourcepath surse surse/Matematica. de exemplu a s surse/geometrie/plan.class /analiza Functie.class. fiecare unitate de compilare va fi plasat˘ ˆ acela¸i director cu fi¸ierul s˘u a ın s s a surs˘. a a a s a ¸ Similar.class Sfera. dar numai acestea. unit˘¸ile de compilare sunt organizate astfel pentru a da posibilat itatea interpretorului s˘ gaseasc˘ ¸i s˘ ˆ a a s a ıncarce ˆ memorie o anumit˘ clas˘ ˆ ın a a ın timpul executiei programului. atˆt a la compilare cˆt ¸i la interpretare trebuie specificat˘ lista de directoare r˘d˘cin˘ a s a a a a .java -d clase Optiunea -d specific˘ directorul r˘d˘cin˘ al ierarhiei de clase. ¸ Ins˘ aceast˘ organizare nu este suficient˘ deoarece specific˘ numai partea a a a a final˘ din calea c˘tre fi¸ierele .java ¸i . de exemplu a a s s /matematica/clase/geometrie/plan/Poligon.java -d clase sau javac -classpath surse surse/Matematica. ıntˆ a a a a ceea ce ˆ ınseamna c˘ trebuie s˘ gaseasc˘ fi¸erul surs˘ care o contine.6.2.class 155 Crearea acestei structuri ierarhice este facut˘ automat de c˘tre compilator. Pentru aceasta. putem folosi expresia: javac surse/geometrie/plan/*.

Definitie ¸ O cale de c˘utare este o list˘ de directoare sau arhive ˆ care vor fi c˘utate a a ın a fi¸ierele necesare unei aplicatii.Grup.4 Setarea c˘ii de c˘utare (CLASSPATH) a a Setarea c˘ii de c˘utare se poate face ˆ dou˘ modalit˘¸i: a a ın a at • Setarea variabilei de mediu CLASSPATH . public class Matematica { public static void main(String args[]) { Poligon a = new Poligon().Sfera = new geometrie.2.spatiu. Fiecare director din calea de cautare este s ¸ directorul imediat superior structurii de directoare corespunz˘toare numelor a pachetelor ˆ care se g˘sesc clasele din directorul respectiv. s a a a ¸ Implicit. geometrie.folosind aceast˘ variant˘ a a toate aplicatiile Java de pe ma¸ina respectiv˘ vor c˘uta clasele necesare ¸ s a a ˆ directoarele specificate ˆ variabila CLASSPATH. calea de c˘utare este format˘ doar din directorul curent. //. a a S˘ consider˘m clasa principal˘ a aplicatiei Matematica.Functie.plan.Sfera(). Aceast˘ list˘ se nume¸te cale de cautare ın a s ¸ a a s (classpath).java: a a a ¸ import geometrie. ORGANIZAREA CLASELOR ˆ care se g˘sesc fi¸ierele aplicatiei.. ın ın . In cazul a s ˆ care nu este g˘sit nici unul sau sunt g˘site mai multe va fi semnalat˘ ın a a a o eroare. 6.*.spatiu. import algebra..156 CAPITOLUL 6. } } Identificarea unei clase referite ˆ program se face ˆ felul urm˘tor: ın ın a • La directoarele aflate ˆ calea de c˘utare se adaug˘ subdirectoarele ın a a specificate ˆ import sau ˆ numele lung al clasei ın ın • In directoarele formate este c˘utat un fi¸ier cu numele clasei. astfel ˆ at compiın a ıncˆ latorul ¸i interpretorul s˘ poat˘ construi calea complet˘ spre clasele aplicatiei. import analiza.

¸ Un fi¸ier JAR poate fi creat folosind utilitarul jar aflat ˆ distributia s ın ¸ J2SDK. o organizare eficient˘ a fi¸ierelor aplicatiei ar ar˘ta astfel: a s ¸ a /matematica /surse /clase compile. Ele pot fi folosite ¸i pentru comprim˘ri ¸ s a obi¸nuite..util.directoarele specificate astfel vor fi valabile doar pentru comanda curent˘: a javac ...classpath <cale de cautare> <surse java> java .bat (javac -sourcepath surse surse/Matematica.jar. DOS shell (Windows 95/NT/.bat (java -classpath clase Matematica) 6. 157 • Folosirea optiunii -classpath la compilarea ¸i interpretarea programelor ¸ s .): SET CLASSPATH = cale1.3. se ın ¸ va face astfel: java -classpath clase Matematica In concluzie. ce contine diverse informatii auxiliare legate de ¸ ¸ aplicatia sau clasele arhivate. ARHIVE JAR UNIX: SET CLASSPATH = cale1:cale2:. din directorul matematica. diferenta fat˘ de o arhiv˘ ZIP obi¸nuit˘ fiind doar existenta unui s ¸ ¸a a s a ¸ director denumit META-INF.java -d clase) run.classpath <cale de cautare> <clasa principala> Lansarea ˆ executie a aplicatiei noastre. a ....cale2..este un format de arhivare independent de platform˘.3 Arhive JAR Fi¸ierele JAR (Java Archive) sunt arhive ˆ format ZIP folosite pentru s ın ˆ ımpachetarea aplicatiilor Java. Dintre beneficiile oferite de arhivele JAR amintim: • portabilitate .6. sau metode ale claselor suport din pachetul java.

jar" .jar A.3.class B.. ORGANIZAREA CLASELOR • compresare . 6.> Exemple: • Arhivarea a dou˘ fi¸iere class: a s jar cf classes.jar • Deschiderea unui applet arhivat <applet code=A.1 Folosirea utilitarului jar Arhivatorul jar se g˘se¸te ˆ subdirectorul bin al directorului ˆ care este a s ın ın instalat kitul J2SDK.jar • Extragerea doar a unor fi¸iere s jar xf arhiva. ¸ ın a a • minimizarea timpului de ˆ ıncarcare a unui applet: dac˘ appletul (fi¸iere a s class.class archive="arhiva. el poate fi ˆ arcat a ınc˘ ˆ ıntr-o singur˘ tranzactie HTTP..arhivele JAR pot fi ”semnate” electronic • mecanismul pentru lucrul cu fi¸iere JAR este parte integrata a plats formei Java.jar fi¸ier(e)-intrare s • Vizualizare continutului ¸ jar tf nume-arhiva • Extragerea continutului ¸ jar xf arhiva. Mai jos sunt prezentate pe scurt operatiile uzuale: ¸ • Crearea unei arhive jar cf arhiva.jar fi¸ier(e)-arhivate s • Executarea unei aplicatii ¸ java -jar arhiva.dimensiunea unei aplicatii ˆ forma sa final˘ este redus˘. etc) este compresat ˆ ıntr-o arhiv˘ JAR.class • arhivarea tuturor fi¸ierelor din directorul curent: s jar cvf allfiles. a s • securitate .158 CAPITOLUL 6.jar * . f˘r˘ a fi deci nevoie de a deschide cˆte a ¸ aa a o conexiune nou˘ pentru fiecare fi¸ier. resurse.

class In urma acestei comenzi vom obtine arhiva mate. a s ˆ care vom scrie: ın Main-Class: Matematica • adaug˘m aceast˘ informatie la fi¸ierul manifest al arhivei mate.mf ce se gase¸te ˆ dia ın s ın rectorul META-INF trebuie s˘ ˆ a ınregistr˘m clasa principal˘ a aplicatiei.jar cu interpretorul Java. Aceasta ˆ ınseamna c˘ ˆ fiserul Manifest. Din directorul clase vom ın a lansa comanda: jar cvf mate. platforma Java 2 va asocia extensiile .class Pe sistemele Win32.jar”.java.jar geometrie analiza algebra Matematica.3.txt Ambele operatii puteau fi executate ˆ ¸ ıntr-un singur pas: jar cvfm mate. ˆ care clasa principal˘ era Matematica.6.3.2 Executarea aplicatiilor arhivate ¸ Pentru a rula o aplicatie ˆ ¸ ımpachetat˘ ˆ a ıntr-o arhiv˘ JAR trebuie s˘ facem a a cunoscut˘ interpretorului numele clasei principale a aplicatiei. ARHIVE JAR 159 6. de exemplu manifest. Dac˘ vom ˆ a ıncerca s˘ lans˘m ˆ executie aceast˘ arhiv˘ prin comanda java -jar mate. a .jar a a ın ¸ a a vom obtine urm˘toarea eroare: ”Failed to load Main-Class manifest from ¸ a mate.jar manifest.txt.jar: a a ¸ s jar uvfm mate.jar manifest. S˘ consider˘m a ¸ a a urm˘torul exemplu.txt geometrie analiza algebra Matematica. ˆ care dorim s˘ arhiv˘m clasele aplicatiei descrise mai a ın a a ¸ sus.jar. Acest a a ¸ lucru ˆ vom face ˆ doi pa¸i: ıl ın s • se creeaz˘ un fi¸ier cu un nume oarecare. ceea ce ˆ ınseamn˘ c˘ facˆnd dublu-click pe o arhiv˘ JAR va fi a a a a lansat˘ ˆ executie aplicatia ˆ a ın ¸ ¸ ımpachetat˘ ˆ acea arhiv˘ (dac˘ exist˘ o clas˘ a ın a a a a principal˘).

160 CAPITOLUL 6. ORGANIZAREA CLASELOR .

2. ¸ a Utilizarea colectiilor ofer˘ avantaje evidente ˆ procesul de dezvoltare a ¸ a ın unei aplicatii.Capitolul 7 Colectii ¸ 7. Prin intermediul colectiilor vom avea acces la diferite tipuri de ¸ date cum ar fi vectori. a a ¸ ¸ Aceste clase reprezint˘ tipuri de date reutilizabile. Cele mai importante sunt: ¸ 161 . reprezentˆnd ¸ a ¸ a elementul de functionalitate reutilizabil˘. Colectiile sunt folosite atˆt pentru memorarea ¸i manipularea ¸ a s datelor. cˆt ¸i pentru transmiterea unor informatii de la o metod˘ la alta. definite pentru obiecte ce implementeaz˘ interfetele a a ¸ ce descriu colectii. tabele de ınl˘ ¸ ¸ dispersie. a • Implement˘ri: implement˘ri concrete ale interfetelor ce descriu colectii. ceea ce ˆ ¸ ınseamn˘ a c˘ multimile reprezentate sunt eterogene.1 Introducere O colectie este un obiect care grupeaz˘ mai multe elemente ˆ ¸ a ıntr-o singur˘ a unitate. a • Algoritmi: metode care efectueaz˘ diverse operatii utile cum ar fi a ¸ c˘utarea sau sortarea. liste ˆ antuite. Ace¸ti algoritmi se numesc ¸i polimorfici deoarece ¸ s s pot fi folositi pe implement˘ri diferite ale unei colectii. a ¸ a Incepˆnd cu versiunea 1. stive. etc. ˆ Java colectiile sunt tratate ˆ a ın ¸ ıntr-o manier˘ a unitar˘. fiind organizate ˆ a ıntr-o arhitectur˘ foarte eficient˘ ¸i flexibil˘ ce cuprinde: a as a • Interfete: tipuri abstracte de date ce descriu colectiile ¸i permit uti¸ ¸ s lizarea lor independent de detaliile implement˘rilor. a s ¸ a Tipul de date al elementelor dintr-o colectie este Object. putˆnd include obiecte de orice tip. multimi matematice.

2 Interfete ce descriu colectii ¸ ¸ Interfetele reprezint˘ nucleul mecanismului de lucru cu colectii. Unele implement˘ri ale acestei s a interfete permit existenta elementelor duplicate. Iterator iterator(). cum ar fi Set sau List. scopul lor ¸ a ¸ fiind de a permite utilizarea structurilor de date independent de modul lor de implementare. boolean add(Object element). s ¸ ın ¸ • Cre¸terea vitezei ¸i calit˘¸ii programului: implement˘rile efective s s at a ale colectiilor sunt de ˆ ¸ ınalt˘ performant˘ ¸i folosesc algoritmi cu timp a ¸a s de lucru optim. ci exist˘ doar implement˘ri ale unor a ¸ a a subinterfete mai concrete. boolean remove(Object element). COLECTII ¸ • Reducerea efortului de programare: prin punerea la dispozitia ¸ programatorului a unui set de tipuri de date ¸i algoritmi ce modeleaz˘ s a structuri ¸i operatii des folosite ˆ aplicatii. ¸ 7. boolean isEmpty(). altele nu. ¸ public interface Collection { // Metode cu caracter general int size(). Platforma Java nu ofer˘ nici o ima plementare direct˘ a acestei interfete. void clear(). // Operatii la nivel de element boolean contains(Object element). alte implement˘ri nu. . Collection modeleaz˘ o colectie la nivelul cel mai general. Un¸ ¸ a ele au elementele ordonate. la scrierea unei aplicatii putem s˘ ne concentr˘m eforturile asupra ¸ a a problemei ˆ sine ¸i nu asupra modului de reprezentare ¸i manipulare a ın s s informatiilor.162 CAPITOLUL 7. descriind un a ¸ grup de obiecte numite ¸i elementele sale. Astfel.

. ¸ s SortedSet este asem˘n˘toare cu interfata Set. diferenta principal˘ constˆnd a a ¸ ¸ a a ˆ faptul c˘ elementele dintr-o astfel de colectie sunt ordonate ascendent. o2 ale colectiei. O multime nu a ¸ ¸ ın ¸ poate avea elemente duplicate. pentru orice dou˘ obiecte o1.2. s s s f˘r˘ a avea alte metode specifice. Object[] toArray(Object a[]). mai bine zis nu poate contine dou˘ obiecte o1 ¸ a ¸i o2 cu proprietatea o1. SortedSet headSet(Object toElement). Singura condittie este ¸ a ¸ ¸ ca. // Metode de conversie in vector Object[] toArray(). mo¸tene¸te metodele acesteia.equals(o2). aa Dou˘ dintre clasele standard care ofer˘ implement˘ri concrete ale acestei a a a interfete sunt HashSet ¸i TreeSet. boolean removeAll(Collection c). } Set modeleaz˘ notiunea de multime ˆ sens matematic. ın a ¸ Pune la dispozitie operatii care beneficiaz˘ de avantajul ordon˘rii elementelor.compareT o(o2) a ¸ (sau comparator. Mo¸tene¸te metodele din Collection. ¸ ¸ a a Ordonarea elementelor se face conform ordinii lor naturale. oferind a ¸ s s metode suplimentare ce ¸in cont de faptul c˘ multimea este sortat˘: t a ¸ a public interface SortedSet extends Set { // Subliste SortedSet subSet(Object fromElement. dac˘ este folosit un comparator) trebuie a s˘ fie valid ¸i s˘ nu provoace exceptii. sau conform cu ordinea dat˘ de un comparator specificat la crearea colectiei ¸i este mentinut˘ a ¸ s ¸ a automat la orice operatie efectuat˘ asupra multimii. apelul o1. a s a ¸ Fiind subclas˘ a interfetei Set. boolean addAll(Collection c). boolean retainAll(Collection c).7. Object toElement). o2). INTERFETE CE DESCRIU COLECTII ¸ ¸ 163 // Operatii la nivel de multime boolean containsAll(Collection c).compare(o1.

} . Object element). int lastIndexOf(Object o). int to). Object last(). a a ¸a List descrie liste (secvente) de elemente indexate.164 CAPITOLUL 7. Listele pot contine ¸ duplicate ¸i permit un control precis asupra pozitiei unui element prin ins ¸ termediul indexului acelui element. fat˘de metodele definite de ¸a interfata Collection. ListIterator listIterator(int index). // Iterare ListIterator listIterator(). Object set(int index. // Cautare int indexOf(Object o). abstract boolean addAll(int index. Object element). COLECTII ¸ SortedSet tailSet(Object fromElement). In plus. } Clasa care implementeaz˘ aceast˘ interfat˘ este TreeSet. Definitia interfetei este: a ¸ ¸ public interface List extends Collection { // Acces pozitional Object get(int index). avem metode pentru acces pozitional. Comparator comparator(). Collection c). // Extragere sublista List subList(int from. Object remove(int index). c˘utare ¸i it¸ ¸ a s erare avansat˘. // Capete Object first(). void add(int index.

Obiectele de acest tip nu pot contine chei duplia a ¸ cate ¸i fiecare cheie este asociat˘ la un singur element. public Set entrySet(). } } . 165 Map descrie structuri de date ce asociaz˘ fiecarui element o cheie unic˘. Object setValue(Object value). a a dup˘ care poate fi reg˘sit. Object getValue(). Object get(Object key). INTERFETE CE DESCRIU COLECTII ¸ ¸ Clase standard care implementeaz˘ aceast˘ interfat˘ sunt: ArrayList. // Operatii la nivel de multime void putAll(Map t). public Collection values(). a a Definittai interfetei este prezentat˘ mai jos: ¸ ¸ a public interface Map { // Metode cu caracter general int size(). Vector. Object value). boolean isEmpty(). // Vizualizari ale colectiei public Set keySet(). void clear(). boolean containsKey(Object key). Ierarhia interfetelor s a ¸ derivate din Map este independent˘ de ierarhia derivat˘ din Collection.2. boolean containsValue(Object value). Object remove(Object key). a a ¸a LinkedList.7. // Interfata pentru manipularea unei inregistrari public interface Entry { Object getKey(). // Operatii la nivel de element Object put(Object key.

Pe lˆng˘ ın s ıncˆ a ın a a acestea au fost create noi clase corespunz˘toare interfetelor definite. } Clasa care implementeaz˘ aceast˘ interfat˘ este TreeMap.166 CAPITOLUL 7. aflarea comparatorului folosit pentru ordonare. // Capete Object first(). COLECTII ¸ Clase care implementeaz˘ interfat˘ Map sunt HashMap. SortedMap tailMap(Object fromKey). chiar a ¸ dac˘ functionalitatea lor era aproape identic˘ cu cea a unei clase anterioare. // Comparatorul folosit pentru ordonare Comparator comparator(). Definitia interfetei este dat˘ mai jos: ¸ ¸ a public interface SortedMap extends Map { // Extragerea de subtabele SortedMap subMap(Object fromKey. Este subclasa a interfetei Map. Object last(). a a ¸a 7. la care se adaug˘ fapa a ¸ a tul c˘ multimea cheilor dintr-o astfel de colectie este mentinut˘ ordonat˘ a ¸ ¸ ¸ a a ascendent conform ordinii naturale. ˆ a ¸ ıns˘ acestea nu erau organizate pe ierarhia de interfete prezentat˘ ˆ sectiunea ¸ a ın ¸ anterioar˘. TreeMap ¸i a ¸a s Hashtable. SortedMap este asem˘n˘toare cu interfata Map. oferind ¸ ¸ metode suplimentare pentru: extragere de subtabele. sau conform cu ordinea dat˘ de un coma parator specificat la crearea colectiei. Object toKey). aflarea primei/ultimei chei. a ¸ a . SortedMap headMap(Object toKey). Aceste clase sunt ˆ continuare disponibile ¸i multe dintre ele a ın s au fost adaptate ˆ a¸a fel ˆ at s˘ se integreze ˆ noua abordare.3 Implement˘ri ale colectiilor a ¸ Inainte de versiunea 1.2. exista un set de clase pentru lucrul cu colectii.

• au definit˘ metoda clone. acestea oferind de altfel ¸i implement˘ri concrete pentru s a multe din metodele definite de interfete. HashTable In vechea ierarhie: Dictionary .Properties Evident.3. cum ar ¸ a fi: • permit elementul null.AbstractSet. TreeSet. unde ’implementare’ se refer˘ la a structura intern˘ folosit˘ pentru reprezentarea multimii.Hashtable .HashMap.. IMPLEMENTARI ALE COLECTIILOR ¸ 167 Clasele de baz˘ care implementeaz˘ interfete ce descriu colectii au numele a a ¸ ¸ de forma < Implementare >< Interf ata >. ˆ ın ımpreun˘ cu interfetele corespunz˘toare (clasele din a ¸ a vechiul model sunt trecute pe rˆndul de jos): a Interfata ¸ Set SortedSet List Clasa HashSet TreeSet ArrayList. Vector-Stack AbstractMap . s s Pe lˆng˘ organizarea ierarhic˘ a interfetelor implementate. TreeMap. AbstractList . ca ˆ figura a a ın de mai jos: AbstractCollection . • sunt serializabile. clasele care descriu colectii au unele tr˘saturi comune. s a ¸ a s ¸ cum ar fi ArrayList ¸i Vector. clasele ce dea a a ¸ scriu colectii sunt de asemenea concepute ˆ ¸ ıntr-o manier˘ ierarhic˘. a . ¸i sunt prezentate a a ¸ s ˆ tabelul de mai jos. HashMap ¸i Hashtable..HashSet. LinkedList Vector Map HashMap Hashtable SortedMap TreeMap A¸adar se observ˘ existenta unor clase care ofer˘ aceea¸i functionalite. implementarea interfetelor este explicit realizat˘ la nivelul super¸ a claselor abstracte.˘ 7. ¸ In general.

¸ 7. } .t1 ) ) . prima fiind ˆ general mult mai folosit˘. fiecare interfat˘ ce descrie o colectie are mai multe a ¸a ¸ implement˘ri. • au atˆt constructor f˘r˘ argumente cˆt ¸i un constructor care accept˘ a aa a s a ca argument o alt˘ colectie a ¸ • exceptˆnd clasele din arhitectura veche. i < N . util . prin realizarea unor compromisuri ˆ ın ¸ ¸ ıntre spatiul ¸ necesar pentru memorarea datelor.1: Comparare ArrayList . respectiv a a a LinkedList ¸i execut˘ diverse operatii pe ea. curre ntTimeM illis () . rapiditatea reg˘sirii acestora ¸i timpul a s necesar actualiz˘rii colectiei ˆ cazul unor modific˘ri. curre ntTimeM illis () . nu sunt sincronizate (vezi ”Fire a de executie). interfata List este implementat˘ de clasele a ¸ a ArrayList ¸i LinkedList. ¸ • permit crearea de iteratori pentru parcurgere. public static void testAdd ( List lst ) { long t1 = System . i ++) lst . care returneaz˘ o reprezentare ca ¸ir de a a s caractere a colectiei respective. out .*. a ¸ ın a S˘ consider˘m un exemplu ce creeaza o list˘ folosind ArrayList. long t2 = System .4 Folosirea eficient˘ a colectiilor a ¸ Dup˘ cum am vazut. for ( int i =0. De ce s ın a exist˘ atunci ¸i clasa LinkedList ? Raspunsul const˘ ˆ faptul c˘ folosind a s a ın a reprezent˘ri diferite ale multimii gestionate putem obtine performante mai a ¸ ¸ bune ˆ functie de situatie. System . public class TestEficienta { final static int N = 100000.LinkedList import java .168 CAPITOLUL 7. COLECTII ¸ • au definit˘ metoda toString. cronometrˆnd timpul necesar s a ¸ a realiz˘rii acestora: a Listing 7. add ( new Integer ( i ) ) . println ( " Add : " + ( t2 . De exemplu.

currentTimeM illis () . curre ntTimeMillis () . deoarece ˆ a ıntr-o list˘ ˆ a ınlantuit˘ accesul la un element se face prin ¸ a . for ( int i =0. println ( " Get : " + ( t2 .˘ 7. s a a ArrayList ofer˘ acces ˆ timp constant la elementele sale ¸i din acest motiv a ın s folosirea lui ”get” este rapid˘. out . testGet ( lst2 ) . println ( " LinkedList " ) . testAdd ( lst2 ) . testGet ( lst1 ) . i ++) lst . System . println ( " Remove : " + ( t2 .4. testRemove ( lst2 ) .45 0. remove (0) . out . sunt dati ˆ tabelul de mai jos: ¸ ın ¸ ın ArrayList 0. System . } } 169 Timpii aproximativi de rulare pe un calculator cu performante medii. List lst2 = new LinkedList () . i < N . } public static void main ( String args []) { System . } public static void testRemove ( List lst ) { long t1 = System . List lst1 = new ArrayList () . currentTimeM illis () . i ++) lst . ad˘ugarea elementelor este rapid˘ pentru ambele tipuri de liste.t1 ) ) . testRemove ( lst1 ) . for ( int i =0. ¸ exprimati ˆ secunde. long t2 = System . FOLOSIREA EFICIENTA A COLECTIILOR ¸ public static void testGet ( List lst ) { long t1 = System . ˆ timp ce pentru LinkedList este extrem a ın de lent˘. println ( " ArrayList " ) . long t2 = System . out . System . get ( i ) . curre ntTimeMillis () .01 add get remove A¸adar.12 0.t1 ) ) . testAdd ( lst1 ) .14 87.05 LinkedList 0. i < N . out .01 12.

a • shuffle . a a . etc. ArrayList se comport˘ bine pentru cazuri ˆ care avem a a ın nevoie de reg˘sirea unor elemente la pozitii diferite ˆ list˘. ¸ a ¸ s inser˘ri). ¸ • apelul lor general va fi de forma: Collections. a s ¸ Metodele mai des folosite din clasa Collections sunt: • sort .amestec˘ elementele unei liste . a • au un singur argument de tip colectie. a Concluzia nu este c˘ una din aceste clase este mai ”bun˘” decˆt cealalt˘. • majoritatea opereaz˘ pe liste dar ¸i pe colectii arbitrare. a 7. folosirea lui ArrayList este lent˘ deoarece el¸ a ementele r˘mase sufer˘ un proces de reindexare (shift la stˆnga). Caracterisiticile principale ale acestor algoritmi sunt: • sunt metode de clas˘ (statice).5 Algoritmi polimorfici Algoritmii polimorfici descri¸i ˆ aceast˘ sectiune sunt metode definite ˆ s ın a ¸ ın clasa Collections care permit efectuarea unor operatii utile cum ar fi c˘utarea.algoritm(colectie.170 CAPITOLUL 7. ¸ a sortarea.efectueaz˘ c˘utarea eficient˘ (binar˘) a unui element a a a a ˆ ıntr-o list˘ ordonat˘. COLECTII ¸ parcurgerea secvential˘ a listei pˆn˘ la elementul respectiv. iar LinkedList a ¸ ın a functioneaza eficient atunci cˆnd facem multe operatii de modificare (¸tergeri. ˆ timp a a a ın ce pentru LinkedList este rapid˘ ¸i se face prin simpla schimbare a unei a s leg˘turi. a a a a ci c˘ exist˘ diferente substantiale ˆ reprezentarea ¸i comportamentul diferitelor a a ¸ ¸ ın s implement˘ri ¸i c˘ alegerea unei anumite clase pentru reprezentarea unei a s a multimi de elemente trebuie s˘ se fac˘ ˆ functie de natura problemei ce ¸ a a ın ¸ trebuie rezolvat˘. [argumente]). a • binarySearch . ¸ a a a La operatiunea de eliminare.opusul lui sort.sorteaz˘ ascendent o list˘ referitor la ordinea s˘ natural˘ sau la a a a a ordinea dat˘ de un comparator. Deci.

6. putem rescrie secventa astfel: ¸ . a ¸ • swap . Definirea unui ¸ ¸a tip generic se realizeaz˘ prin specificarea ˆ a ıntre paranteze unghiulare a unui tip de date Java. lista definit˘ poate contine obiecte de orice tip. simplific˘ ın a lucrul cu colectii. • copy .returneaz˘ maximul dintr-o colectie.add(new Integer(123)). permitˆnd tipizarea elementelor acestora. S˘ consider˘m un exemplu de utilizare a colectiilor ¸ a a ¸ ˆ ınainte ¸i dup˘ introducerea tipurilor generice: s a // Inainte de 1. ¸ • unmodifiableTipColectie .5 a limbajului Java. a a 171 • fill .inverseaz˘ ordinea elementelor dintr-o list˘. trebuie s˘ facem a cast explicit de la tipul Object la Integer atunci cˆnd prelu˘m valoarea a a unui element.6 Tipuri generice Tipurile generice. TIPURI GENERICE • reverse . ¸ ¸ 7. de¸i a ¸ s am dori ca elementele s˘ fie doar numere ˆ a ıntregi. In exemplul de mai sus. ın • min .returneaz˘ minimul dintr-o colectie.get(0)). Folosind tipuri generice. Mai mult.interschimb˘ elementele de la dou˘ pozitii specificate ale unei a a ¸ liste.7.returneaz˘ o instant˘ sincronizat˘ a unei a ¸a a colectii (vezi ”Fire de executie”). a ¸ • max . • enumeration .returneaza o enumerare a elementelor dintr-o colectie.5 ArrayList list = new ArrayList().copie elementele unei liste ˆ alta. int val = ((Integer)list. efectul fiind impunerea tipului respectiv pentru toate elementele colectiei: <TipDate>. introduse ˆ versiunea 1. a ¸ • synchronizedTipColectie .returneaz˘ o instant˘ care nu poate fi moda ¸a ificat˘ a colectiei respective.populeaza o lista cu un anumit element repetat de un num˘r de a ori.intValue(). list.

get(0).get(0).out. Ei sunt descri¸i ¸ a a s de obiecte ce implementeaz˘ interfetele Enumeration. folosind si autoboxing ArrayList<Integer> list = new ArrayList<Integer>(). varianta mai concisa for (Enumeration e = v. In cazul folosirii tipurilor generice. ˆ ¸ ımpreun˘ a cu modalitatea lor de folosire.hasMoreElements()) { System. indiferent dac˘ aceasta este indexat˘ sau nu. Toate clasele care implementeaz˘ colectii au metode ce a ¸ returneaz˘ o enumerare sau un iterator pentru parcurgerea elementelor lor. semnificatiile lor fiind evidente: ¸ • Enumeration: hasMoreElements. nextElement // Parcurgerea elementelor unui vector v Enumeration e = v. spre deosebire de varianta anterioar˘ ce permitea doara aruncarea unor a exceptie de tipul ClassCastException ˆ cazul folosirii incorecte a tipurilor.intValue().7 Iteratori ¸i enumer˘ri s a Enumer˘rile ¸i iteratorii descriu modalit˘¸i pentru parcurgerea secvential˘ a a s at ¸ a unei colectii.elements. obtinem o variant˘ mult sima a s ¸ a plificat˘ a secventei initiale: a ¸ ¸ // Dupa 1. Dac˘ utiliz˘m ¸i mecanismul de autoboxing.nextElement()). respectiv Iterator a ¸ sau ListIterator. folosind tipuri generice ArrayList<Integer> list = new ArrayList<Integer>(). .5.172 CAPITOLUL 7. a a ın a ¸ Metodele uzuale ale acestor interfete sunt prezentate mai jos.println(e.5. int val = list. list. ¸ ¸ a s ın aceasta din urm˘ este preferat˘ ˆ noile implement˘ri ale colectiilor. ¸ ın 7.add(123). while (e. } // sau. a Deoarece functionalitatea interfetei Enumeration se reg˘se¸te ˆ Iterator. list.add(new Integer(123)). ˆ ıncercarea de a utiliza ˆ cadrul unei ın colectii a unui element necorespunz˘tor ca tip va produce o eroare la compi¸ a lare.elements(). COLECTII ¸ // Dupa 1. int val = list.

hasNext(). if (obj == null) it. if (obj == null) it. } • Iterator: hasNext.7.) { Object obj = it.next().out. dac˘ este a a cazul. set dar ¸i prin faptul c˘ denumirile metodelor sunt mai concise. s a Atentie ¸ Deoarece colectiile sunt construite peste tipul de date Object.hasNext(). fiind responsabilitatea noastr˘ de a face conversie (cast) la alte tipuri de date. remove // Parcurgerea elementelor unui vector // si eliminarea elementelor nule for (Iterator it = v.remove().hasMoreElements(). Iteratorii sunt preferati enumer˘rilor datorit˘ posibilit˘¸ii lor ¸ a a at de a actiona asupra colectiei pe care o parcurg prin metode de tip remove. it.iterator(). remove. cei de tip ListIterator permit ¸i inserarea unui element la pozitia s ¸ curent˘. ¸ ¸ add. add. precum ¸i iterarea ˆ ama s ın bele sensuri.set(new Integer(0)). it. set // Parcurgerea elementelor unui vector // si inlocuirea elementelor nule cu 0 for (ListIterator it = v. next.nextElement()).) { System. } • ListIterator: hasNext. ITERATORI SI ENUMERARI ¸ e. next. previous.listIterator(). metodele ¸ de tip next sau prev ale iteratorilor vor returna tipul Object. hasPrevious.println(e. . respectiv modificarea elementului curent.) { Object obj = it.˘ 7.next(). } 173 Iteratorii simpli permit eliminarea elementului curent din colectia pe care ¸ o parcurg.

listIterator () . for (Iterator i = list. i <=10. ) { Integer x = ( Integer ) it .*. it .) { Integer val=(Integer)i. shuffle ( a ) .iterator(). dup˘ care le parcurgem element cu element folosind un iterator.5 a limbajului Java. i ++) a . class TestIterator { public static void main ( String args []) { ArrayList a = new ArrayList () . exist˘ o variant˘ simplificat˘ a a a a de utilizare a iteratorilor. } } Incepˆnd cu versiunea 1. a a ˆ ınlocuind numerele pare cu 0. o secvent˘ de genul: ¸a ArrayList<Integer> list = new ArrayList<Integer>(). print ( " Rezultat : " + a ) .hasNext(). println ( " Vectorul amestecat : " + a ) . set ( new Integer (0) ) . i.174 CAPITOLUL 7. il facem 0 if ( x . le amestec˘m. // Parcurgem vectorul for ( ListIterator it = a . } System . intValue () % 2 == 0) it . next () . Listing 7. // Daca elementul curent este par . System . util .next(). // Adaugam numerele de la 1 la 10 for ( int i =1. add ( new Integer ( i ) ) . .. // Amestecam elementele colectiei Collections . COLECTII ¸ In exemplul de mai jos punem ˆ ıntr-un vector numerele de la 1 la 10. // Proceseaza val . Astfel.2: Folosirea unui iterator import java . out . out . hasNext () ..

for (Integer val : list) { // Proceseaza val .7.˘ 7. ITERATORI SI ENUMERARI ¸ } poate fi rescris˘ astfel: a ArrayList<Integer> list = new ArrayList<Integer>().. } 175 ..

COLECTII ¸ .176 CAPITOLUL 7.

Capitolul 8 Serializarea obiectelor 8. ceea ce ˆ ¸ ınseamna c˘ durata de viata a a ¸ unui obiect nu este determinat˘ de executia unui program ˆ care acesta a ¸ ın este definit .obiectul poate exista ¸i ˆ s ıntre apelurile programelor care ˆ ıl folosesc. • Permite persistenta obiectelor. apoi. de citire a unui obiect serializat pentru a-i reface starea original˘. prin serializare a s se ˆ ıntelege procesul de scriere/citire a obiectelor. obiectul va fi citit de pe disc ¸i starea lui refacut˘. se nume¸te deserializare. Tipurile primitive pot fi de asemenea serializate. Cu alte cuvinte. Intr-un cadru mai larg. serializarea permite salvarea ˆ ıntr-o manier˘ unitar˘ a a a tuturor informatiilor unui obiect pe un mediu de stocare extern programului. Acest lucru se realizeaz˘ prin serializarea obiectului ¸i scrierea a s lui pe disc ˆ ınainte de terminarea unui program. Acest s a 177 . Utilitatea serializarii const˘ ˆ urm˘toarele aspecte: a ın a • Asigur˘ un mecanism simplu de utilizat pentru salvarea ¸i restaurarea a s a datelor.1 Folosirea serializ˘rii a Definitie ¸ Serializarea este o metod˘ ce permite transformarea unui obiect ˆ a ıntr-o secventa de octeti sau caractere din care s˘ poat˘ fi ref˘cut ulterior obiectul ¸˘ ¸ a a a original. la relansarea programului. ¸ Procesul invers.

SERIALIZAREA OBIECTELOR tip de persistent˘ a obiectelor se nume¸te persistent˘ u¸oar˘. Orice compoın ¸ nent˘ Bean are o stare definit˘ de valorile implicite ale propriet˘¸ilor a a at sale.este o modalitate prin care metodele unor obiecte de pe o alt˘ ma¸in˘ pot fi apelate ca ¸i cum acestea ar exa s a s ista local pe ma¸ina pe care ruleaz˘ aplicatia. serializarea a a s a este utilizat˘ pentru transportul argumentelor prin retea ¸i pentru rea ¸ s turnarea valorilor. ceea ce ˆ a ¸ ınseamn˘ c˘ un algoritm general de salvare a st˘rii a a a unui obiect nu este tocmai facil. indea pendent de formatul de reprezentare a datelor. a¸a cum am vazut. atunci salvarea informatiilor ˆ ¸ ıncapsulate ˆ acel ın obiect se poate face ¸i prin salvarea pe rˆnd a datelor. dar.sunt componente reutilizabile. folosind clasa s a DataOutputStream. a • Compensarea diferentelor ˆ ¸ ıntre sisteme de operare . pentru ca apoi s˘ fie restaurate prin metode ale clasei a DataInputStream. o asemenea abordare nu este s . ˆ ¸a s ¸a s a ıntrucˆt a ea trebuie efectuat˘ explicit de c˘tre programator ¸i nu este realizat˘ a a s a automat de c˘tre sistem.178 CAPITOLUL 8. • Transmiterea datelor ˆ retea . Acesta s ¸ ¸ este un proces recusiv de salvare a datelor. Atunci cˆnd este trimis s a ¸ a un mesaj c˘tre un obiect ”remote” (de pe alt˘ ma¸in˘). de sine st˘t˘toare ce pot aa fi utilizate ˆ medii vizuale de dezvoltare a aplicatiilor. ¸i a¸a mai a a s s departe. • Java Beans . ˆ ıntrucˆt celelalte obiectele referite a de obiectul care se serializeaz˘ pot referi la rˆndul lor alte obiecte. Un aspect important al serializ˘rii este c˘ nu salveaz˘ doar imaginea unui a a a obiect ci ¸i toate referintele la alte obiecte pe care acesta le contine. • RMI (Remote Method Invocation) . A¸adar referintele care construiesc starea unui obiect formeaz˘ o s ¸ a ˆ ıntreag˘ retea. respectiv receptionate ¸ obiecte serializate. stare care este specificat˘ ˆ etapa de design a aplicatiei.transmiterea unor informatii ˆ ¸ ıntre platforme de lucru diferite se realizeaz˘ unitar.Aplicatiile ce ruleaz˘ ˆ retea pot comuın ¸ ¸ a ın ¸ nica ˆ ıntre ele folosind fluxuri pe care sunt trimise. Mediile a ın ¸ vizuale folosesc mecanismul serializ˘rii pentru asigurarea persistentei a ¸ componentelor Bean. In cazul ˆ care starea unui obiect este format˘ doar din valori ale unor ın a variabile de tip primitiv. ordinea octetilor sau ¸ alte detalii specifice sistemelor repective.

Acestea implementeaz˘ interfetele DataInput. Citirea informatiilor scrise ˆ exemplul de mai sus se va face astfel: ¸ ın FileInputStream fis = new FileInputStream("test. out.1. unele cˆmpuri pot ¸ a face referint˘ la acela¸i obiect.345). DataInputStream in = new DataInputStream(fis). deoarece pot ap˘rea probleme cum ar fi: variabilele ın a a membre ale obiectului pot fi instante ale altor obiecte.readDouble().dat").close(). fie cu ObjectOutputStream s ¸i ObjectInputStream. int i = in.writeBoolean(true).1 Serializarea tipurilor primitive Serializarea tipurilor primitive poate fi realizat˘ fie prin intermediul fluxua rilor DataOutputStream ¸i DataInputStream. .writeDouble(12. In continuare.readBoolean(). Mai jos este prezentat un exemplu de serializare folosind clasa DataOutputStream: FileOutputStream fos = new FileOutputStream("test. double d = in. FOLOSIREA SERIALIZARII 179 ˆ general suficient˘. ın 8.dat").writeUTF("Sir de caractere").flush().1. etc. out. boolean b = in. DataOutputStream out = new DataOutputStream(fos). respectiv a writeTipPrimitiv pentru scrierea/citirea datelor primitive ¸i a ¸irurilor de s s caractere. fos. out.readInt(). ¸a s Serializarea ˆ format binar a tipurilor primitive ¸i a obiectelor se realın s izeaz˘ prin intermediul fluxurilor definite de clase specializate ˆ acest scop a ın cu ar fi: ObjectOutputStream pentru scriere ¸i ObjectInputStream pentru restaus rare. res a ¸ spectiv DataOutput ce declar˘ metode de tipul readTipPrimitiv. prin termenul serializare ne vom referi doar la serializarea ˆ format binar.writeInt(12345). out. out.˘ 8.

signatura clasei ¸i valorile tuturor cˆmpurile serializabile ale obiecs a tului. respectiv ObjectOutput care extind DataInput. Metodele pentru serializarea obiectelor sunt: • writeObject. pentru restaurare. fis.flush(). s secventa uzual˘ fiind cea de mai jos: ¸ a ObjectOutputStream out = new ObjectOutputStream(fluxPrimitiv). respectiv DataOutput.close(). Referintele la alte obiecte serializabile din cadrul obiectului curent vor ¸ duce automat la serializarea acestora iar referintele multiple c˘tre un acela¸i ¸ a s obiect sunt codificate utilizˆnd un algoritm care s˘ poat˘ reface ”reteaua de a a a ¸ obiecte” la aceea¸i stare ca atunci cˆnd obiectul original a fost salvat. out. pe lˆng˘ metodele dedicate serializ˘rii obiectelor. sau de pe care va fi restaurat un obiect serializat. ceea ce ˆ ınseamn˘ c˘.1.2 Serializarea obiectelor Serializarea obiectelor se realizeaz˘ prin intermediul fluxurilor definite de a clasele ObjectOutputStream (pentru salvare) ¸i ObjectInputStream s (pentru restaurare). fluxPrimitiv.writeObject(referintaObiect). . ceea ce ˆ ınseamna c˘ vor fi folosite ˆ a ımpreuna cu alte fluxuri pentru scrierea/citirea efectiv˘ a a datelor pe mediul extern pe care va fi salvat. Mecanismul implicit de serializare a unui obiect va salva numele clasei obiectului. 8. SERIALIZAREA OBIECTELOR String s = in. vor a a a a a exista ¸i metode pentru scrierea/citirea datelor primitive ¸i a ¸irurilor de s s s caractere.readUTF(). 8. Acestea sunt fluxuri de procesare. pentru scriere ¸i s • readObject.close(). s a Clasele ObjectInputStream ¸i ObjectOutputStream implementeaz˘ interfetele s a ¸ ObjectInput. out.180 CAPITOLUL 8.3 Clasa ObjectOutputStream Scrierea obiectelor pe un flux de ie¸ire este un proces extrem de simplu.1.

fi¸ierul a s rezultat va contine informatiile reprezentate ˆ format binar. out. ¸ 8. out.writeBoolean(true). out. Evident.1. out.ser. Secventa uzual˘ pentru s ¸ a deserializare este cea de mai jos: ObjectInputStream in = new ObjectInputStream(fluxPrimitiv).1.writeObject(new Date()).flush().˘ 8. ¸ ¸ ın FileOutputStream fos = new FileOutputStream("test. fos.close(). //sau . citirea a s acestora ¸i reconstruirea obiectelor salvate se va face printr-un flux de intrare s de tip ObjectInputStream.345).writeDouble(12. Metoda writeObject arunc˘ exceptii de tipul IOException ¸i derivate a ¸ s din aceasta. ˆ s ımpreun˘ cu un obiect de tip String. mai precis NotSerializableException dac˘ obiectul primit ca a argument nu este serializabil. out. asts s fel ˆ at apeluri ca cele de mai jos sunt permise : ıncˆ out. pe lˆnga metoda de scriere a ¸ a a obiectelor.writeUTF("Sir de caractere"). Vom vedea ˆ continuare a a ın ın c˘ un obiect este serializabil dac˘ este instant˘ a unei clase ce implementeaz˘ a a ¸a a interfata Serializable. FOLOSIREA SERIALIZARII 181 Exemplul de mai jos construie¸te un obiect de tip Date ¸i ˆ salveaz˘ ˆ s s ıl a ın fi¸ierul test. Acesta este de asemenea un flux de procesare ¸i va trebui asociat cu un flux pentru citirea efectiv˘ a datelor. sau InvalidClassException dac˘ sunt proba leme cu o clas˘ necesar˘ ˆ procesul de serializare. Object obj = in. Deoarece implementeaz˘ interfata DataOutput.ser"). clasa pune la dispozitie ¸i metode de tipul writeTipPrimitiv s pentru serializarea tipurilor de date primitive ¸i a ¸irurilor de caractere.4 Clasa ObjectInputStream Odat˘ ce au fost scrise obiecte ¸i tipuri primitive de date pe un flux.writeObject("Ora curenta:"). ObjectOutputStream out = new ObjectOutputStream(fos).writeInt(12345). out. cum ar fi s a FileInputStream pentru date salvate ˆ ıntr-un fi¸ier.readObject().

Date data = (Date)in. . double d = in. ObjectInputStream in = new ObjectInputStream(fis).readInt().readObject().close(). int i = in. pe a ¸ lˆng˘ metoda de citire a obiectelor.182 CAPITOLUL 8.readObject().readDouble().readObject(). String mesaj = (String)in. altfel vor ap˘rea evident exceptii ˆ procesul de desea ¸ ın rializare.readUTF(). Citirea informatiilor scrise ˆ exemplul de mai sus se va face astfel: ¸ ın FileInputStream fis = new FileInputStream("test. fluxPrimitiv. // gresit Date date = (Date)in. fis.ser"). // corect Atentie ¸ Ca ¸i la celelalte fluxuri de date care implemeteaz˘ interfata DataInput s a ¸ citirea dintr-un flux de obiecte trebuie s˘ se fac˘ exact ˆ ordinea ˆ carea a a ın ın acestea au fost scrise. Clasa ObjectInputStream implementeaz˘ interfata DataInput deci. boolean b = in. clasa pune la dispozitie ¸i metode de a a ¸ s tipul readTipPrimitiv pentru citirea tipurilor de date primitive ¸i a ¸irurilor s s de caractere. SERIALIZAREA OBIECTELOR TipReferinta ref = (TipReferinta)in. ceea a ce ˆ ınseamn˘ c˘ trebuie realizat˘ explicit conversia la tipul corespunzator a a a obiectului citit: Date date = in. Trebuie observat c˘ metoda readObject are tipul returnat Object.readObject().readBoolean().close(). String s = in.readObject().

clasa respectiv˘ trebuie s˘ implementeze.2. ¸ ¸ ¸ a a singurul ei scop fiind de a identifica clasele ale c˘ror obiecte sunt serializabile. fiind responsabilitatea clasei curente de a asigura un mecanism propriu pentru salvarea/restaurarea lor. A¸adar. dac˘ dorim ca instantele unei a ¸ s a ¸ clase s˘ poat˘ fi serializate. interfata Serializable. fiind f˘cut˘ prin simpla implementare a interfetei Serializable: a a a ¸ public class ClasaSerializabila implements Serializable { // Corpul clasei } Orice subclas˘ a unei clase serializabile este la rˆndul ei serializabil˘. Acest lucru va fi discutat ˆ sectiunea referitoare ın ¸ la personalizarea serializ˘rii.io. atunci trebuie s˘ avem ˆ vedere urm˘toarele lucruri: a a ın a • Variabilele accesibile ale superclasei nu vor fi serializate. direct a a a a sau indirect. a a a ˆ ıntrucˆt implementeaz˘ indirect interfata Serializable. public interface Serializable { // Nimic ! } Declararea claselor ale c˘ror instante trebuie s˘ fie serializate este a¸adar a ¸ a s extrem de simpl˘. va fi generat˘ o exceptie la aa a a ¸ executie.8. a • Superclasa trebuie s˘ aib˘ obligatoriu un constructor accesibil f˘r˘ ara a aa gumente. a a ¸ In situatia ˆ care dorim s˘ declar˘m o clas˘ serializabil˘ dar superclasa ¸ ın a a a a sa nu este serializabil˘.2. a Definitia sa complet˘ este: ¸ a package java. In lipsa unui constructor ¸ accesibil f˘r˘ argumente pentru superclas˘. OBIECTE SERIALIZABILE 183 8. acesta fiind utilizat pentru initializarea variabilelor mo¸tenite ¸ s ˆ procesul de restaurare al unui obiect.2 Obiecte serializabile Un obiect este serializabil dac˘ ¸i numai dac˘ clasa din care face parte imas a plementeaz˘ interfata Serializable.1 Implementarea interfetei Serializable ¸ Interfata Serializable nu contine nici o declaratie de metod˘ sau constant˘. ¸ 8. ¸ . Variabilele proprii vor fi ın initializate cu valorile de pe fluxul de intrare.

2 Controlul serializ˘rii a Exist˘ cazuri cˆnd dorim ca unele variabile membre ale unui obiect s˘ nu fie a a a salvate automat ˆ procesul de serializare. SERIALIZAREA OBIECTELOR In procesul serializ˘rii. De exemplu. ¸ Listing 8. public class Test1 implements Serializable { int x =1. sau variabile temporare pe care nu are rost s˘ le salv˘m. // Participa la serializare In exemplele urm˘toare cˆmpurile marcate ’DA’ particip˘ la serializare.184 CAPITOLUL 8.1: Modificatorii static ¸i transient s import java . Acestea sunt cazuri comune atunci ın cˆnd respectivele cˆmpuri reprezint˘ informatii confidentiale. Chiar declarate a a private ˆ cadrul clasei aceste cˆmpuri particip˘ la serializare. Cu a alte cuvinte. transient int y =2. dac˘ este ˆ alnit un obiect care nu implementeaz˘ a a ıntˆ a interfata Serializable atunci va fi generat˘ o exceptie de tipul NotSerializableException ¸ a ¸ ce va identifica respectiva clas˘ neserializabil˘. a a static transient int N. " + z + " . transient static int z =3. a a a cele marcate ’NU’. " + y + " . " + t . a a 8. Pentru ca un ın a a cˆmp s˘ nu fie salvat ˆ procesul de serializare el trebuie declarat cu modia a ın ficatorul transient ¸i trebuie s˘ fie ne-static. variabilele de clas˘ particip˘ obligatoriu la serializare.*. cum ar fi paa a a ¸ ¸ role. } } . static int t =4. nu particip˘ iar cele marcate cu ’Exceptie’ vor provoca a exceptii de tipul NotSerializableException. declararea unei s a variabile membre temporare ar trebui facut˘ astfel: a transient private double temp.2. // Ignorata la serializare Modificatorul static anuleaz˘ efectul modificatorului transient. // DA // NU // DA // DA public String toString () { return x + " . io .

*. // DA . OBIECTE SERIALIZABILE 185 Dac˘ un obiect ce trebuie serializat are referinte la obiecte neserializabile. a s a s Listing 8. } } Atunci cˆnd o clas˘ serializabila deriva dintr-o alt˘ clas˘. // Exceptie B b = new B () . class A { int x =1. a ¸ atunci va fi generat˘ o exceptie de tipul NotSerializableException.*.2. class C { int x =0. // NU y = 2. In caz contrar. // Obligatoriu constructor fara argumente } class D extends C implements Serializable { int y =0. a ¸ Listing 8. y .2: Membrii neserializabili import java . } class B implements Serializable { int y =2.3: Serializarea cˆmpurilor mo¸tenite a s import java . salvarea cˆmpurilor a a a a a clasei p˘rinte se va face doar dac˘ ¸i aceasta este serializabil˘. io . } public class Test3 extends D { public Test3 () { x = 1. a as a subclasa trebuie s˘ salveze explicit ¸i cˆmpurile mo¸tenite. // DA public String toString () { return a . io . x + " . } public class Test2 implements Serializable { A a = new A () .8. " + b .

} } Mai jos este descrisa o aplicatie care efectueaz˘ salvarea ¸i restaurarea ¸ a s unor obiecte din cele trei clase prezentate mai sus. System . } catch ( Cl as sNo t F o u n d E x c e p t i o n e ) { e . close () . out . out . try { test ( new Test2 () ) . ser " ) . out . println ( " A fost restaurat obiectul : " + obj ) . } fis . // Restauram FileInputStream fis = new FileInputStream ( " fisier . public class Exemplu { public static void test ( Object obj ) throws IOException { // Salvam FileOutputStream fos = new FileOutputStream ( " fisier . System .4: Testarea serializ˘rii a import java . readObject () . fos . } public static void main ( String args []) throws IOException { test ( new Test1 () ) . writeObject ( obj ) . close () . println ( " A fost salvat obiectul : " + obj ) . ObjectInputStream in = new Obje ctInput Stream ( fis ) . printStackTrace () . flush () . " + y .*. out . SERIALIZAREA OBIECTELOR } public String toString () { return x + " . ser " ) . } catch ( N o t Se r i a l i z a b l e E x c e p t i o n e ) { . io .186 CAPITOLUL 8. ObjectOutputStrea m out = new Ob je ct Ou tp utS tr ea m ( fos ) . Listing 8. try { obj = in .

ad˘ugˆnd ¸i alte informatii necesare a a a s ¸ pentru serializarea unor obiecte. citind informatiile salvate a ın ¸ ¸i. 2 8. De asemenea. eventual. 3. In aceste situatii. dup˘ cum ıns˘ a am spus. 3.ObjectOutputStream stream) throws IOException private void readObject(java. 0. fiind creat pentru cazul general. 4 neserializabil: java. PERSONALIZAREA SERIALIZARII OBIECTELOR System .3. println ( " Obiect neserializabil : " + e ) .NotSerializableException: A salvat obiectul: 1. out . putem s˘ ˆ ¸ a ınlocuim algoritmul implicit cu unul propriu.˘ 8. } } 187 Rezultatul acestui program va fi : A fost A fost Obiect A fost A fost salvat obiectul: 1. particularizat pentru o clas˘ anume.io. 4 restaurat obiectul: 1. ClassNotFoundException Metoda writeObject controleaz˘ ce date sunt salvate iar readObject a controleaz˘ modul ˆ care sunt restaurate obiectele.io. In majoritatea cazurilor mecanismul standard este suficient ˆ a. 2. modifcˆnd starea obiectelor citite astfel ˆ at ele s˘ corespund˘ s a ıncˆ a a .io. 2 restaurat obiectul: 0. se poate comporta ineficient ˆ a ın anumite situatii: poate fi mult mai lent decˆt este cazul sau reprezentarea ¸ a binar˘ generat˘ pentru un obiect poate fi mult mai voluminoas˘ decˆt ar a a a a trebui. o clas˘ poate avea nevoie de mai mult control asupra serializ˘rii. a a Personalizarea serializarii se realizeaz˘ prin definirea (ˆ a ıntr-o clas˘ seriala izabil˘!) a metodelor writeObject ¸i readObject avˆnd exact signatura de a s a mai jos: private void writeObject(java.ObjectInputStream stream) throws IOException. } test ( new Test3 () ) .3 Personalizarea serializ˘rii obiectelor a Dezavantajul mecanismului implicit de serializare este c˘ algoritmul pe care a se beazeaz˘. este posibil a s˘ extindem comportamentul implicit.

putem s˘ folosim metodele defaultWriteObject.3. etc. 8.ClassNotFoundException { // Restaurarea obiectului curent stream.. etc...) . respectiv a defaultReadObject care descriu procedurile implicite de serializare.) // si extragerea informatiilor suplimentare .defaultReadObject(). SERIALIZAREA OBIECTELOR anumitor cerinte.. // Scrierea obiectului curent stream. // Adaugarea altor informatii suplimentare .. Forma general˘ de implementare a metodelor writeObject ¸i readObject a s este: private void writeObject(ObjectOutputStream stream) throws IOException { // Procesarea campurilor clasei (criptare. In cazul ˆ care nu dorim s˘ ˆ ¸ ın a ınlocuim complet mecanismul standard. Dac˘ ˆ a o clas˘ trebuie sa-¸i coordoneze serializarea pros a ıns˘ a s prie cu serializarea superclasei sale. } Metodele writeObject ¸i readObject sunt responsabile cu serializarea s clasei ˆ care sunt definite. serializarea superclasei sale fiind facut˘ automat ın a (¸i implicit)..1 Controlul versiunilor claselor S˘ presupunem c˘ dorim s˘ realiz˘m o aplicatie care s˘ ¸in˘ evidenta angajatilor a a a a ¸ at a ¸ ¸ unei companii. Evident. vom avean nevoie de o clas˘ care s˘ reprezinte a a . atunci trebuie s˘ implementeze interfata a ¸ Externalizable. } private void readObject(ObjectInputStream stream) throws IOException.188 CAPITOLUL 8. // Actualizarea starii obiectului (decriptare.defaultWriteObject().

public int salariu . class Angajat implements Serializable { public String nume .3. parola = parola . private String parola .*. La fiecare pornire a aplicatiei. String parola ) { this . this . ser " ) . this . public void citire () throws IOException { FileInputStream fis = null . } public String toString () { return nume + " ( " + salariu + " ) " . io . .5: Prima variant˘ a clasei Angajat a import java . ObjectInputStream in = new Obje ctInput Stream ( fis ) . public class GestiuneAngajati { // Lista angajatilor ArrayList ang = new ArrayList () .˘ 8. import java . nume = nume . ¸ Listing 8. PERSONALIZAREA SERIALIZARII OBIECTELOR 189 notiunea de angjat. int salariu . public Angajat ( String nume .*. salariu = salariu . } } Mai jos este prezentat˘ o mic˘ aplicatie care permite introducerea de a a ¸ angajati ¸i salvarea lor ˆ ¸ s ıntr-un fi¸ier.6: Aplicatia de gestionare a angajatilor ¸ ¸ import java . O variant˘ simplificat˘ a acesteia ar putea ar˘ta astfel: ¸ a a a Listing 8. vor fi s ¸ citite datele din fi¸ier astfel ˆ at programul va actualiza ˆ permanent˘ lista s ıncˆ ın ¸a angajatilor cu noi persoane. io . try { fis = new FileInputStream ( " angajati .*. util .

String parola = stdin . startsWith ( " N " ) ) break . out . String nume = stdin . print ( " Parola : " ) . int salariu = Integer .. ang . " ) . println ( " Eroare la citirea datelor .. while ( true ) { System . print ( " Mai adaugati ? ( D / N ) " ) . out . ObjectOutputStrea m out = new Ob je ct Ou tp utS tr ea m ( fos ) . } public void adaugare () throws IOException { BufferedReader stdin = new BufferedReader ( new InputStream Reader ( System . if ( raspuns . out . } finally { if ( fis != null ) fis . readLine () . writeObject ( ang ) . add ( new Angajat ( nume . " ) . readLine () ) . printStackTrace () . System .190 CAPITOLUL 8. out . String raspuns = stdin . println ( " Fisierul nou . parseInt ( stdin . . System . print ( " Salariu : " ) . println ( " Lista angajatilor :\ n " + ang ) . } catch ( Exception e ) { System . } catch ( File NotF o u n d E x c e p t i o n e ) { System . e . out . in ) ) . System . readLine () . } public void salvare () throws IOException { FileOutputStream fos = new FileOutputStream ( " angajati . close () . readObject () . SERIALIZAREA OBIECTELOR ang = ( ArrayList ) in . } System . salariu . out . readLine () . out . out . toUpperCase () .. parola ) ) . ser " ) . print ( " \ nNume : " ) .. } } public static void main ( String args []) throws IOException { GestiuneAngajati app = new GestiuneAngajati () .

} } Problema care se pune acum este urm˘toarea. salvare () . In plus. a a este generat pornind de la diverse informatii ale clasei. cum ar a fi ad˘ugarea unui nou cˆmp. denumit serialVersionUID. La restaurarea unui obiect. citire () . In cazul ˆ a s a a ın care acestea nu sunt egale. Acest lucru se realizeaz˘ a a a a prin setarea manual˘ a variabilei serialVersionUID ˆ cadrul clasei dorite. va fi generat˘ o exceptie de tipul a ¸ InvalidClassException ¸i deserializarea nu va fi f˘cut˘. procedura de citire a angajatilor din fi¸ier nu ¸ ¸ ¸ s va mai functiona.˘ 8. De ce se ˆ amplˆ acest lucru ? ıntˆ a Explicatia const˘ ˆ faptul c˘ mecanismul de serializare Java este foarte ¸ a ın a atent cu signatura claselor serializate. va determina modificarea num˘rului s˘u de a a a a versiune. PERSONALIZAREA SERIALIZARII OBIECTELOR 191 // Incarcam angajatii din fisier app . clasa Angajat este modifia ¸ ın s cat˘ prin ad˘ugarea unei noi variabil˘ membre care s˘ retina adresa. adaugare () . producˆnd o exceptie de tipul InvalidClassException. La a a a a ¸ executia aplicatiei noastre. cum ar fi variabilele ¸ sale membre. ¸ a ¸ Aceast˘problem˘ ar fi ap˘rut chiar dac˘ variabila ad˘ugat˘ era declarat˘ de a a a a a a a tip transient. In aceast˘ situatie trebuie s˘ comua ¸ a nic˘m explicit c˘ cele dou˘ clase sunt compatibile. orice modificare semnificativ˘ a clasei. num˘rul de versiune salvat ˆ forma serializat˘ a ın a va fi reg˘sit ¸i comparat cu noua semn˘tur˘ a clasei obiectului. // Salvam angajatii inapoi fisier app .3. Dup˘ introducerea unui a a num˘r suficient de mare de angajati ˆ fi¸ier. Acest num˘r. // Adaugam noi angajati app . dat poate fi sup˘r˘toare atunci cˆnd modific˘rile aduse clasei nu stric˘ aa a a a compatibilitatea cu vechea versiune. care reprezint˘ un fel de a ¸ a ”amprent˘” a clasei obiectului. (dar nu numai) ¸i este salvat ˆ procesul de serializare ˆ s ın ımpreun˘ a cu celelalte date. s a a Aceast˘ abordare extrem de precaut˘ este foarte util˘ pentru prevenirea a a a unor anomalii ce pot ap˘rea cˆnd dou˘ versiuni de clase sunt incompatia a a bile. Pentru fiecare obiect serializat este calculat automat un num˘r reprezentat pe 64 de biti. a ın ad˘ugˆnd pur ¸i simplu cˆmpul: a a s a .

La noua ın ın . private String parola .7: Variant˘ compatibil˘ a clasei Angajat a a import java . Cum putem afla ˆ a num˘rul de sea a ıns˘ a rie al vechii clase Angajat care a fost folosit˘ anterior la salvarea angajatilor a ¸ ? Utilitarul serialVer permite generarea num˘rului serialVersionUID pena tru o clas˘ specificat˘. ˆ a rubrica adres˘ nu va fi initializat˘ ¸ a ¸ ıns˘ a ¸ a ˆ nici un fel (va fi null). class Angajat implements Serializable { static final long serialVersionUID = 56 534 93 248 680 665 29 7 L . this . Rezultatul va fi: s a a a Angajat: static final long serialVersionUID = 5653493248680665297L.192 CAPITOLUL 8. String parola ) { this . } public String toString () { return nume + " ( " + salariu + " ) " . adresa . a a ci s˘-l foloseasc˘ pe cel specificat de noi. public String nume . public int salariu . adresa = " Iasi " . SERIALIZAREA OBIECTELOR static final long serialVersionUID = /* numar_serial_clasa */. Prezenta variabilei serialVersionUID printre membrii unei clase va in¸ forma algoritmul de serialzare c˘ nu mai calculeze num˘rul de serie al clasei. } } Aplicatia noastr˘ va functiona acum. trebuie s˘ recompil˘m vechea clas˘ Angajat a a s a a a ¸i s˘-i afl˘m num˘rul de serie astfel: serialVer Angajat. this .*. A¸adar. Vom rescrie noua clas˘ Angajat astfel ˆ at s˘ fie compatibil˘ cu cea a ıncˆ a a veche astfel: Listing 8. nume = nume . public Angajat ( String nume . io . deoarece ea nu exista ˆ formatul original. salariu = salariu . int salariu . parola = parola . this .

a s precum ¸i prin utilizarea unei functii de criptare a datelor.. io . n < input .3. salariu = salariu . implementˆnd metodele readObject ¸i writeObject. Problema const˘ ˆ faptul c˘. adresa . parola = parola . public int salariu . String parola ) { this .2 Securizarea datelor Dup˘ cum am v˘zut membrii privati. s ¸ a trebuie ˆ a s˘ le citim de la tastatur˘. a a ¸ Rezolvarea acestei probleme se face prin modificarea mecanismului implicit de serializare. informatiile unui obiect serializat nu sunt criptate ˆ nici un fel ¸i pot ¸ ın s fi reg˘site cu u¸urint˘. } public String toString () { return nume + " ( " + salariu + " ) " . this . . toString () .*. ceea ce poate reprezenta un inconvenient atunci cˆnd a s ¸a a exist˘ cˆmpuri confidentiale. } static String criptare ( String input .˘ 8. this .) ıns˘ a a 8. for ( int n =0. de¸i ˆ format a a ın a s ın binar. vor fi serializate ¸i informatiile legate de adres˘ (evident. length () . class Angajat implements Serializable { static final long serialVersionUID = 5 65 349 324 868 06 652 97 L . nume = nume . charAt ( n ) ) ) . n ++) sb . adresa = " Iasi " . PERSONALIZAREA SERIALIZARII OBIECTELOR 193 salvare a datelor.8: Varianta securizat˘ a clasei Angajat a import java . return sb . int offset ) { StringBuffer sb = new StringBuffer () . this . public String nume .3. int salariu . Varianta securs ¸ izat˘ a clasei Angajat din exemplul anterior ar putea ar˘ta astfel: a a Listing 8. particip˘ la serializare. append (( char ) ( offset + input . cum ar fi parola din exemplul de mai a a ¸ sus.. private String parola . public Angajat ( String nume .

3) . interfata Externalizable este folosit˘ ˆ situatii ˆ care se dore¸te ¸ a ın ¸ ın s ˆ ımbun˘t˘¸irea performantelor algoritmului standard. aceste clase trebuie s˘ implementeze obligatoriu metodele writes a External ¸i readExternal ˆ care se va face serializarea complet˘ a obiectelor s ın a ¸i coordonarea cu superclasa ei. defaultWri te Ob je ct () . } A¸adar. explicit. al procesului de serializare. -3) . .3 Implementarea interfetei Externalizable ¸ Pentru un control complet. public interface Externalizable extends Serializable { public void writeExternal(ObjectOutput out) throws IOException. Pentru instante ale acestor a ¸ ¸ clase doar numele clasei este salvat automat pe fluxul de obiecte. defaultRead Object () . ClassNotFoundException. SERIALIZAREA OBIECTELOR private void writeObject ( Ob je ct Ou tpu tS tr ea m stream ) throws IOException { parola = criptare ( parola .3. clasa fiind responsabil˘ cu scrierea ¸i citirea membrilor s˘i ¸i trebuie s˘ se coordoneze a s a s a cu superclasele ei. Definitia interfetei Externalizable este: ¸ ¸ package java. stream . } } 8. -3) . s Uzual. C l a s s N o t F o u n d E x c e p t i o n { stream . parola = criptare ( parola . public void readExternal(ObjectInput in) throws IOException.194 } CAPITOLUL 8. parola = criptare ( parola .io. } private void readObject ( O bjectIn putStre am stream ) throws IOException . mai exact cre¸terea vitezei a at ¸ s procesului de serializare. o clas˘ trea buie s˘ implementeze interfata Externalizable.

9: Serializare implicit˘ a import java . int cod ) { this . public Persoana ( String nume .*. this . } public void readExternal ( ObjectInput s ) throws ClassNotFoundException . IOException { nume = s . nume = nume . writeUTF ( nume ) . readUTF () .10: Serializare proprie import java . PERSONALIZAREA SERIALIZARII OBIECTELOR 195 Mai jos este prezentat˘ o clas˘ simpl˘ ¸i modalitatea de rescriere a sa a a a s folosind interfata Externalizable: ¸ Listing 8.*. String nume . cod = cod . readInt () . class Persoana implements Serializable { int cod . writeInt ( cod ) . this . } } Listing 8. cod = cod . String nume . s . nume = nume . cod = s .˘ 8. class Persoana implements Externalizable { int cod . int cod ) { this . io .3. } } . io . public Persoana ( String nume . } public void writeExternal ( ObjectOutput s ) throws IOException { s .

ˆ a a a ımpreuna cu copierea tuturor obiectelor referite de cˆmpurile acelui obiect poate fi a implementat˘ prin mecanismul serializ˘rii astfel: a a public Object clone() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(). s a a O posibilitate de a face o copie a unui obiect este folosirea metodei clone definit˘ ˆ clasa Object. In cazul ˆ care exist˘ cˆmpuri a ın a a referinta la alte obiecte. out.clone(). in. ObjectInputStream in = new ObjectInputStream(bais). TipReferinta o2 = (TipReferinta) o1. ObjectOutputStream out = new ObjectOutputStream(baos). TipReferinta o1 = new TipReferinta(). ¸ a O metod˘ clone care s˘ realizeze o copie efectiv˘ a unui obiect. nu face decˆt s˘ declare o nou˘ variabil˘ o2 ca referinta la obiectul referit de a a a a ¸ o1 ¸i nu creeaz˘ sub nici o form˘ un nou obiect. s a ¸ O secventa de forma: ¸ TipReferinta o1 = new TipReferinta(). ByteArrayInputStream bais = new ByteArrayInputStream(buffer). SERIALIZAREA OBIECTELOR 8. Aceasta creeaz˘ un nou obiect ¸i initializeaz˘ toate a ın a s ¸ a variabilele sale membre cu valorile obiectului clonat. obiectele referite nu vor mai fi clonate la rˆndul lor.196 CAPITOLUL 8.4 Clonarea obiectelor Se ¸tie c˘ nu putem copia valoarea unui obiect prin instructiunea de atribuire. out. Object ret = in.toByteArray().close(). return ret.readObject().writeObject(this). Deficienta acestei metode este c˘ nu realizeaz˘ duplicarea ˆ ¸ a a ıntregii retele ¸ de obiecte corespunz˘toare obiectului clonat. } catch (Exception e) { . TipReferinta o2 = o1.close(). byte[] buffer = baos.

8.println(e).4. CLONAREA OBIECTELOR System.out. return null. } } 197 .

198 CAPITOLUL 8. SERIALIZAREA OBIECTELOR .

exist˘ dou˘ modalit˘¸i de a crea o aplicatie cu a a at ¸ interfata grafic˘ ¸i anume: ¸˘ as • AWT (Abstract Windowing Toolkit) . ın a s Swing se bazeaz˘ pe modelul AWT.1 Introducere Interfata grafic˘ cu utilizatorul (GUI). pe de o parte dificult˘¸ii legate de a at implementarea notiunii de portabilitate.este API-ul initial pus la dispozitie ¸ ¸ ˆ ıncepˆnd cu primele versiuni de Java. prin a ¸ care vom ˆ ıntelege conceptul generic de interactiune dintre program ¸i utiliza¸ s tori. Limbajul Java pune la dispozitie numeroase clase pentru implementarea ¸ diverselor functionalitati UI. Aceasta este o particularizare a interfetei cu utilizatorul (UI). Netscape ¸i IBM. este un termen cu ˆ ¸eles larg care ¸ a ınt se refer˘ la toate tipurile de comunicare vizual˘ ˆ a a ıntre un program ¸i utilizas torii s˘i. ¸ De la aparitia limbajului Java. ˆ a ne vom ocupa ˆ continuare de cele care ¸ ıns˘ ın permit realizarea intefetei grafice cu utilizatorul (GUI). bibliotecile de clase care ofer˘ servicii ¸ a grafice au suferit probabil cele mai mari schimb˘ri ˆ trecerea de la o vera ın siune la alta. 199 .parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) creat ˆ urma colabor˘rii dintre Sun. pe de alt˘ parte nevoii de a integra ¸ a mecanismele GUI cu tehnologii ap˘rute ¸i dezvoltate ulterior. extinzˆnd functionalitatea acestuia a a ¸ ¸i ad˘ugˆnd sau ˆ s a a ınlocuind componente pentru dezvoltarea aplicatiilor ¸ GUI. In momentul actual. cum ar fi Java a s Beans. a • Swing .Capitolul 9 Interfata grafic˘ cu utilizatorul ¸ a 9. Acest lucru se datoreaz˘.

prin notiunea de component˘ s ¸ a vom ˆ ıntelege ˆ continuare orice obiect care poate avea o reprezentare grafic˘ ın a ¸i care poate interactiona cu utilizatorul. controale pentru editarea textelor. ıns˘ ¸ a ¸ reutilizate ˆ Swing. crearea unei aplicatii grafice presupune urm˘toarele lucruri: ¸ a • Design – Crearea unei suprafete de afi¸are (cum ar fi o fereastr˘) pe care vor ¸ s a fi a¸ezate obiectele grafice (componente) care servesc la comunis carea cu utilizatorul (butoane. s 9. – Crearea ¸i a¸ezarea componentelor pe suprafata de afi¸are la pozitiile s s ¸ s ¸ corespunz˘toare. a ¸ a In principiu. listele. care poate fi o fereastr˘ ıntˆ s s a . este de preferat ca aplicatiile Java s˘ fie create folosind tehnologia s ¸ a Swing. bare de defilare. deoarece va fi simplificat procesul de ˆ ¸elegere a ınt dezvolt˘rii unei aplicatii GUI.200 ˘ CAPITOLUL 9. a Obiectele grafice sunt derivate din Component. butoanele. liste. etc. A¸adar. a Crearea obiectelor grafice nu realizeaz˘ automat ¸i afi¸area lor pe ecran. ¸ s ¸ a a¸a cum au fost ele definite. Toate componentele AWT sunt definte de clase proprii ce se gasesc ˆ pachetul java. a s s Mai ˆ ai ele trebuie a¸ezate pe o suprafata de afi¸are. cu exceptia meniurilor care ¸ descind din clasa MenuComponent. aceasta punˆnd la dispozitie o palet˘ mult mai larg˘ de facilit˘¸i. ¸ a ¸ – ”Ascultarea” evenimentelor generate de obiecte ˆ momentul ın interactiunii cu utilizatorul ¸i executarea actiunilor corespunz˘toare. a • Functionalitate ¸ – Definirea unor actiuni care trebuie s˘ se execute ˆ momentul cˆnd ¸ a ın a utilizatorul interactioneaz˘ cu obiectele grafice ale aplicatiei. dup˘ care vom face trecerea la Swing. INTERFATA GRAFICA CU UTILIZATORUL ¸ A¸adar. ın In acest capitol vom prezenta clasele de baz˘ ¸i mecanismul de tratare a as evenimentelor din AWT. Exemple de componente sunt feres strele.awt. etc). clasa Component ın fiind superclasa abstract˘ a tuturor acestor clase.2 Modelul AWT Pachetul care ofer˘ componente AWT este java. a ¸ a a at ˆ a nu vom renunta complet la AWT deoarece aici exist˘ clase esentiale.awt.

9.2. MODELUL AWT

201

sau un applet, ¸i vor deveni vizibile ˆ momentul ˆ care suprafata pe care sunt s ın ın ¸ afi¸ate va fi vizibil˘. O astfel de suprafat˘ pe care sunt plasate componente s a ¸a se mai nume¸te container ¸i reprezint˘ o instant˘ a unei clase derivate din s s a ¸a Container. Clasa Container este o subclas˘ aparte a lui Component, fiind a la rˆndul ei superclasa tuturor suprafetelor de afi¸are Java. a s A¸a cum am v˘zut, interfat˘ grafic˘ serve¸te interactiunii cu utilizatorul. s a ¸a a s ¸ De cele mai multe ori programul trebuie s˘ fac˘ o anumit˘ prelucrare ˆ a a a ın momentul ˆ care utilizatorul a efectuat o actiune ¸i, prin urmare, compoın ¸ s nentele trebuie s˘ genereze evenimente ˆ functie de actiunea pe care au a ın ¸ ¸ suferit-o (actiune transmis˘ de la tastatur˘, mouse, etc.). Incepˆnd cu ver¸ a a a siunea 1.1 a limbajului Java, evenimentele sunt instante ale claselor derivate ¸ din AWTEvent. A¸adar, un eveniment este produs de o actiune a utilizatorului asupra unui s ¸ obiect grafic, deci evenimentele nu trebuie generate de programator. In schimb, ˆ ıntr-un program trebuie specificat codul care se execut˘ la aparitia a ¸ unui eveniment. Tratarea evenimentelor se realizeaz˘ prin intermediul unor a clase de tip listener (ascult˘tor, consumator de evenimente), clase care sunt a definite ˆ pachetul java.awt.event. In Java, orice component˘ poate ”conın a suma” evenimentele generate de o alt˘ component˘ (vezi ”Tratarea evenia a mentelor”). S˘ consider˘m un mic exemplu, ˆ care cre˘m o fereastr˘ ce contine dou˘ a a ın a a ¸ a butoane. Listing 9.1: O fereastr˘ cu dou˘ butoane a a
import java . awt .*; public class ExempluAWT1 { public static void main ( String args []) { // Crearea ferestrei - un obiect de tip Frame Frame f = new Frame ( " O fereastra " ) ; // Setarea modului de dipunere a componentelor f . setLayout ( new FlowLayout () ) ; // Crearea celor doua butoane Button b1 = new Button ( " OK " ) ; Button b2 = new Button ( " Cancel " ) ; // Adaugarea butoanelor f . add ( b1 ) ;

202

˘ CAPITOLUL 9. INTERFATA GRAFICA CU UTILIZATORUL ¸
f . add ( b2 ) ; f . pack () ; // Afisarea fereastrei f . show () ;

} }

Dup˘ cum veti observa la executia acestui program, atˆt butoanele ad˘ugate a ¸ ¸ a a de noi cˆt ¸i butonul de ˆ a s ınchidere a ferestrei sunt functionale, adic˘ pot fi ¸ a apasate, dar nu realizeaz˘ nimic. Acest lucru se ˆ ampl˘ deoarece nu am a ıntˆ a specificat nic˘ieri codul care trebuie s˘ se execute la ap˘sarea acestor bua a a toane. De asemenea, mai trebuie remarcat c˘ nu am specificat nic˘ieri dimensiua a nile ferestrei sau ale butoanelor ¸i nici pozitiile ˆ acestea s˘ fie plasate. Cu s ın a toate acestea ele sunt plasate unul lˆnga celalalt, f˘r˘ s˘ se suprapun˘ iar a aa a a suprafata fereastrei este suficient de mare cˆt s˘ cuprind˘ ambele obiecte. ¸ a a a Aceste ”fenomene” sunt provocate de un obiect special de tip FlowLayout pe care l-am specificat ¸i care se ocup˘ cu gestionarea ferestrei ¸i cu plasarea s a s componentelor ˆ ıntr-o anumit˘ ordine pe suprafata ei. A¸adar, modul de a ¸ s aranjare nu este o caracteristic˘ a suprafetei de afi¸are ci, fiecare container a ¸ s are asociat un obiect care se ocup˘ cu dimensionarea ¸i dispunerea compoa s nentelor pe suprafata de afi¸are ¸i care se numeste gestionar de pozitionare ¸ s s ¸ (layout manager) (vezi ”Gestionarea pozition˘rii”). ¸ a

9.2.1

Componentele AWT

Dup˘ cum am spus deja, toate componentele AWT sunt definte de clase a proprii ce se gasesc ˆ pachetul java.awt, clasa Component fiind superclasa ın abstracta a tuturor acestor clase. • Button - butoane cu eticheta format˘ dintr-un text pe o singur˘ linie; a a • Canvas - suprafat˘ pentru desenare; ¸a • Checkbox - component˘ ce poate avea dou˘ st˘ri; mai multe obiecte a a a de acest tip pot fi grupate folosind clasa CheckBoxGroup; • Choice - liste ˆ care doar elementul selectat este vizibil ¸i care se ın s deschid la ap˘sarea lor; a

9.2. MODELUL AWT

203

• Container - superclasa tuturor suprafetelor de afi¸are (vezi ”Suprafete ¸ s ¸ de afi¸are”); s • Label - etichete simple ce pot contine o singur˘ linie de text needitabil; ¸ a • List - liste cu selectie simpl˘ sau multipl˘; ¸ a a • Scrollbar - bare de defilare orizontale sau verticale; • TextComponent - superclasa componentelor pentru editarea textului: TextField (pe o singur˘ linie) ¸i TextArea (pe mai multe linii). a s Mai multe informatii legate de aceste clase vor fi prezentate ˆ sectiunea ¸ ın ¸ ”Folosirea componentelor AWT”. Din cauza unor diferente esentiale ˆ implementarea meniurilor pe diferite ¸ ın platforme de operare, acestea nu au putut fi integrate ca obiecte de tip Component, superclasa care descrie meniuri fiind MenuComponent (vezi ”Meniuri”).

Componentele AWT au peste 100 de metode comune, mo¸tenite din clasa s Component. Acestea servesc uzual pentru aflarea sau setarea atributelor obiectelor, cum ar fi: dimensiune, pozitie, culoare, font, etc. ¸i au formatul ¸ s general getProprietate, respectiv setProprietate. Cele mai folosite, grupate pe tipul propriet˘¸ii gestionate sunt: at • Pozitie ¸ getLocation, getX, getY, getLocationOnScreen setLocation, setX, setY • Dimensiuni getSize, getHeight, getWidth setSize, setHeight, setWidth • Dimensiuni ¸i pozitie s ¸ getBounds setBounds • Culoare (text ¸i fundal) s getForeground, getBackground setForeground, setBackground

204

˘ CAPITOLUL 9. INTERFATA GRAFICA CU UTILIZATORUL ¸

• Font getFont setFont • Vizibilitate setVisible isVisible • Interactivitate setEnabled isEnabled

9.2.2

Suprafete de afi¸are (Clasa Container) ¸ s

Crearea obiectelor grafice nu realizeaz˘ automat ¸i afi¸area lor pe ecran. Mai a s s ˆ ai ele trebuie a¸ezate pe o suprafat˘, care poate fi o fereastr˘ sau suprafata ıntˆ s ¸a a ¸ unui applet, ¸i vor deveni vizibile ˆ momentul ˆ care suprafata respectiv˘ s ın ın ¸ a va fi vizibil˘. O astfel de suprafata pe care sunt plasate componentele se a ¸ nume¸te suprafat˘ de afi¸are sau container ¸i reprezint˘ o instanta a unei clase s ¸a s s a ¸ derivat˘ din Container. O parte din clasele a c˘ror p˘rinte este Container a a a este prezentat˘ mai jos: a • Window - este superclasa tututor ferestrelor. Din aceast˘ clas˘ sunt a a derivate: – Frame - ferestre standard; – Dialog - ferestre de dialog modale sau nemodale; • Panel - o suprafat˘ f˘r˘ reprezentare grafic˘ folosit˘ pentru gruparea ¸a a a a a altor componente. Din aceast˘ clas˘ deriv˘ Applet, folosit˘ pentru a a a a crearea appleturilor. • ScrollPane - container folosit pentru implementarea automat˘ a derul˘rii a a pe orizontal˘ sau vertical˘ a unei componente. a a A¸adar, un container este folosit pentru a ad˘uga componente pe suprafata s a ¸ lui. Componentele ad˘ugate sunt memorate ˆ a ıntr-o list˘ iar pozitiile lor din a ¸ aceast˘ list˘ vor defini ordinea de traversare ”front-to-back” a acestora ˆ a a ın cadrul containerului. Dac˘ nu este specificat nici un index la ad˘ugarea unei a a componente, atunci ea va fi adaugat˘ pe ultima pozitie a listei. a ¸

9.2. MODELUL AWT

205

Clasa Container contine metodele comune tututor suprafetelor de afi¸are. ¸ ¸ s Dintre cele mai folosite, amintim: • add - permite ad˘ugarea unei componente pe suprafata de afi¸are. a ¸ s O component˘ nu poate apartine decˆt unui singur container, ceea ce a ¸ a ˆ ınseamn˘ c˘ pentru a muta un obiect dintr-un container ˆ altul trebuie a a ın sa-l eliminam mai ˆ ai de pe containerul initial. ıntˆ • remove - elimin˘ o component˘ de pe container; a a • setLayout - stabile¸te gestionarul de pozitionare al containerului (vezi s ¸ ”Gestionarea pozition˘rii”); ¸ a • getInsets - determin˘ distanta rezervat˘ pentru marginile suprafetei a ¸ a ¸ de afi¸are; s • validate - forteaz˘ containerul s˘ rea¸eze toate componentele sale. ¸ a a s Aceast˘ metod˘ trebuie apelat˘ explicit atunci cˆnd ad˘ug˘m sau elimin˘m a a a a a a a componente pe suprafata de afi¸are dup˘ ce aceasta a devenit vizibil˘. ¸ s a a Exemplu: Frame f = new Frame("O fereastra"); // Adaugam un buton direct pe fereastra Button b = new Button("Hello"); f.add(b); // Adaugam doua componente pe un panel Label et = new Label("Nume:"); TextField text = new TextField(); Panel panel = new Panel(); panel.add(et); panel.add(text); // Adaugam panel-ul pe fereastra // si, indirect, cele doua componente f.add(panel);

206

˘ CAPITOLUL 9. INTERFATA GRAFICA CU UTILIZATORUL ¸

9.3

Gestionarea pozition˘rii ¸ a

S˘ consider˘m mai ˆ ai un exemplu de program Java care afi¸eaz˘ 5 butoane a a ıntˆ s a pe o fereastr˘: a Listing 9.2: Pozitionarea a 5 butoane ¸
import java . awt .*; public class TestLayout { public static void main ( String args []) { Frame f = new Frame ( " Grid Layout " ) ; f . setLayout ( new GridLayout (3 , 2) ) ; // * Button Button Button Button Button b1 b2 b3 b4 b5 = = = = = new new new new new Button ( " Button 1 " ) ; Button ( " 2 " ) ; Button ( " Button 3 " ) ; Button ( " Long - Named Button 4 " ) ; Button ( " Button 5 " ) ;

f . add ( b1 ) ; f . add ( b2 ) ; f . add ( b3 ) ; f . add ( b4 ) ; f . add ( b5 ) ; f . pack () ; f . show () ; } }

Fereastra afi¸ata de acest program va ar˘ta astfel: s a

S˘ modific˘m acum linia marcata cu ’*’ ca mai jos, l˘sˆnd neschimbat a a aa restul programului: Frame f = new Frame("Flow Layout"); f.setLayout(new FlowLayout()); Fereastra afi¸at˘ dup˘ aceast˘ modificare va avea o cu totul altfel de s a a a dispunere a componentelor sale:

˘ 9.3. GESTIONAREA POZITIONARII ¸

207

Motivul pentru care cele dou˘ ferestre arat˘ atˆt de diferit este c˘ folosesc a a a a gestionari de pozitionare diferiti: GridLayout, respectiv FlowLayout. ¸ ¸ Definitie ¸ Un gestionar de pozitionare (layout manager) este un obiect care con¸ troleaz˘ dimensiunea ¸i aranjarea (pozitia) componentelor unui container. a s ¸ A¸adar, modul de aranjare a componentelor pe o suprafata de afi¸are s ¸ s nu este o caracteristic˘ a containerului. Fiecare obiect de tip Container a (Applet, Frame, Panel, etc.) are asociat un obiect care se ocup˘ cu disa punerea componentelor pe suprafata sa ¸i anume gestionarul s˘u de pozitionare. ¸ s a ¸ Toate clasele care instantiaza obiecte pentru gestionarea pozition˘rii imple¸ ¸ a menteaz˘ interfat˘ LayoutManager. a ¸a La instantierea unui container se creeaz˘ implicit un gestionar de pozitionare ¸ a ¸ asociat acestuia. De exemplu, pentru o fereastr˘ gestionarul implict este de a tip BorderLayout, ˆ timp ce pentru un panel este de tip FlowLayout. ın

9.3.1

Folosirea gestionarilor de pozitionare ¸

A¸a cum am v˘zut, orice container are un gestionar implicit de pozitionare s a ¸ un obiect care implemeneaz˘ interfata LayoutManager, acesta fiindu-i ata¸at a ¸ s automat la crearea sa. In cazul ˆ care acesta nu corespunde necesit˘¸ilor ın at noastre, el poate fi schimbat cu u¸urint˘. Cei mai utilizati gestionari din s ¸a ¸ pachetul java.awt sunt: • FlowLayout • BorderLayout • GridLayout • CardLayout • GridBagLayout

208

˘ CAPITOLUL 9. INTERFATA GRAFICA CU UTILIZATORUL ¸

Pe lˆng˘ ace¸tia, mai exist˘ ¸i cei din modelul Swing care vor fi prezentati a a s as ¸ ˆ capitolul dedicat dezvolt˘rii de aplicatii GUI folosind Swing. ın a ¸ Ata¸area explicit˘ a unui gestionar de pozitionare la un container se face s a ¸ cu metoda setLayout a clasei Container. Metoda poate primi ca parametru orice instant˘ a unei clase care implementeaz˘ interfat˘ LayoutManager. ¸a a ¸a Secventa de ata¸are a unui gestionar pentru un container, particularizat˘ ¸ s a pentru FlowLayout, este: FlowLayout gestionar = new FlowLayout(); container.setLayout(gestionar); // sau, mai uzual: container.setLayout(new FlowLayout()); Programele nu apeleaz˘ ˆ general metode ale gestionarilor de pozitionare, a ın ¸ dar ˆ cazul cˆnd avem nevoie de obiectul gestionar ˆ putem obtine cu metoda ın a ıl ¸ getLayout din clasa Container. Una din facilit˘¸ile cele mai utile oferite de gestionarii de pozitionare at ¸ este rearanjarea componentele unui container atunci cˆnd acesta este reda imesionat. Pozitiile ¸i dimensiunile componentelor nu sunt fixe, ele fiind ¸ s ajustate automat de c˘tre gestionar la fiecare redimensionare astfel ˆ at s˘ a ıncˆ a ocupe cˆt mai ”estetic” suprafata de afi¸are. Cum sunt determinate ˆ a a ¸ s ıns˘ dimensiunile implicite ale componentelor ? Fiecare clas˘ derivat˘ din Component poate implementa metodele getPrea a ferredSize, getMinimumSize ¸i getMaximumSize care s˘ returneze dis a mensiunea implicit˘ a componentei respective ¸i limitele ˆ afara c˘rora coma s ın a ponenta nu mai poate fi desenat˘. Gestionarii de pozitionare vor apela aceste a ¸ metode pentru a calcula dimensiunea la care vor afi¸a o component˘. s a Sunt ˆ a situatii cˆnd dorim s˘ plas˘m componentele la anumite pozitii ıns˘ ¸ a a a ¸ fixe iar acestea s˘ ramˆna acolo chiar dac˘ redimension˘m containerul. Folosind a a a a un gestionar aceast˘ pozitionare absolut˘ a componentelor nu este posibil˘ ¸i a ¸ a as deci trebuie cumva s˘ renunt˘m la gestionarea automat˘ a containerul. Acest a ¸a a lucru se realizeaz˘ prin trimitera argumentului null metodei setLayout: a // pozitionare absoluta a componentelor in container container.setLayout(null); Folosind pozitionarea absolut˘, nu va mai fi ˆ a suficient s˘ ad˘ugam cu ¸ a ıns˘ a a metoda add componentele ˆ container, ci va trebui s˘ specific˘m pozitia ¸i ın a a ¸ s

˘ 9.3. GESTIONAREA POZITIONARII ¸

209

dimensiunea lor - acest lucru era f˘cut automat de gestionarul de pozitionare. a ¸ container.setLayout(null); Button b = new Button("Buton"); b.setSize(10, 10); b.setLocation (0, 0); container.add(b); In general, se recomand˘ folosirea gestionarilor de pozitionare ˆ toate a ¸ ın situatiile cˆnd acest lucru este posibil, deoarece permit programului s˘ aib˘ ¸ a a a aceea¸i ”ˆ s ınfatisare” indiferent de platforma ¸i rezolutia pe care este rulat. s ¸ Pozitionarea absolut˘ poate ridica diverse probleme ˆ acest sens. ¸ a ın

S˘ analizam ˆ continuare pe fiecare din gestionarii amintiti anterior. a ın ¸

9.3.2

Gestionarul FlowLayout

Acest gestionar a¸eaz˘ componentele pe suprafata de afi¸are ˆ flux liniar, mai s a ¸ s ın precis, componentele sunt ad˘ugate una dup˘ alta pe linii, ˆ limita spatiului a a ın ¸ disponibil. In momentul cˆnd o component˘ nu mai ˆ a a ıncape pe linia curent˘ se a trece la urm˘toarea linie, de sus ˆ jos. Ad˘ugarea componentelor se face de a ın a la stˆnga la dreapta pe linie, iar alinierea obiectelor ˆ cadrul unei linii poate a ın fi de trei feluri: la stˆnga, la dreapta ¸i pe centru. Implicit, componentele a s sunt centrate pe fiecare linie iar distanta implicit˘ ˆ ¸ a ıntre componente este de 5 pixeli pe vertical˘ ¸i 5 pe orizontal˘. as a Este gestionarul implicit al containerelor derivate din clasa Panel deci ¸i s al applet-urilor. Listing 9.3: Gestionarul FlowLayout
import java . awt .*; public class TestFlowLayout { public static void main ( String args []) { Frame f = new Frame ( " Flow Layout " ) ; f . setLayout ( new FlowLayout () ) ; Button b1 = new Button ( " Button 1 " ) ; Button b2 = new Button ( " 2 " ) ; Button b3 = new Button ( " Button 3 " ) ;

care va fi amplasat apoi ˆ regiunea ın dorit˘ (vezi ”Gruparea componentelor . add ( b5 ) . CENTER. O component˘ poate fi a s a plasat˘ ˆ oricare din aceste regiuni. add ( b3 ) .clasa Panel”). f . ele trebuie grupate ˆ prealabil ˆ ın ıntr-un panel. show () .3 Gestionarul BorderLayout Gestionarul BorderLayout ˆ ımparte suprafata de afi¸are ˆ cinci regiuni.210 ˘ CAPITOLUL 9. core¸ s ın spunz˘toare celor patru puncte cardinale ¸i centrului. Button b5 = new Button ( " Button 5 " ) . care va fi specificat˘ prin una din constantele clasei: a a NORTH. SOUTH. add ( b4 ) . . dimeniunea componentei fiind calculata a ın astfel ˆ at s˘ ocupe ˆ ıncˆ a ıntreg spatiul de afi¸are oferit de regiunea respectiv˘. f . pack () . f .Named Button 4 " ) . add ( b1 ) . ultimele dintre ele vor fi trecute pe linia urm˘toare: a 9. } } Componentele ferestrei vor fi afi¸ate astfel: s Redimensionˆnd fereastra astfel ˆ at cele cinci butoane s˘ nu mai ˆ a ıncˆ a ıncap˘ a pe o linie. ¸ s a Pentru a ad˘uga mai multe obiecte grafice ˆ a ıntr-una din cele cinci zone.3. la ad˘ugarea unei componente pe o suprafat˘ gestionat˘ de BorderLayout. a A¸adar. s a ¸a a metoda add va mai primi pe lˆnga referinta componentei ¸i zona ˆ care a ¸ s ın aceasta va fi amplasat˘. add ( b2 ) . f . f . f . INTERFATA GRAFICA CU UTILIZATORUL ¸ Button b4 = new Button ( " Long . deci al tuturor tipurilor de ferestre. EAST. WEST. f . BorderLayout este gestionarul implicit pentru toate containerele care descind din clasa Window.

WEST ) . add ( new f .4 Gestionarul GridLayout Gestionarul GridLayout organizeaz˘ containerul ca un tabel cu rˆnduri ¸i a a s coloane. Button ( " Centru " ) . BorderLayout . Num˘rul de linii ¸i a a a a s coloane vor fi specificate ˆ constructorul gestionarului. // Apelul de mai jos poate sa lipseasca f . GESTIONAREA POZITIONARII ¸ Listing 9. 211 Cele cinci butoane ale ferestrei vor fi afi¸ate astfel: s La redimensionarea ferestrei se pot observa urm˘toarele lucruri: nordul ¸i a s sudul se redimensioneaz˘ doar pe orizontal˘.˘ 9. Button ( " Sud " ) . CENTER ) . estul ¸i vestul doar pe vertical˘. show () . Button ( " Vest " ) . pack () . add ( new f . } } Button ( " Nord " ) . add ( new f . NORTH ) . awt .3.4: Gestionarul BorderLayout import java . Button ( " Est " ) . ˆ ıncepˆnd cu primul rˆnd. a 9. add ( new f . SOUTH ) . public class TestBorderLayout { public static void main ( String args []) { Frame f = new Frame ( " Border Layout " ) . BorderLayout .*.3. componentele fiind plasate ˆ celulele tabelului de la stˆnga la ın a dreapta. add ( new f . setLayout ( new BorderLayout () ) . dar pot fi modificate ın . f . Celulele tabelului au dimensiuni egale a a iar o component˘ poate ocupa doar o singur˘ celul˘. EAST ) . BorderLayout . BorderLayout . a a s a ˆ timp ce centrul se redimensioneaz˘ atˆt pe orizontal˘ cˆt ¸i pe vertical˘. f . ın a a a a s a Redimensionarea componentelor din fiecare zon˘ se face astfel ˆ at ele ocup˘ a ıncˆ a toat˘ zona containerului din care fac parte. BorderLayout .

f . pack () . awt . f . respectiv setCols. Cele ¸ase butoane ale ferestrei vor fi plasate pe trei rˆnduri ¸i dou˘ s a s a coloane. add ( new f . distanta ˆ a a ¸ ıntre componente pe orizontal˘ ¸i distanta ˆ as ıntre rˆndurile tabelului pot fi specificate a ˆ constructor sau stabilite ulterior. atˆt pe orizontal˘ cˆt ¸i pe vertical˘. Button ( " 4 " ) ) . add ( new f . s a a a s a 9. Dac˘ num˘rul de linii s a a sau coloane este 0 (dar nu ambele ˆ acela¸i timp). setLayout ( new GridLayout (3 . show () . ın Listing 9. add ( new f . 2) ) .212 ˘ CAPITOLUL 9. public class TestGridLayout { public static void main ( String args []) { Frame f = new Frame ( " Grid Layout " ) .*. Button ( " 5 " ) ) . atunci componentele vor ın s fi plasate ˆ ıntr-o singur˘ coloan˘ sau linie.5: Gestionarul GridLayout import java . } } Button ( " 1 " ) ) . add ( new f . astfel: Redimensionarea ferestrei va determina redimensionarea tuturor celulelor ¸i deci a tuturor componentelor. INTERFATA GRAFICA CU UTILIZATORUL ¸ ¸i ulterior prin metodele setRows. De asemenea. Button ( " 2 " ) ) . add ( new f .5 Gestionarul CardLayout Gestionarul CardLayout trateaz˘ componentele ad˘ugate pe suprafata sa a a ¸ ˆ ıntr-o manier˘ similar˘ cu cea a dispunerii c˘rtilor de joc ˆ a a a¸ ıntr-un pachet. . add ( new f .3. f . Button ( " 3 " ) ) . Button ( " 6 " ) ) .

a Principala utilitate a acestui gestionar este utilizarea mai eficient˘ a a spatiului disponibil ˆ situatii ˆ care componentele pot fi grupate ˆ a¸a ¸ ın ¸ ın ın s fel ˆ at utilizatorul s˘ interactioneze la un moment dat doar cu un anumit ıncˆ a ¸ grup (o carte din pachet). tab .3. import java . a a Listing 9. a a Clasa dispune de metode prin care s˘ poat˘ fi afi¸at˘ o anumit˘ coma a s a a ponent˘ din pachet. Button card2 = new Button ( " Card 2 " ) . butoane . setLayout ( new CardLayout () ) .˘ 9. public class TestCardLayout extends Frame implements ActionListener { Panel tab . celelalte fiind ascunse. NORTH ) . numai o singur˘ coma a ponent˘ este vizibil˘ (”cea de deasupra”). O clas˘ Swing care implementeaz˘ un mecansim similar este JTabbedPane. add ( " Card 1 " . awt . TextField tf = new TextField ( " Text Field " ) . tab = new Panel () . Button card1 = new Button ( " Card 1 " ) . add ( butoane . BorderLayout .*. awt . tab . sau s˘ se poat˘ parcurge secvential pachetul. CENTER ) . btn ) . BorderLayout . add ( card2 ) .*. GESTIONAREA POZITIONARII ¸ 213 Suprafata de afi¸are poate fi asem˘nat˘ cu pachetul de c˘rti iar fiecare com¸ s a a a¸ ponent˘ este o carte din pachet. public TestCardLayout () { super ( " Test CardLayout " ) . butoane . tf ) . pack () .6: Gestionarul CardLayout import java . ordinea a a a ¸ componentelor fiind intern˘ gestionarului. event . add ( tab . tab . Panel butoane = new Panel () . . show () . La un moment dat. add ( " Card 2 " . Button btn = new Button ( " Button " ) . add ( card1 ) .

3. f . addActionListe ner ( this ) . ınalt a a s at o component˘ poate ocupa mai multe celule adiacente. getLayout () . Spre deosebire de GridLayout. card2 . INTERFATA GRAFICA CU UTILIZATORUL ¸ card1 . La fel ca ˆ s ¸ ın cazul gestionarului GridLayout. suprafata de afi¸are este considerat˘ ca fiind ¸ s a un tabel ˆ a. show () . De asemenea.214 ˘ CAPITOLUL 9. e . acesteia ˆ este s ıi asociat un obiect de tip GridBagConstraints. chiar de dimensiuni a diferite. spre deosebire de acesta. ˆ functie de componentele gestionate. Leg˘tura dintre o component˘ ¸i un ın a ın a a as obiect GridBagConstraints se realizeaz˘ prin metoda setConstraints: a GridBagLayout gridBag = new GridBagLayout(). } public static void main ( String args []) { TestCardLayout f = new TestCardLayout () . ˆ care se specific˘ diferite ın a propriet˘¸i ale componentei referitoare la regiunea s˘ de afi¸are ¸i la modul at a s s ˆ care va fi plasat˘ ˆ aceast˘ regiune. iar pe coloan˘ aib˘ aceea¸i l˘¸ime. . Pentru a specifica modul de afi¸are a unei componente. } } Prima ”carte” este vizibil˘ a A doua ”carte” este vizibil˘ a 9. dimensiunile s ın ¸ celulelor pot fi diferite cu singurele restrictii ca pe aceea¸i linie s˘ aib˘ aceea¸i ¸ s a a s ˆ ¸ime. } public void actionPerformed ( ActionEvent e ) { CardLayout gestionar = ( CardLayout ) tab . getActionCommand () ) . gestionar . show ( tab . ˆ functie de componentele amplasate pe suprafata de ın ¸ ¸ afi¸are.6 Gestionarul GridBagLayout Este cel mai complex ¸i flexibil gestionar de pozitionare din Java. addActionListe ner ( this ) . zona ocupat˘ fiind referit˘ prin ”regiunea de afi¸are” a componentei a a s respective. num˘rul de linii ¸i de coloane sunt ıns˘ a s determinate automat.

weighty . .folosit˘ pentru a specifica dac˘ o component˘ va ocupa ˆ a a a ıntreg spatiul pe care ˆ are destinat. container. c).folosite pentru distributia spatiului liber.num˘rul de celule pe linie ¸i coloan˘ pe care a s a va fi afi¸at˘ componenta. c).distantele dintre component˘ ¸i marginile suprafetei sale de ¸ as ¸ afi¸are. GridBagConstraints c = new GridBagConstraints(). . gridy . valorile posibile sunt HORIZONTAL. sud. ˆ s ınainte de a ad˘uga o component˘ pe suprafata unui container a a ¸ care are un gestionar de tip GridBagLayout. gridBag. Cele mai utilizate tipuri de constrˆngeri pot fi specificate prin intermediul a urm˘toarelor variabile din clasa GridBagConstraints: a • gridx. s • anchor .setConstraints(componenta. . VERTICAL. . s a • fill . GESTIONAREA POZITIONARII ¸ 215 container. • weigthx. ¸ ıl BOTH. NONE. . a ¸ a • gridwidth. • insets . . est.folosit˘ atunci cˆnd componenta este mai mic˘ decˆt suprafata a a a a ¸ sa de afi¸are pentru a forta o anumit˘ dispunere a sa: nord.celula ce reprezint˘ coltul stˆnga sus al componentei. Aceste constrˆngeri vor fi specificate prin intermediul unui obiect de tip a a GridBagConstraints. A¸adar.setConstraints(componenta1. //Specificam restrictiile referitoare la afisarea componentei . care poate fi refolosit pentru mai multe componente care au acelea¸i constrˆngeri de afi¸are: s a s gridBag. uzual ¸ ¸ au valoarea 1. s ¸ a vest.setLayout(gridBag). gridBag. gridheight . va trebui s˘ specific˘m anumiti a a ¸ parametri (constrˆngeri) referitori la cum va fi plasat˘ componenta respeca a tiv˘.setConstraints(componenta2. etc. c).add(componenta).˘ 9.3.

weighty = 1. gridBag . f . setConstraints ( comp . static void adauga ( Component comp . gbc . int h ) { gbc .216 ˘ CAPITOLUL 9. public class TestGridBag Layout { static Frame f . Pentru a a a a ın simplifica codul. int y . gridx = x . awt .7: Gestionarul GridBagLayout import java . gridheight = h .0. . ¸ a Listing 9. int x . gbc . gridy. s˘ realiz˘m o fereastr˘ ca ˆ figura de mai jos. int w . add ( comp ) . gbc . gridwidth = w . weightx = 1. gridwidth. gridheight ¸i ad˘ugarea unei componente cu s a restrictiile stabilite pe fereastr˘. gbc = new GridBa gC ons tr ai nt s () . gbc ) . } public static void main ( String args []) { f = new Frame ( " Test GridBagLayout " ) . gbc . gridBag = new GridBagLayout () . INTERFATA GRAFICA CU UTILIZATORUL ¸ Ca exemplu. gridy = y . static GridBagLayout gridBag . a fost creat˘ o metod˘ responsabil˘ cu setarea valorilor a a a gridx. gbc .*. static GridBagConstr aint s gbc .0.

2 . Button salvare = new Button ( " Salvare " ) . CENTER . 5 .3. insets = new Insets (5 . 2 . 1) . 1 . Button iesire = new Button ( " Iesire " ) . 1 . 30) . fill = GridBagConst ra in ts . 2) . 24) ) . 1 . setLayout ( gridBag ) . 1 . 1 . fill = GridBagConst ra in ts . 0 . gbc . 1) . mesaj . fill = GridBagConst ra in ts . BOLD . 0 . gbc . f . 2 . } } . mesaj . 1) . 1 . GESTIONAREA POZITIONARII ¸ gbc . CENTER ). gbc . pack () . setFont ( new Font ( " Arial " . Label etSalariu = new Label ( " Salariu : " ) . setBackground ( Color . Label etNume = new Label ( " Nume : " ) . f . TextField nume = new TextField ( " " . adauga ( adaugare . 0 . 4 . 0 . adauga ( mesaj . TextField salariu = new TextField ( " " . HORIZONTAL . gbc . 30) . fill = GridBagConst ra in ts . Label . 217 Label mesaj = new Label ( " Evidenta persoane " . adauga ( salariu .˘ 9. adauga ( nume . 3 . Button adaugare = new Button ( " Adaugare " ) . 1 . anchor = GridBagCon st ra in ts . show () . 2) . 4 . 2 . adauga ( iesire . 1) . EAST . 1 . BOTH . NONE . f . adauga ( etNume . fill = GridBagConst ra in ts . 3 . HORIZONTAL . gbc . 3 . 2 . 2 . yellow ) . adauga ( etSalariu . gbc . 1) . adauga ( salvare . Font . 5 . gbc . anchor = GridBagCon st ra in ts . 5) . NONE . 4 . 1) .

¸ ıncˆ a a indiferent de gestionarul de pozitionare al suprafetei de afi¸are. Gestionarul implicit pen¸ tru containerele de tip Panel este FlowLayout. se recomand˘ ın ın a gruparea componentelor ˆ ınrudite ca functii astfel ˆ at s˘ putem fi siguri c˘. public class TestPanel { public static void main ( String args []) { Frame f = new Frame ( " Test Panel " ) . prin specificarea gestionaru¸ lui de pozitionare al ferestrei. ¸ Listing 9. INTERFATA GRAFICA CU UTILIZATORUL ¸ 9. add ( new Button ( " Adaugare " ) ) . intro . Panel intro = new Panel () .218 ˘ CAPITOLUL 9. ¸ a • aranjarea panel-urilor pe suprafata ferestrei. Din acest motiv. intro .7 Gruparea componentelor (Clasa Panel) Plasarea componentelor direct pe suprafata de afi¸are poate deveni incomod˘ ¸ s a ˆ cazul ˆ care avem multe obiecte grafice. o aranjare eficient˘ a componentelor unei ferestre ˆ s a ınseamn˘: a • gruparea componentelor ”ˆ ınfratite” (care nu trebuie s˘ fie despartite ¸ a ¸ de gestionarul de pozitionare al ferestrei) ˆ panel-uri. ¸ ın • aranjarea componentelor unui panel. lista . intro . extensie a superclasei Container. setLayout ( new FlowLayout () ) . El nu are o reprezentare vizibil˘. 20) ) . awt . ele se vor g˘si ¸ ¸ s a ˆ ımpreun˘.8: Gruparea componentelor import java . lista . Clasa care instantiaza aceste obiecte ¸ este Panel. Panel lista = new Panel () .*.3. Gruparea componentelor se face ˆ panel-uri. a ın Un panel este cel mai simplu model de container. add ( new TextField ( " " . prin specificarea unui gestionar de pozitionare corespunz˘tor. A¸adar. add ( new List (10) ) . lista . setLayout ( new GridLayout (1 . add ( new Button ( " Stergere " ) ) . 3) ) . folosind metoda setLayout. Pentru a aranja corespunz˘tor a componentele grupate ˆ ıntr-un panel. add ( new Label ( " Text : " ) ) . rolul s˘u fiind de a oferi o suprafat˘ de afi¸are pentru componente a a ¸a s grafice. acestuia i se poate specifica un gestionar de pozitionare anume. inclusiv pentru alte panel-uri. . intro .

SOUTH ) . add ( control . s Interceptarea evenimentelor generate de componentele unui program se realizeaz˘ prin intermediul unor clase de tip listener (ascult˘tor. modia ficarea textului ˆ ıntr-un control de editare. TRATAREA EVENIMENTELOR 219 Panel control = new Panel () . NORTH ) . add ( new Button ( " Iesire " ) ) . ˆ ınchiderea sau redimensionarea unei ferestre.9. f . BorderLayout . control . add ( lista .4. pentru a scrie cod care s˘ se execute ˆ momentul ˆ care utilizas a ın ın torul interactioneaz˘ cu o component˘ grafic˘ trebuie s˘ facem urm˘toarele a a a a a lucruri: • s˘ scriem o clas˘ de tip listener care s˘ ”asculte” evenimentele produse a a a de acea component˘ ¸i ˆ cadrul acestei clase s˘ implement˘m metode a s ın a a specifice pentru tratarea lor. CENTER ) . f . BorderLayout . f . Exemple de evenimente sunt: ap˘sarea unui buton. consumator a a de evenimente). orice obiect poate ”consuma” evenimentele generate de o anumit˘ component˘ grafic˘. Componentele care genereaz˘ anumite evenimente se mai a numesc ¸i surse de evenimente. BorderLayout . f . add ( intro . add ( new Button ( " Salvare " ) ) . In Java. etc. control . .4 Tratarea evenimentelor Un eveniment este produs de o actiune a utilizatorului asupra unei compo¸ nente grafice ¸i reprezint˘ mecanismul prin care utilizatorul comunic˘ efectiv s a a cu programul. a a a A¸adar. pack () . show () . f . } } 9.

.. evenimentul generat de actionarea unui buton este ¸ descris de clasa ActionEvent. } } class AscultaTexte implements TextListener { public void textValueChanged(TextEvent e) { // Metoda interfetei TextListener . De exemplu. ca orice altceva ˆ Java. obiecte. Clasele care descriu ın aceste obiecte se ˆ ımpart ˆ mai multe tipuri ˆ functie de componenta care ın ın ¸ le genereaz˘. } } Intrucˆt o clas˘ poate implementa oricˆte interfete. a a O clas˘ consumatoare de evenimente (listener) poate fi orice clas˘ care a a specifica ˆ declaratia sa c˘ dore¸te s˘ asculte evenimente de un anumit ın ¸ a s a tip. ¸ Fiecare interfat˘ define¸te una sau mai multe metode care vor fi apelate ¸a s automat la aparitia unui eveniment: ¸ class AscultaButoane implements ActionListener { public void actionPerformed(ActionEvent e) { // Metoda interfetei ActionListener . pentru ascultarea evenimentelor de tip a ActionEvent clasa respectiv˘ trebuie s˘ implementeze interfata ActionListener. a ın ¸ ¸ Pentru fiecare tip de eveniment exist˘ o clas˘ care instantiaz˘ obiecte de a a ¸ a acel tip. Toate aceste interfete sunt derivate din EventListener. ea va putea s˘ asculte a a a ¸ a evenimente de mai multe tipuri: .. ¸a etc. a Evenimentele sunt. cel generat de modificarea unui text de clasa TextEvent. Toate aceste clase sunt derivate din superclasa AWTEvent. a a ¸ pentru TextEvent interfat˘ care trebuie implementata este TextListener. Astfel. cu alte cuvinte s˘ ˆ a a ınregistr˘m acea clas˘ a a drept ”consumator” al evenimentelor produse de componenta respectiv˘. etc..220 ˘ CAPITOLUL 9. mai precis ˆ functie de actiunea utilizatorului asupra acesteia. Acest lucru se realizeaz˘ prin implementarea unei interfete specifice a ¸ fiec˘rui tip de eveniment. lista lor complet˘ fiind prezentat˘ ulterior. INTERFATA GRAFICA CU UTILIZATORUL ¸ • s˘ comunic˘m componentei surs˘ c˘ respectiva clasa ˆ ”ascult˘” evenia a a a ıi a mentele pe care le genereaz˘.

a a ıntˆ a • Sursele evenimentelor permit oric˘rei clase s˘ ”asculte” evenimentele a a sale prin metode de tip addXXXListener. event .”.4. a a A¸a cum am spus mai devreme.. pentru ca evenimentele unei componente s s˘ fie interceptate de c˘tre o instant˘ a unei clase ascult˘tor. . TextListener { public void actionPerformed(ActionEvent e) { .*.4. a cu conditia ca acestea s˘ fie ˆ ¸ a ınregistrate la componenta respectiv˘. import java . Inregisa trarea unei clase ˆ lista ascult˘torilor unei componente se face cu metode ın a din clasa Component de tipul addTipEvenimentListener. repectiv ”Cancel”. s˘ consider˘m un exemplu a a de tratare a evenimentelor. awt . ¸ 9. } public void textValueChanged(TextEvent e) { .9. Am spus ın a lista. tratarea evenimentelor ˆ Java se desf˘¸oar˘ astfel: a ın as a • Componentele genereaz˘ evenimente cˆnd ceva ”interesant” se ˆ ampl˘.1 Exemplu de tratare a evenimentelor Inainte de a detalia aspectele prezentate mai sus. a a Sumarizˆnd.acestea descriu metode ce vor fi apelate a automat la aparitia evenimentelor. Vom crea o fereastr˘ care s˘ contin˘ dou˘ bua a ¸ a a toane cu numele ”OK”. unde XXX este un tip de eveniment. Listing 9.9: Ascultarea evenimentelor a dou˘ butoane a import java .*... } } 221 Vom vedea ˆ continuare metodele fiec˘rei interfete pentru a ¸ti ce trebuie ın a ¸ s s˘ implementeze o clas˘ consumatoare de evenimente. aceast˘ clas˘ a a ¸a a a a trebuie ˆ ınregistrata ˆ lista ascult˘torilor componentei respective. La ap˘sarea fiec˘rui buton vom a a scrie pe bara de titlu a ferestrei mesajul ”Ati apasat butonul . • O clas˘ care ascult˘ evenimente trebuie s˘ implementeze interfete specia a a ¸ fice fiec˘rui tip de eveniment . awt . deoarece evenimentele unei componente pot fi ascultate de oricˆte clase... TRATAREA EVENIMENTELOR class Ascultator implements ActionListener. iar eliminarea ei din aceast˘ list˘ cu removeTipEvenimentListener..

// instanta a clasei Ascultator .222 ˘ CAPITOLUL 9. In exemplul de mai sus am definit clasa Ascultator pentru a intercepta evenimentele produse de cele dou˘ butoane ¸i din acest motiv a a s trebuit s˘ trimitem ca parametru constructorului clasei o referinta la fereasa ¸ tra noastr˘. add ( b2 ) . b1 . // Ambele butoane sunt ascultate de obiectul listener . } } Nu este obligatoriu s˘ definim clase speciale pentru ascultarea evenia mentelor. } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e ) { f . public Ascultator ( Fereastra f ) { this . f = f . Ascultator listener = new Ascultator ( this ) . addActionListener ( listener ) . setLayout ( new FlowLayout () ) . Mai simplu ar fi fost s˘ folosim chiar clasa Fereastra pentru a a a trata evenimentele produse de componentele sale. Vom modifica putin ¸i ¸ s . setSize (200 . definita mai jos } } class Ascultator implements ActionListener { private Fereastra f . 100) . } } public class TestEvent1 { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test Event " ) . addActionListener ( listener ) . Button b2 = new Button ( " Cancel " ) . setTitle ( " Ati apasat " + e . f . getActionCommand () ) . add ( b1 ) . show () . INTERFATA GRAFICA CU UTILIZATORUL ¸ class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . Button b1 = new Button ( " OK " ) . b2 .

import java . } } } public class TestEvent2 { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test Event " ) . TRATAREA EVENIMENTELOR 223 aplicatia pentru a pune ˆ evidenta o alt˘ modalitate de a determina com¸ ın ¸ a ponenta generatoare a unui eveniment . // Terminam aplicatia if ( e . addActionListener ( this ) . add ( ok ) . exit .metoda getSource.9. ok .4. exit (0) . setTitle ( " Ati apasat OK de " + n + " ori " ) . addActionListener ( this ) . setLayout ( new FlowLayout () ) . getSource () == ok ) { n ++. int n =0.10: Tratarea evenimentelor ˆ ferestr˘ ın a import java . setSize (200 . 100) . getSource () == exit ) System .*.*. awt . this . // Ambele butoane sunt ascultate in clasa Fereastra // deci ascultatorul este instanta curenta : this } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e ) { if ( e . f . show () . } } . event . add ( exit ) . public Fereastra ( String titlu ) { super ( titlu ) . Listing 9. Button exit = new Button ( " Exit " ) . awt . class Fereastra extends Frame implements ActionListener { Button ok = new Button ( " OK " ) .

¸ WindowEvent Operatiuni asupra ferestrelor: ¸ minimizare. ın a s Evenimentele de nivel jos reprezint˘ o interactiune de nivel jos cum ar a ¸ fi o ap˘sare de tast˘. etc. sau o operatie asupra unei ferestre.2 Tipuri de evenimente Evenimentele se ˆ ımpart ˆ dou˘ categorii: de nivel jos ¸i semantice. Clasele a a care descriu aceste tipuri de evenimente sunt: ActionEvent AdjustmentEvent ItemEvent TextEvent Actionare ¸ Ajustarea unei valori Schimbarea st˘rii a Schimbarea textului . redimensionare. selectarea unui articol dintr-o list˘. a ¸ De exemplu. eliberare taste. deplasare. drag. unul pentru eliberare ¸i unul pentru tastare. tastare a MouseEvent Operatiuni cu mouse-ul: click. eliminare a FocusEvent Obtinere.224 ˘ CAPITOLUL 9. etc. orice clas˘ poate asculta evenimente de orice tip cu conditia s˘ s a ¸ a implementeze interfetele specifice acelor tipuri de evenimente. ¸ 9. pierdere foucs ¸ KeyEvent Ap˘sare. tastarea literei ’A’ va genera trei evenimente: unul pentru ap˘sare. maximizare. In functie de necea s ¸ sit˘¸ile aplicatie putem scrie cod pentru tratarea fiec˘rui eveniment ˆ parte. mi¸carea mouse-ului.etc. INTERFATA GRAFICA CU UTILIZATORUL ¸ A¸adar. afi¸are s ContainerEvent Ad˘ugare pe container. O anumit˘ actiune a utilizatorului poate genera mai multe evenimente.4. a a s ¸ In tabelul de mai jos sunt enumerate clasele ce descriu aceste evenimente ¸i s operatiunile efectuate (asupra unei componente) care le genereaz˘: ¸ a ComponentEvent Ascundere. at ¸ a ın Evenimentele semantice reprezint˘ interactiunea cu o component˘ a ¸ a GUI: ap˘sarea unui buton.

TRATAREA EVENIMENTELOR 225 Urm˘torul tabel prezint˘ componentele AWT ¸i tipurile de evenimente a a s generate.4. se vor reg˘si ¸i pentru a a s toate subclasele sale. de exemplu. a Orice clas˘ care trateaz˘ evenimente trebuie s˘ implementeze obligatoriu a a a metodele interfetelor corespunz˘toare. cum ar fi Component. prezentate sub forma interfetelor corespunz˘toare. ˆ situatia cˆnd tratarea acestora nu ne intereseaz˘ ¸i dorim s˘ ¸ ın ¸ a a s a trat˘m doar evenimente de tip click. Component Container Window Button List MenuItem TextField Choice Checkbox List CheckboxMenuItem Scrollbar TextField TextArea ComponentListener FocusListener KeyListener MouseListener MouseMotionListener ContainerListener WindowListener ActionListener ItemListener AdjustmentListener TextListener Observati c˘ de¸i exist˘ o singur˘ clas˘ MouseEvent. eveni¸ a mentele generate de o superclas˘. a a . Evident. pentru ¸ a a fiecare interfat˘. Acest lucru a fost f˘cut s a deoarece evenimentele legate de deplasarea mouse-ului sunt generate foarte frecvent ¸i receptionarea lor poate avea un impact negativ asupra vitezei de s ¸ executie. metodele puse la dispozitie ¸i care trebuie implementate de ¸a s c˘tre clasa ascult˘tor. Tabelul de mai jos prezint˘. exist˘ dou˘ interfete ¸ a s a a a a a ¸ asociate MouseListener ¸i MouseMotionListener.9.

In cazul ˆ care dorim s˘ diferentiem doar tipul componentei surs˘. INTERFATA GRAFICA CU UTILIZATORUL ¸ Interfat˘ ¸a ActionListener AdjustmentListener Metode actionPerformed(ActionEvent e) adjustmentValueChanged(AdjustmentEvent e) componentHidden(ComponentEvent e) ComponentListener componentMoved(ComponentEvent e) componentResized(ComponentEvent e) componentShown(ComponentEvent e) ContainerListener componentAdded(ContainerEvent e) componentRemoved(ContainerEvent e) FocusListener focusGained(FocusEvent e) focusLost(FocusEvent e) ItemListener itemStateChanged(ItemEvent e) keyPressed(KeyEvent e) KeyListener keyReleased(KeyEvent e) keyTyped(KeyEvent e) mouseClicked(MouseEvent e) mouseEntered(MouseEvent e) MouseListener mouseExited(MouseEvent e) mousePressed(MouseEvent e) mouseReleased(MouseEvent e) MouseMotionListener mouseDragged(MouseEvent e) mouseMoved(MouseEvent e) TextListener textValueChanged(TextEvent e) windowActivated(WindowEvent e) windowClosed(WindowEvent e) windowClosing(WindowEvent e) WindowListener windowDeactivated(WindowEvent e) windowDeiconified(WindowEvent e) windowIconified(WindowEvent e) windowOpened(WindowEvent e) In cazul ˆ care un obiect listener trateaz˘ evenimente de acela¸i tip provoın a s cate de componente diferite.226 ˘ CAPITOLUL 9. ın a ¸ a . Toate tipurile de evenimente mo¸tenesc ¸ ın ¸a s metoda getSource care returneaz˘ obiectul responsabil cu generarea evenia mentului. care este sursa evenimentului pe care ˆ trat˘m penıl a tru a putea reactiona ˆ consecint˘. ˆ cadrul uneia din a ın metodele de mai sus. este necesar s˘ putem afla.

if (sursa instanceof Button) { // A fost apasat un buton Button btn = (Button) sursa. returneaz˘ eticheta butonului care a fost ap˘sat. De exemplu.getSource()..4. Astfel de a a particularit˘¸i vor fi prezentate mai detaliat ˆ sectiunile dedicate fiecˆrei at ın ¸ a componente ˆ parte.. chiar a ¸a dac˘ nu specific˘ nici un cod pentru unele dintre ele. a a ¸ Un exemplu sugestiv este urm˘torul: o fereastr˘ care nu are specificat cod a a pentru tratarea evenimentelor sale nu poate fi ˆ ınchis˘ cu butonul standard a . ın 9.. mai ales atunci cˆnd nu ne intereseaz˘ a a a decˆt o singura metod˘ a interfetei. Aceasta ˆ ¸ a ınseamn˘ c˘ trebuie a a s˘ implementeze obligatoriu toate metodele definite de acea interfat˘.. public void actionPerformed(ActionEvent e) { Object sursa = e. } } 227 Pe lˆng˘ getSource. } if (sursa instanceof TextField) { // S-a apasat Enter dupa editarea textului TextField tf = (TextField) sursa. if (tf == nume) { // A fost editata componenta ’nume’ } . TRATAREA EVENIMENTELOR putem folosi operatorul instanceof.3 Folosirea adaptorilor ¸i a claselor anonime s Am vazut c˘ o clas˘ care trateaz˘ evenimente de un anumit tip trebuie s˘ ima a a a plementeze interfata corespunz˘toare acelui tip. Sunt ˆ a situatii cˆnd a a ıns˘ ¸ a acest lucru poate deveni sup˘rator. ActionEvent contine metoda getActionCommand ¸ care. implicit. obiectele ce descriu evenimente pot pune la dispozitie a a ¸ ¸i alte metode specifice care permit aflarea de informatii legate de evenimens ¸ tul generat. if (btn == ok) { // A fost apasat butonul ’ok’ } .4.9.

Listing 9. f . } public void windowClosed ( WindowEvent e ) {} public void windowIconified ( WindowEvent e ) {} public void windowDeiconified ( WindowEvent e ) {} public void windowActivated ( WindowEvent e ) {} public void windowDeact ivated ( WindowEvent e ) {} } public class TestWind ow Lis te ne r { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test WindowListener " ) . import java . exit (0) .exit pentru terminarea programului. addWindowList ener ( this ) .*. chiar dac˘ ¸ a a a ¸ a nu scriem nici un cod pentru unele dintre ele. Aceasta ˆ a ¸ ınseamn˘ c˘ trebuie a a s˘ implement˘m interfata WindowListener care are nu mai putin de ¸apte a a ¸ ¸ s metode. } // Metodele interfetei WindowListener public void windowOpened ( WindowEvent e ) {} public void windowClosing ( WindowEvent e ) { // Terminare program System . INTERFATA GRAFICA CU UTILIZATORUL ¸ marcat cu ’x’ din coltul dreapta sus ¸i nici cu combinatia de taste Alt+F4.*. this . Singura metod˘ care ne interea seaz˘ este windowClosing. event . class Fereastra extends Frame implements WindowListener { public Fereastra ( String titlu ) { super ( titlu ) . Pentru a evita scrierea inutil˘ a a a . } } Observati c˘ trebuie s˘ implement˘m toate metodele interfetei.11: Implementarea interfetei WindowListener ¸ import java .228 ˘ CAPITOLUL 9. awt . show () . ¸ s ¸ Pentru a realiza acest lucru trebuie interceptat evenimentul de ˆ ınchidere a ferestrei ˆ metoda windoClosing ¸i apelat˘ metoda dispose de ˆ ın s a ınchidere a ferestrei. awt . ˆ cazul cˆnd ın a este vorba de fereastra principal˘ a aplicatiei. ˆ care specific˘m ce trebuie f˘cut atunci cˆnd a ın a a a utilizatorul doreste s˘ ˆ a ınchid˘ fereastra. sau System.

import java .12: Extinderea clasei WindowAdapter import java . awt . addWindowListener ( new Ascultator () ) . a a ¸ ¸a . event . } } Avantajul clar al acestei modalit˘¸i de tratare a evenimentelor este reat ducerea codului programului.*. Aceste clase se aa numesc adaptori. awt .*. this . Ins˘ exist˘ ¸i a as dou˘ dezavantaje majore. adaptorul interfetei WindowListener este WindowAdapter ¸ iar folosirea acestuia este dat˘ ˆ exemplul de mai jos: a ın Listing 9. TRATAREA EVENIMENTELOR 229 acestor metode. s˘ extindem adaptorul corespunz˘tor interfetei respective (dac˘ are!) a a ¸ a ¸i s˘ supradefinim doar metodele care ne intereseaz˘ (cele ˆ care vrem s˘ s a a ın a scriem o anumit˘ secvent˘ de cod). f . Dup˘ cum ati observat fat˘de exemplul anterior. class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . aa ¸ Scopul unei astfel de clase este ca la crearea unui ”ascult˘tor” de evenia mente. Un adaptor este o clas˘ abstract˘ care implementeaz˘ o anumit˘ interfat˘ a a a a ¸a f˘r˘ a specifica cod nici unei metode a interfetei.4. a ¸a De exemplu. show () .9. ˆ loc s˘ implement˘ o anumit˘ interfat˘ ¸i implicit toate metodele ın a a a ¸a s sale. } } class Ascultator extends WindowAdapter { // Suprdefinim metodele care ne intereseaza public void windowClosing ( WindowEvent e ) { System . acesta devenind mult mai lizibil. exist˘ o serie de clase care implementeaz˘ interfetele de tip a a ¸ ”listener” f˘r˘ a specifica nici un cod pentru metodele lor. exit (0) . } } public class TestWindowAdapter { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test WindowAdapter " ) .

ısi Interfata ¸ ActionListener AdjustemnrListener ComponentListener ContainerListener FocusListener ItemListener KeyListener MouseListener MouseMotionListener TextListener WindowListener Adaptor nu are nu are ComponentAdapter ContainerAdapter FocusAdapter nu are KeyAdapter MouseAdapter MouseMotionAdapter nu are WindowAdapter Stim c˘ o clas˘ intern˘ este o clas˘ declarat˘ ˆ cadrul altei clase.se oberv˘ c˘ o interfat˘ XXXListener are un adaptor de tipul XXXAdapter.230 ˘ CAPITOLUL 9. a a ¸a Interfetele care nu au un adaptor sunt cele care definesc o singur˘ metod˘ ¸i ¸ a as prin urmare crearea unei clase adaptor nu ˆ are rostul. va crea o metod˘ a clasei respective. ¸ s a class Ascultator extends WindowAdapter { // In loc de windowClosing scriem WindowClosing // Nu supradefinim vreo metoda a clasei WindowAdapter // Nu da nici o eroare // Nu face nimic ! public void WindowClosing(WindowEvent e) { System. Un exemplu tipic de folosire a lor este instantierea ¸ . iar ¸ a a a a a ın clasele anonime sunt clase interne folosite pentru instantierea unui singur ¸ obiect de un anumit tip. } } In tabelul de mai jos sunt dati toti adaptorii interfetelor de tip ”listener” ¸ ¸ ¸ .exit(0). INTERFATA GRAFICA CU UTILIZATORUL ¸ clasa Fereastra nu poate extinde WindowAdapter deoarece ea extinde deja clasa Frame ¸i din acest motiv am construit o nou˘ clas˘ numit˘ Ascultator. Un alt dezavantaj este c˘ orice gre¸eal˘ de sintax˘ ˆ declararea unei metode a s a a ın a interfetei nu va produce o eroare de compilare dar nici nu va supradefini ¸ metoda interfetei ci. s a a a Vom vedea ˆ a c˘ acest dezavantaj poate fi eliminat prin folosirea unei clase ıns˘ a anonime. pur ¸i simplu.

this .*. NORTH ) . awt . label . 400) . getX () . awt . fillOval ( e . Listing 9. blue ) . . 1) . g . class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . int raza = ( int ) ( Math . BorderLayout . addWindowListener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { // Terminam aplicatia System . import java . add ( label . event . this .*.13: Folosirea adaptorilor ¸i a claselor anonime s import java . this . g . getX () . " ) . e . this .. getY () . setText ( " Click . setColor ( Color .ului Graphics g = Fereastra . getGraphics () . Label . g . } }) . setBackground ( Color . yellow ) .9. raza ) . getGraphics () . e . CENTER ) . drawOval ( e . Graphics g = Fereastra . exit (0) . raza . random () * 50) . this . getY () . 1 . addMouseListener ( new MouseAdapter () { public void mouseClicked ( MouseEvent e ) { // Desenam un cerc la fiecare click de mouse label . } }) ..4. ad dM ous eM oti on Li st e n e r ( new Mo us eM ot ion Ad ap te r () { public void mouseMoved ( MouseEvent e ) { // Desenam un punct la coordonatele mouse . setSize (400 . } }) . TRATAREA EVENIMENTELOR 231 adaptorilor direct ˆ corpul unei clase care contine componente ale c˘ror ın ¸ a evenimente trebuie tratate. final Label label = new Label ( " " .

a • hide . show () . setText ( " Ati tastat : " + e .5. una dintre ele fiind numit˘ fereastra principal˘. a ¸ Metodele mai importante ale clasei Window.face vizibil˘ fereastra. f . a a 9. Implicit.5 Folosirea ferestrelor Dup˘ cum am v˘zut suprafetele de afi¸are ale componentelor sunt extensii a a ¸ s ale clasei Container. getKeyChar () + " " ) .232 ˘ CAPITOLUL 9. } } public class TestAdapters { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test adaptori " ) . o fereastr˘ nou creat˘ nu este a a a vizibil˘.face fereastra invizibil˘ f˘r˘ a o distruge ˆ a. sunt date de mai jos: • show . pentru a redeveni a aa ıns˘ vizibila se poate apela metoda show. O categorie aparte a acestor containere o reprezint˘ a ferestrele. . care sunt de altfel mo¸tenite s de toate subclasele sale. } }) . s O aplicatie Java cu intefat˘ grafic˘ va fi format˘ din una sau mai multe ¸ ¸a a a ferestre.1 Clasa Window Clasa Window este rar utilizat˘ ˆ mod direct deoarece permite doar crearea a ın unor ferestre care nu au chenar ¸i nici bar˘ de meniuri. Acestea sunt descrise de clase derivate din Window. } } 9. addKeyListener ( new KeyAdapter () { public void keyTyped ( KeyEvent e ) { // Afisam caracterul tastat label . Este util˘ atunci s a a cˆnd dorim s˘ afi¸am ferestre care nu interactioneaz˘ cu utilizatorul ci doar a a s ¸ a ofer˘ anumite informatii. INTERFATA GRAFICA CU UTILIZATORUL ¸ this . cele mai utilizate fiind Frame ¸i Dialog.

ˆ ınchide) fereastra ¸i ¸i elibereaz˘ toate resursele acesteia..9. f. De obicei.awt. ca ˆ exemplul de mai jos: ın import java. a ¸ • getFocusOwner .returneaz˘ componenta ferestrei care are focus-ul a (dac˘ fereastra este activ˘). Orice aplicatie s ¸ a a ¸ cu interfat˘ grafic˘ conttine cel putin o fereastr˘.awt. eventual continˆnd o bar˘ de meniuri.show(). .. a a 9. } } Crearea ferestrelor prin instantierea direct˘ a obiectelor de tip Frame este ¸ a mai putin folosit˘.testeaz˘ dac˘ fereastra este vizibil˘ sau nu. class Fereastra extends Frame{ // Constructorul public Fereastra(String titlu) { super(titlu). a a a 233 • dispose . cea mai important˘ fiind ¸a a ¸ ¸ a a numit˘ ¸i fereastra principal˘. as a Constructorii uzuali ai clasei Frame permit crearea unei ferestre cu sau f˘r˘ titlu. Pentru ca o fereastr˘ s˘ devin˘ vizibil˘ se va aa ¸ a a a a a apela metoda show definit˘ ˆ superclasa Window. initial invizibil˘. FOLOSIREA FERESTRELOR • isShowing .redimensioneaz˘ automat fereastra la o suprafata optim˘ care a ¸ a s˘ cuprind˘ toate componentele sale. } . ferestrele unui program vor fi definite ˆ clase ¸ a ın separate care extind clasa Frame. a ın import java. s s a • pack .*. public class TestFrame { public static void main(String args[]) { Frame f = new Frame("Titlul ferestrei").*. trebuie apelat˘ ˆ general dup˘ a a a ın a ad˘ugarea tuturor componentelor pe suprafata ferestrei.5.2 Clasa Frame Este derivat˘ a clasei Window ¸i este folosit˘ pentru crearea de ferestre indea s a pendente ¸i functionale.5.

mai uzual. . f. } }) . awt . ˆ momentul ˆ care fereastra este creat˘ dar nici o compoın ın a nent˘ grafic˘ nu este ad˘ugat˘. } } Gestionarul de pozitionare implicit al clasei Frame este BorderLayout.14: Structura general˘ a unei ferestre a import java .*. prin folosirea unui adaptor de tip WindowAdapter. ¸ Tratarea evenimentelor ferestrei se face prin implementarea interfetei WindowListener ¸ sau. event . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { dispose () . // Tratam evenimentul de inchidere a ferestrei this . class Fereastra extends Frame implements ActionListener { // Constructorul public Fereastra ( String titlu ) { super ( titlu ) . INTERFATA GRAFICA CU UTILIZATORUL ¸ } public class TestFrame { public static void main(String args[]) { Fereastra f = new Fereastra("Titlul ferestrei"). awt .234 ˘ CAPITOLUL 9.show(). Acela¸i efect ˆ vom obtine dac˘ o redimenionam ¸i apel˘m apoi s ıl ¸ a s a metoda pack care determin˘ dimeniunea suprafetei de afi¸are ˆ functie de a ¸ s ın ¸ componentele ad˘ugate. exit (0) . // inchidem fereastra // sau terminam aplicatia System . maximizare sa s ¸i ˆ s ınchidere. ¸ Din acest motiv. suprafata de afi¸are a feretrei va fi determia a a a ¸ s nat˘ automota de gestionarul de pozittionare ¸i va oferi doar spatiul necesar a ¸ s ¸ afi¸˘rii barei ferestrei ¸i grupului de butoane pentru minimizare.*. Structura general˘ a unei ferestre este descris˘ de clasa Fereastra din a a exemplul de mai jos: Listing 9. a Se observ˘ de asemenea c˘ butonul de ˆ a a ınchidere a ferestrei nu este functional. import java .

} } public class TestFrame { public static void main ( String args []) { // Cream fereastra Fereastra f = new Fereastra ( " O fereastra " ) .metod˘ static˘ ce returneaz˘ lista tuturor ferestrelor dea a a schise ale unei aplicatii.5. exist˘ o serie de metode a a s a specifice clasei Frame. FOLOSIREA FERESTRELOR // Eventual .seteaz˘ titlul ferestrei. schimbam gestionarul de pozitionare setLayout ( new FlowLayout () ) . // Facem inregistrarea claselor listener exit . addActionListener ( this ) .9. // Stabilim dimensiunile pack () . // implicit // sau explicit // setSize (200 .seteaz˘ iconita ferestrei. ¸ • setIconImage . • setTitle . exit (0) . show () .seteaz˘ bara de meniuri a ferestrei (vezi ”Folosirea mea niurilor”). Dintre cele mai folosite amintim: • getFrames . } } 235 Pe lˆng˘ metodele mo¸tenite din clasa Window. } // Implementam metodele interfetelor de tip listener public void actionPerformed ( ActionEvent e ) { System . 200) . a . a ¸ • setMenuBar . add ( exit ) . // O facem vizibila f . // Adaugam componentele pe suprafata ferestrei Button exit = new Button ( " Exit " ) .

numit˘ ¸i fereastra p˘rinte.236 ˘ CAPITOLUL 9. ferestrele de dialog nu au o existent˘ de sine st˘t˘toare. 9. Constructorii clasei Dialog a s s sunt: Dialog(Frame parinte) Dialog(Frame parinte. a Ferestrele de dialog pot fi de dou˘ tipuri: a • modale: care blocheaz˘ accesul la fereastra parinte ˆ momentul dea ın schiderii lor. ˆ a exist˘ cona as a ıns˘ a structori care s˘ specifice ¸i ace¸ti parametri. de alegere a unui fi¸ier. Cu alte a a as a cuvinte. INTERFATA GRAFICA CU UTILIZATORUL ¸ • setResizable . s ¸ • nemodale: care nu blocheaz˘ fluxul de intrare c˘tre fereastra p˘rinte a a a . String titlu) Dialog(Frame parinte. String titlu) Dialog(Dialog parinte. a a Diferenta major˘ dintre ferestrele de dialog ¸i ferestrele de tip Frame ¸ a s const˘ ˆ faptul c˘ o fereastr˘ de dialog este dependent˘ de o alt˘ fereastra a ın a a a a (normal˘ sau tot fereastr˘ de dialog). de selectare a unei optiuni. subclas˘ direct˘ a clasei Window. mesaje de avertizare. etc.de exemplu. String titlu. o fereastr˘ de dialog este nemodal˘ ¸i invizibil˘.3 Clasa Dialog Toate interfetele grafice ofer˘ un tip special de ferestre destinate prelu˘rii ¸ a a unor informatii sau a unor date de la utilizator.5. String titlu. dialogul de c˘utare a unui cuvˆnt ˆ a a ıntr-un fi¸ier. boolean modala) . etc. boolean modala) Dialog(Dialog parinte) Dialog(Dialog parinte.stabile¸te dac˘ fereastra poate fi redimenionat˘ de utis a a lizator. boolean modala) Dialog(Frame parinte. cum ar fi ferestrele de introducere a unor date. Cˆnd fer¸a aa a eastra p˘rinte este distrus˘ sunt distruse ¸i ferestrele sale de dialog. cˆnd este a a s a minimizat˘ ferestrele sale de dialog sunt f˘cute invizibile iar cˆnd este restaua a a rat˘ acestea sunt aduse la starea ˆ care se g˘seau ˆ momentul minimiz˘rii a ın a ın a ferestrei p˘rinte. s Implicit. Acestea se numesc ferestre ¸ de dialog sau casete de dialog ¸i sunt implementate prin intermediul clasei s Dialog.

*. FOLOSIREA FERESTRELOR 237 Parametrul ”p˘rinte” reprezint˘ referinta la fereastra p˘rinte. awt . // Fereastra principala class FerPrinc extends Frame implements ActionListener { .9. pentru ca aceasta din urm˘ s˘ poat˘ folosi datele introduse (sau a a a a optiunea specificata) ˆ caseta de dialog. Deschiderea ferestrei de dialog se va face la ap˘sarea unui buton al a ferestrei principale numit ”Schimba titlul”. import java . Cele dou˘ ferestre vor ar˘ta ca a a ˆ imaginile de mai jos: ın Fereastra principal˘ a Fereastra de dialog Listing 9. event . iar fereastra de dialog s˘ ofere metode publice prin care a datele introduse s˘ fie preluate din exterior. • obiectul care creeaz˘ dialogul (fereastra p˘rinte) s˘ se ˆ a a a ınregistreze ca ascult˘tor al evenimentelor de la butoanele care determin˘ ˆ a a ıncheierea dialogului.*.valoarea a a a implicit˘). de exemplu. se poate realiza folosind una din ¸ ın urm˘toarele abord˘ri generale: a a • obiectul care reprezint˘ dialogul poate s˘ trateze evenimentele generate a a de componentele de pe suprafata s˘ ¸i s˘ seteze valorile unor variabile ¸ as a accesibile ale ferestrei p˘rinte ˆ momentul ˆ care dialogul este ˆ a ın ın ıncheiat. va primi ¸irul de caractere introdus ¸i ˆ va modifica titlul ca fiind s s ısi acesta. Fereastra principal˘ a aplicatiei va fi p˘rintele casetei s a a de dialog. o fereastr˘ de dialog modal˘ pentru introducerea a a a a unui ¸ir de caractere. awt . a Crearea unei ferestre de dialog este relativ simpla ¸i se realizeaz˘ prin s a derivarea clasei Dialog.15: Folosirea unei ferestre de dialog import java . ”titlu” a a ¸ a reprezint˘ titlul ferestrei iar prin argumentul ”modal˘” specific˘m dac˘ fera a a a eastra de dialog creat˘ va fi modal˘ (true) sau nemodal˘ (false .5. a S˘ cre˘m. Comunicarea dintre fereastra de dialog ¸i fereastra s sa p˘rinte.

setLayout ( new FlowLayout () ) . ok = new Button ( " OK " ) . add ( text . private Button ok . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . cancel . dispose () . boolean modala ) { super ( parinte . exit (0) . String titlu = d . this . private TextField text . } } // Fereastra de dialog class FerDialog extends Dialog implements ActionListener { public String raspuns = null . titlu . String titlu . } public void actionPerformed ( ActionEvent e ) { FerDialog d = new FerDialog ( this . text = new TextField ( " " . } }) . 80) . public FerDialog ( Frame parinte . INTERFATA GRAFICA CU UTILIZATORUL ¸ public FerPrinc ( String titlu ) { super ( titlu ) . Panel panel = new Panel () . . b . Button b = new Button ( " Schimba titlul " ) . true ) . 30) . this . addActionListener ( this ) . } }) . " Dati titlul " . setTitle ( titlu ) . setSize (300 . if ( titlu == null ) return .238 ˘ CAPITOLUL 9. addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { raspuns = null . CENTER ) . raspuns . modala ) . BorderLayout . add ( b ) .

dar forma ˆ care vor fi afi¸ate este specific˘ platformei pe care ın s a ruleaz˘ aplicatia.awt pune la dispozitie ¸i un tip de fereastr˘ de dialog folosit˘ s a a pentru selectarea unui nume de fi¸ier ˆ vederea ˆ arc˘rii sau salv˘rii unui s ın ınc˘ a a fi¸ier: clasa FileDialog. addActionListener ( this ) . add ( cancel ) . panel . show () . ok . BorderLayout . addActionListener ( this ) . text . SOUTH ) . getSource () .9. else raspuns = null . } public void actionPerformed ( ActionEvent e ) { Object sursa = e . } } 239 9. add ( ok ) .5.4 Clasa FileDialog Pachetul java. if ( sursa == ok || sursa == text ) raspuns = text . f .5. a ¸ Constructorii clasei sunt: FileDialog(Frame parinte) . derivat˘ din Dialog. add ( panel . show () . dispose () . Instantele acestei clase au un s a ¸ comportament comun dialogurilor de acest tip de pe majoritatea platformelor de lucru. panel . cancel . addActionListener ( this ) . getText () . pack () . FOLOSIREA FERESTRELOR cancel = new Button ( " Cancel " ) . } } // Clasa principala public class TestDialog { public static void main ( String args []) { FerPrinc f = new FerPrinc ( " Fereastra principala " ) .

S˘ consider˘m un exemplu ˆ care vom alege. La crearea unui obiect FileDialog acesta nu este implicit vizibil.16: Folosirea unei ferestre de dialog import java . "Salvare fisier".SAVE). Directorul initial este directorul s ¸ curent. valorile pe care le poate lua acest argument sunt: a s • FileDialog. caseta de dialog va fi modal˘. Numele fi¸ierului s ales va fi afi¸at la consol˘. INTERFATA GRAFICA CU UTILIZATORUL ¸ FileDialog(Frame parinte.*.*. FileDialog. // Dialog pentru salvarea unui fisier new FileDialog(parinte.LOAD). String titlu. this . FileDialog. iar numele implicit este TestFileDialog. class FerPrinc extends Frame implements ActionListener { public FerPrinc ( String titlu ) { super ( titlu ) . Dac˘ afi¸area s a a s se face cu setVisible(true). io . // Dialog pentru incarcarea unui fisier new FileDialog(parinte. respectiv ınc˘ • FileDialog. Dac˘ a afi¸area sa se face cu show.pentru ˆ arcare. Dup˘ selectarea unui a a fi¸ier ea va fi facut˘ automat invizibil˘. getDirectory. import java . ”titlu” reprezint˘ a a ¸ a a titlul ferestrei iar prin argumentul ”mod” specific˘m dac˘ ˆ arc˘m sau a a ınc˘ a salv˘m un fi¸ier. "Alegere fisier". prin intermediul unui obiect a a ın FileDialog.240 ˘ CAPITOLUL 9. pentru stabilirea unui criteriu de filtrare setFilenameFilter.java. awt . import java .*. String titlu) FileDialog(Frame parinte. s a Listing 9. addWindowList ener ( new WindowAdapter () { .pentru salvare. boolean mod) Parametrul ”p˘rinte” reprezint˘ referinta ferestrei p˘rinte. un fi¸ier cu extensia ”java”. s a a Pe lˆng˘ metodele mo¸tenite de la superclasa Dialog clasa FileDialog a a s mai contine metode pentru obtinerea numelui fi¸ierului sau directorului se¸ ¸ s lectat getFile. etc. atunci va fi nemodal˘. awt .LOAD .SAVE . event .

java " ) . } } Clasa FileDialog este folosit˘ mai rar deoarece ˆ Swing exist˘ clasa a ın a JFileChooser care ofer˘ mai multe facilit˘¸i ¸i prin urmare va constitui a at s prima optiune ˆ ¸ ıntr-o aplicatie cu intefat˘ grafic˘. LOAD ) . // Specificam filtrul fd . f . setFilenameFilter ( new FilenameFilter () { public boolean accept ( File dir . addActionListener ( this ) . String numeFis ) { return ( numeFis . println ( " Fisierul ales este : " + fd . out . // Afisam fereastra de dialog ( modala ) fd . pack () . CENTER ) . } 241 public void actionPerformed ( ActionEvent e ) { FileDialog fd = new FileDialog ( this . endsWith ( " . // Stabilim numele implicit fd . setFile ( " TestFileDialog . BorderLayout . getFile () ) . java " ) ) .5. setDirectory ( " . exit (0) . Button b = new Button ( " Alege fisier " ) . show () .9. b . FileDialog . ¸ ¸a a . } }) . add (b . " ) . System . } }) . FOLOSIREA FERESTRELOR public void windowClosing ( WindowEvent e ) { System . " Alegeti un fisier " . show () . } } public class TestFileDialog { public static void main ( String args []) { FerPrinc f = new FerPrinc ( " Fereastra principala " ) . // Stabilim directorul curent fd .

acestea pot contine obiecte de tip MenuItem. ¸ a a aceste meniuri contin articole ce pot fi selectate. a componentele unui meniu reprezint˘ instante ale unor clase derivate din sua ¸ perclasa abstract˘ MenuComponent. articolul Undo ¸i dou˘ comutatoare Bold ¸i Italic. a at Meniurile pot fi grupate ˆ dou˘ categorii: ın a • Meniuri fixe (vizibile permanent): sunt grupate ˆ ıntr-o bar˘ de meniuri a ce contine cˆte un meniu pentru fiecare intrare a sa.6 Folosirea meniurilor Spre deosebire de celelalte obiecte grafice care deriv˘ din clasa Component. O alt˘ diferent˘ fat˘ de meniurile fixe const˘ ˆ faptul a ¸a ¸a a ın c˘ meniurile de context nu sunt grupate ˆ a ıntr-o bar˘ de meniuri. a In figura de mai jos este pus˘ ˆ evident˘ alc˘tuirea unui meniu fix: a ın ¸a a Exemplul de mai sus contine o bar˘ de meniuri format˘ din dou˘ meniuri ¸ a a a principale File ¸i Edit.242 ˘ CAPITOLUL 9. In modelul AWT obiectele care reprezint˘ bare de meniuri sunt reprezena tate ca instante al clasei MenuBar. Aceast˘ exceptie este facut˘ deoarece a a ¸ a unele platforme grafice limiteaz˘ capabilit˘¸ile unui meniu. comutatoare sau alte ¸ meniuri (submeniuri). CheckBoxMenuItem. vom referi uneori bara de meniuri a unei ferestre ca fiind meniul ferestrei. INTERFATA GRAFICA CU UTILIZATORUL ¸ 9. Meniul Edit contine la rˆndul lui alt meniu (submeniu) s ¸ a Options. care sunt de fapt meniurile derulante propriu-zise. O fereastr˘ poate avea un singur meniu fix. Un obiect de tip MenuBar contine obiecte ¸ ¸ de tip Menu. La rˆndul a lor. Prin abuz de s a s limbaj. La rˆndul lor. ¸ dar ¸i alte obiecte de tip Menu (submeniuri). s . a • Meniuri de context (popup): sunt meniuri invizbile asociate unei ferestre ¸i care se activeaz˘ uzual prin ap˘sarea butonului drept al s a a mouse-ului.

Cel mai adesea. Ata¸area unei bare de meniuri la o fereastr˘ se face prin s a metoda addMenuBar a clasei Frame. adaptˆnd conceptul de bar˘ de meniuri la platforma a a curent˘ de lucru.6. cu sintaxa ¸i semnificatiile uzuale.9. 9. getFont. dintre care amintim getName.6. Dup˘ cum am mai spus. acestea implementˆnd interfat˘ a ¸a MenuContainer. setFont. mai precis obiectelor de tip Frame. meniurile sunt ata¸ate fere¸ s strelor. setName. fiind similar˘ celeilalte a superclase abstracte Component. o component˘ trebuie s˘ implementeze ¸ a a interfata MenuContainer.1 Ierarhia claselor ce descriu meniuri S˘ vedem ˆ continuare care este ierarhia claselor folosite ˆ lucrul cu meniuri a ın ın ¸i s˘ analiz˘m pe rˆnd aceste clase: s a a a Clasa MenuComponent este o clasa abstract˘ din care sunt extinse a toate celelalte clase folosite la crearea de meniuri. pentru a lega bara de meniuri la a a o anumit˘ fereastra trebuie apelat˘ metoda setMenuBar din clasa Frame. a a // Crearea barei de meniuri MenuBar mb = new MenuBar(). s ¸ Clasa MenuBar permite crearea barelor de meniuri asociate unei ferestre cadru de tip Frame. MenuComponent contine metode cu carac¸ ter general. . FOLOSIREA MENIURILOR 243 Pentru a putea contine un meniu.

addMenuBar(mb). O instant˘ a ¸a clasei MenuItem reprezint˘ de fapt un buton sau un comutator.. Fiecare meniu are o etichet˘. Orice articol al unui meniu trebuie s˘ fie o instanta a clasei Menua ¸ Item. a ¸ . la invalidarea sa. etc. cu o anumit˘ a a etichet˘ care va ap˘rea ˆ meniu. ceea ce ˆ ¸ ınseamn˘ c˘ a a poate fi deschis ¸i deplasat cu mouse-ul (dragged) ˆ s ıntr-o alt˘ pozitie decˆt a ¸ a cea original˘ (”rupt” din pozitia sa). ceea ce ˆ a ¸ a ınseamn˘ c˘ pot a a fi instante ale uneia din clasele MenuItem. as a care este de fapt numele s˘u ce va fi afi¸at pe bara de meniuri. ”Exit”. cum sunt ”Open”. a Optional. ambele implementˆnd interfata ItemSelectable. ¸ Clasa CheckboxMenuItem implementeaz˘ ˆ a ıntr-un meniu articole de tip comutator . simbolul grafic respectiv va disp˘rea. INTERFATA GRAFICA CU UTILIZATORUL ¸ // Adaugarea meniurilor derulante la bara de meniuri .244 ˘ CAPITOLUL 9. Acest mecanism este dependent de a ¸ platform˘ ¸i poate fi ignorat pe unele dintre ele. ˆ ¸it˘ eventual de un accelerator (obiect a a ın ınsot a de tip MenuShortcut) ce reprezint˘ combinatia de taste cu care articolul a ¸ poate fi apelat rapid (vezi ”Acceleratori”). Obiectele acestei clase descriu a¸adar optiunile individuale ale mes ¸ niurilor derulante. Clasa Menu permite crearea unui meniu derulant ˆ ıntr-o bar˘ de meniuri. actionarea ara a ¸ ticolului determinˆnd trecerea sa dintr-o stare ˆ alta. Menu sau CheckboxMenuItem. f. // Atasarea barei de meniuri la o fereastra Frame f = new Frame("Fereastra cu meniu").. Clasa a CheckboxMenuItem are aceea¸i functionalitate cu cea a casetelor de validare s ¸ de tip Checkbox. un meniu poate fi declarat ca fiind tear-off.care au dou˘ st˘ri logice (validat/nevalidat). ”Close”. Articolele a s dintr-un meniu trebuie s˘ apartin˘ clasei MenuItem. La validarea unui a ın comutator ˆ dreptul etichetei sale va fi afi¸at un simbol grafic care indic˘ ın s a acest lucru.

f . add ( new MenuItem ( " Cut " ) ) . awt . fisier .9. mb . 100) . add ( new CheckboxMenuItem ( " Bold " ) ) . fisier . add ( new MenuItem ( " Paste " ) ) .17: Crearea unui meniu import java .*. public class TestMenu { public static void main ( String args []) { Frame f = new Frame ( " Test Menu " ) . show () . add ( editare ) . } } . awt . editare . MenuBar mb = new MenuBar () . add ( new MenuItem ( " Undo " ) ) . add ( optiuni ) . mb . editare . optiuni . f . FOLOSIREA MENIURILOR 245 S˘ vedem ˆ continuare cum ar ar˘ta un program care construie¸te un a ın a s meniu ca ˆ figura prezentat˘ anterior: ın a Listing 9. optiuni . add ( new MenuItem ( " Close " ) ) . add ( fisier ) . Menu editare = new Menu ( " Edit " ) . add ( new MenuItem ( " Open " ) ) .*. editare . addSeparator () . fisier .6. editare . setMenuBar ( mb ) . editare . addSeparator () . optiuni . setSize (200 . event . f . Menu optiuni = new Menu ( " Options " ) . import java . fisier . Menu fisier = new Menu ( " File " ) . add ( new MenuItem ( " Copy " ) ) . add ( new MenuItem ( " Exit " ) ) . add ( new CheckboxMenuItem ( " Italic " ) ) .

event .6. INTERFATA GRAFICA CU UTILIZATORUL ¸ 9. ceea ce face posibil ca unui buton de pe a suprafata de afi¸are s˘ ˆ corespund˘ o optiune dintr-un meniu. fie ItemEvent a pentru comutatoarele CheckboxMenuItem. a a ın a ˆ ıntocmai ca pe orice component˘. MenuBar mb = new MenuBar () . Tipul de operatie selectare / deselectare s a a este codificat ˆ evenimentul generat de cˆmpurile statice ItemEvent. a respectiv addItemListener. Fiec˘rui meniu ˆ putem asocia un obiect receptor a ıi diferit. f˘cˆndu-se o singur˘ dat˘ ˆ ¸ a a a a ıntr-o clas˘ care este ˆ a ınregistrat˘ a ca receptor atˆt la buton cˆt ¸i la meniu. tratarea evenimentului corespunz˘tor ap˘sarii butonului.2 Tratarea evenimentelor generate de meniuri La alegerea unei optiuni dintr-un meniu se genereaz˘ fie un eveniment de tip ¸ a ActionEvent dac˘ articolul respectiv este de tip MenuItem. CheckboxMenuItem check = new CheckboxMenuItem ( " Check me " ) . Menu test = new Menu ( " Test " ) . A¸adar. awt . awt . sau s a a alegerii optiunii.*. ambele cu ¸ s a ıi a ¸ acela¸i nume. ceea ce u¸ureaz˘ munca ˆ cazul ˆ care ierarhia de meniuri este coms a ın ın plex˘. Choice. A¸adar.*. . public class TestMenuEvent extends Frame implements ActionListener . respec¸ s tiv itemStatChanged. pentru a activa optiunile s ¸ unui meniu trebuie implementate interfatele ActionListener sau/¸i Item¸ s Listener ˆ cadrul obiectelor care trebuie s˘ specifice codul ce va fi executat ın a la alegerea unei optiuni ¸i implementate metodele actionPerformed. CheckBox. import java . s Listing 9.18: Tratarea evenimentelor unui meniu import java .SELECTED ın a ¸i ItemEvent. toate implementˆnd interfata ItemSelectable a ¸ ¸i deci tratarea lor va fi f˘cut˘ la fel. folosind metodele addActionListener.DESELECTED. tratarea evenimentelor generate de obiecte de tip MenuItem este s identic˘ cu tratarea butoanelor. ItemListener { public TestMenuEvent ( String titlu ) { super ( titlu ) . Pentru a realiza leg˘tura ˆ a a ıntre obiectul meniu ¸i obiectul de tip listener s trebuie s˘ adaug˘m receptorul ˆ lista de ascult˘tori a meniului respectiv.246 ˘ CAPITOLUL 9. a a s Obiectele de tip CheckboxMenuItem tip se g˘sesc ˆ a ıntr-o categorie comun˘ a cu List.

add ( test ) . test . check . exit (0) . addActionListener ( this ) .3 Meniuri de context (popup) Au fost introduse ˆ ıncepˆnd cu AWT 1. fiind a . getActionCommand () . setSize (300 . subclas˘ direct˘ a clasei Menu. btnExit . test . Sunt meniuri invizibile a a care sunt activate uzual prin ap˘sarea butonului drept al mouse-ului. if ( command . add ( check ) . FOLOSIREA MENIURILOR test .6. add ( new MenuItem ( " Exit " ) ) . BorderLayout .6. mb . addItemListener ( this ) . show () . 200) . f . } public void itemStateChanged ( ItemEvent e ) { if ( e . addActionListener ( this ) . test . } public void actionPerformed ( ActionEvent e ) { // Valabila si pentru meniu si pentru buton String command = e . Button btnExit = new Button ( " Exit " ) . addSeparator () . setMenuBar ( mb ) . } } 247 9.1 ¸i sunt implementate prin intermediul a s clasei PopupMenu. show () . SOUTH ) .9. } public static void main ( String args []) { TestMenuEvent f = new TestMenuEvent ( " Tratare evenimente meniuri " ) . else setTitle ( " Not checked ! " ) . getStateChange () == ItemEvent . equals ( " Exit " ) ) System . add ( btnExit . SELECTED ) setTitle ( " Checked ! " ) .

remove(popup1). int y) ¸i este de obicei rezultatul ap˘sarii unui buton al mouse-ului. vom ”rupe” leg˘tura ˆ a ıntre fereastr˘ ¸i meniu prin as instructiunea remove: ¸ fereastra. la un moment a a s dat.add(new MenuItem("Exit")). a ¸ s reprezint˘ instanta ferestrei ˆ care se va afi¸a meniul.add(new MenuItem("New")). Metodele de ad˘ugare a articolelor unui meniu de context sunt a a mo¸tenite ˆ s ıntocmai de la meniurile fixe.add(popup2). popup. De obicei. a a a ıl Dup˘ ˆ a ınchiderea acestuia.show(Component origine. vom crea un meniu de contex pe care ˆ vom activa ıl la ap˘sarea butonului drept al mouse-ului pe suprafata ferestrei principale. Deoarece interactiunea a ¸ ın s ¸ cu mouse-ul este dependent˘ de platforma de lucru. vom ad˘uga ferestrei meniul corespunz˘tor dup˘ care ˆ vom face vizibil.addSeparator(). In cazul cˆnd avem mai multe meniuri popup pe care vrem s˘ a a le folosim ˆ ıntr-o fereastr˘. INTERFATA GRAFICA CU UTILIZATORUL ¸ afi¸ate la pozitia la care se g˘sea mouse-ul ˆ momentul ap˘s˘rii butonului s ¸ a ın aa s˘u drept. Meniurile de context nu se adaug˘ la un alt meniu (bar˘ sau sub-meniu) a a ci se ata¸eaz˘ la o component˘ (de obicei la o fereastr˘) prin metoda add s a a a a acesteia. Aceasta este isPopupTrigger ¸i este s definit˘ ˆ clasa MouseEvent. In exemplul de mai jos. popup. . fereastra.248 ˘ CAPITOLUL 9.add(popup1). Argumentul ”origine” reprezint˘ componenta fat˘ de a ¸a originile c˘reia se va calcula pozitia de afi¸are a meniului popup. Afi¸area meniului de context se face prin metoda show: s popup..add(new MenuItem("Edit")). Pozitionarea ¸i afi¸area meniului este ˆ a a ın ¸ s s ıns˘ responsabilitatea programatorului. popup. a ¸ Tratarea evenimentelor generate de un meniu popup se realizeaz˘ identic ca a pentru meniurile fixe. exist˘ o metod˘ care a a a determin˘ dac˘ un eveniment de tip MouseEvent poate fi responsabil cu a a deschiderea unui meniu de context.. trebuie s˘ le definim pe toate ¸i. popup. int x. fereastra. pentru a avea s a acces rapid la meniu. . PopupMenu popup = new PopupMenu("Options").

FOLOSIREA MENIURILOR Listing 9. e . awt . } public void mouseReleased ( MouseEvent e ) { if ( e . popup . equals ( " Exit " ) ) System . } }) . // atasam meniul popup ferestrei popup . setSize (300 . popup . if ( command . public Fereastra ( String titlu ) { super ( titlu ) . event . import java . show ( origin . e . } public void actionPerformed ( ActionEvent e ) { String command = e . addActionListener ( this ) . e . show ( origin . addWindowListener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . 249 .*.9.6.19: Folosirea unui meniu de context (popup) import java . popup . popup . getY () ) . // Cream meniul popup popup = new PopupMenu ( " Options " ) . add ( new MenuItem ( " Edit " ) ) . 300) . exit (0) . e . getX () . this . exit (0) . getY () ) . add ( popup ) . } }) . awt . getX () . addSeparator () . getActionCommand () . addMouseListener ( new MouseAdapter () { public void mousePressed ( MouseEvent e ) { if ( e . class Fereastra extends Frame implements ActionListener { // Definim meniul popup al ferestrei private PopupMenu popup . this . add ( new MenuItem ( " Exit " ) ) . add ( new MenuItem ( " New " ) ) . origin = this . // Pozitia meniului va fi relativa la fereastra private Component origin . isPopupTrigger () ) popup . isPopupTrigger () ) popup .*.

4 Acceleratori (Clasa MenuShortcut) Pentru articolele unui menu este posibil˘ specificarea unor combinatii de a ¸ taste numite acceleratori (shortcuts) care s˘ permit˘ accesarea direct˘. prin a a a intermediul tastaturii. INTERFATA GRAFICA CU UTILIZATORUL ¸ public class TestPopupMenu { public static void main ( String args []) { Fereastra f = new Fereastra ( " PopupMenu " ) .250 } } ˘ CAPITOLUL 9. ca ˆ exemplele ın de mai jos: // Ctrl+O new MenuItem("Open". new MenuShortcut(’p’). oric˘rui obiect ¸ a de tip MenuItem ˆ poate fi asociat un obiect de tip accelerator. Atribuirea unui accelerator la un articol al unui meniu poate fi realizat˘ prin a constructorul obiectelor de tip MenuItem ˆ forma: ın MenuItem(String eticheta. MenuShortcut accelerator). true). ˆ care ın s˘ fie puse ˆ evidentt˘ cˆt mai multe din particularit˘¸ile acestora.7 Folosirea componentelor AWT In continuare vor fi date exemple de folosire ale componentelor AWT. s . definit prin ıi intermediul clasei MenuShortcut. show () . new MenuShortcut(’p’)).VK_O)). Astfel.6. // Ctrl+Shift+P new MenuItem("Preview". f . a optiunilor dintr-un meniu. } } 9. // Ctrl+P new MenuItem("Print". new MenuShortcut(KeyEvent. precum a ın ¸a a at ¸i modul de tratare a evenimentelor generate. Singurele combinatii de taste care pot ¸ juca rolul acceleratorilor sunt: Ctrl + Tasta sau Ctrl + Shift + Tasta. 9.

vest . yellow ) . vest = new Label ( " Vest " . CENTER ) . BorderLayout . f . Listing 9. O etichet˘ este format˘ dintr-o singur˘ ¸ s a a a linie de text static ce nu poate fi modificat de c˘tre utilizator.1 Clasa Label Un obiect de tip Label (etichet˘) reprezint˘ o component˘ pentru plasarea a a a unui text pe o suprafata de afi¸are. BorderLayout . nord . WEST ) . setBackground ( Color . Label . f . RIGHT ) . add ( sud . NORTH ) . add ( est . Label . Font . CENTER ) . add ( nord . BorderLayout . setFont ( new Font ( " Dialog " . ITALIC .*.20: Folosirea clasei Label import java . centru . CENTER ) . Label . awt . 20) ) . est = new Label ( " Est " . est . Font . add ( vest . sud . f . Font . vest . Label . EAST ) . setForeground ( Color . centru . setFont ( new Font ( " Arial " . . nord = new Label ( " Nord " . setForeground ( Color . sud . Label .7. public class TestLabel { public static void main ( String args []) { Frame f = new Frame ( " Label " ) . centru . BorderLayout .9. setFont ( new Font ( " Dialog " . sud = new Label ( " Sud " . 14) ) . centru = new Label ( " Centru " . f . dar poate fi a modificat din program. ITALIC . FOLOSIREA COMPONENTELOR AWT 251 9. blue ) . LEFT ) . red ) . 14) ) . BOLD . SOUTH ) .7. Label nord . est .

event .*. 120) . import java . add ( centru .2 Clasa Button Un obiect de tip Button reprezint˘ o component˘ pentru plasarea unui bua a ton etichetat pe o suprafata de afi¸are. f . b1 . 14) ) . Font . CENTER ) . INTERFATA GRAFICA CU UTILIZATORUL ¸ f . BOLD . Button b1 = new Button ( " OK " ) .21: Folosirea clasei Button import java . exit (0) . pack () . setSize (200 . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . class Fereastra extends Frame implements ActionListener { public Fereastra ( String titlu ) { super ( titlu ) . setLayout ( null ) . a Listing 9. . 50 . show () . b1 . setFont ( new Font ( " Arial " . } }) .*. this .252 ˘ CAPITOLUL 9. 70) . awt . Textul etichetei este format dintr-o ¸ s singur˘ linie. setBounds (30 . BorderLayout . awt . 30 .7. f . } } 9.

println ( e ) . b1 . equals ( " Cancel " ) ) setTitle ( " Anulare ! " ) . setForeground ( Color . getActionCommand () . FOLOSIREA COMPONENTELOR AWT b1 . 50) . setBackground ( Color .7. 30 . b2 . else if ( command .7. Button b2 = new Button ( " Cancel " ) . Este folosit pentru a prelua o anumit˘ optiune de a ın a a ¸ la utilizator. if ( command . out .9. add ( b1 ) . } } public class TestButton { public static void main ( String args []) { Fereastra f = new Fereastra ( " Button " ) . System . b2 . addActionListener ( this ) . add ( b2 ) . orange ) . . equals ( " OK " ) ) setTitle ( " Confirmare ! " ) . f . show () . setBounds (100 . Actiunea a ın a a a a ¸ utilizatorului asupra unui comutator ˆ trece pe acesta ˆ starea complemenıl ın tar˘ celei ˆ care se g˘sea. } } 253 9.3 Clasa Checkbox Un obiect de tip Checkbox (comutator) reprezint˘ o component˘ care se a a poate g˘si ˆ dou˘ st˘ri: ”selectat˘” sau ”neselectat˘” (on/off). blue ) . addActionListener ( this ) . 70 . b2 . } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e ) { String command = e .

22: Folosirea clasei Checkbox import java . INTERFATA GRAFICA CU UTILIZATORUL ¸ Listing 9. awt . exit (0) .254 ˘ CAPITOLUL 9. addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . add ( label1 ) . public Fereastra ( String titlu ) { super ( titlu ) . 1) ) . private Checkbox cbx1 . import java . add ( label2 ) .*. label1 .*. lightGray ) . Label . cbx1 = new Checkbox ( " cascaval " ) . setBackground ( Color . label2 = new Label ( " " ) . event . cbx2 = new Checkbox ( " sunca " ) . orange ) . add ( cbx1 ) . setLayout ( new GridLayout (5 . setBackground ( Color . class Fereastra extends Frame implements ItemListener { private Label label1 . this . CENTER ) . . add ( cbx2 ) . cbx3 . cbx3 = new Checkbox ( " ardei " ) . label2 . add ( cbx3 ) . } }) . awt . label1 = new Label ( " Ingrediente Pizza : " . cbx2 . label2 .

} // Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e ) { StringBuffer ingrediente = new StringBuffer () .7. toString () ) . if ( cbx1 . aceste componente se mai numesc butoane radio. Uzual. append ( " ardei " ) . cbx2 . getState () == true ) ingrediente . } } public class TestCheckbox { public static void main ( String args []) { Fereastra f = new Fereastra ( " Checkbox " ) . if ( cbx3 .7. } } 9. FOLOSIREA COMPONENTELOR AWT 255 setSize (200 . cbx3 . 200) . f . append ( " cascaval " ) . Aceast˘ clas˘ nu este derivat˘ din Component. cbx1 .4 Clasa CheckboxGroup Un obiect de tip CheckboxGroup define¸te un grup de comutatoare din care s doar unul poate fi selectat. addItemListener ( this ) . addItemListener ( this ) . addItemListener ( this ) . getState () == true ) ingrediente . getState () == true ) ingrediente . show () . label2 .9. setText ( ingrediente . append ( " sunca " ) . . if ( cbx2 . oferind doar o a a a modalitate de grupare a componentelor de tip Checkbox.

*. setBackground ( Color .256 ˘ CAPITOLUL 9. false ) . cbx1 = new Checkbox ( " HBO " . label1 .23: Folosirea clasei CheckboxGroup import java . label2 . label2 = new Label ( " " . label2 . cbx3 . CENTER ) . CENTER ) . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . cbg . exit (0) . cbx2 = new Checkbox ( " Discovery " . Label . awt . cbx3 = new Checkbox ( " MTV " . . lightGray ) . private CheckboxGroup cbg . orange ) . setLayout ( new GridLayout (5 . label1 = new Label ( " Alegeti postul TV " . public Fereastra ( String titlu ) { super ( titlu ) . cbg . setBackground ( Color .*. 1) ) . false ) . Label . cbg . class Fereastra extends Frame implements ItemListener { private Label label1 . cbg = new CheckboxGroup () . event . awt . import java . INTERFATA GRAFICA CU UTILIZATORUL ¸ Listing 9. false ) . add ( cbx1 ) . this . } }) . add ( label1 ) . private Checkbox cbx1 . cbx2 . add ( label2 ) .

5 Clasa Choice Un obiect de tip Choice define¸te o list˘ de optiuni din care utilizatorul s a ¸ poate selecta una singur˘. setSize (200 . cea selectat˘ ˆ momentul curent.7. f . din ˆ a ıntreaga list˘ doar o sina gur˘ optiune este vizibil˘. 200) . a a ¸ . } // Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e ) { Checkbox cbx = cbg . add ( cbx3 ) . setText ( cbx . cbx1 . } } 257 9. La un moment dat. } } public class TestCheckboxGroup { public static void main ( String args []) { Fereastra f = new Fereastra ( " CheckboxGroup " ) . getLabel () ) . addItemListener ( this ) .7. addItemListener ( this ) . O component˘ a ¸ a a ın a Choice este ˆ ¸it˘ de un buton etichetat cu o sageat˘ vertical˘ la ap˘sarea ınsot a a a a c˘ruia este afi¸at˘ ˆ a s a ıntreaga sa list˘ de elemente. addItemListener ( this ) . pentru ca utilizatorul s˘ a a poat˘ selecta o anumit˘ optiune. getS e lec ted Che ck box () . if ( cbx != null ) label2 .9. FOLOSIREA COMPONENTELOR AWT add ( cbx2 ) . show () . cbx3 . cbx2 .

add ( label ) . culori . add ( " Rosu " ) . case 2: label . event . break . setBackground ( Color . culori = new Choice () . 1) ) . awt . } // Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e ) { switch ( culori . culori . setLayout ( new GridLayout (4 . blue ) . } }) . getSelectedIndex () ) { case 0: label . . setSize (200 . culori . add ( culori ) . culori . public Fereastra ( String titlu ) { super ( titlu ) . green ) . setBackground ( Color .*. label = new Label ( " Alegeti culoarea " ) . class Fereastra extends Frame implements ItemListener { private Label label . add ( " Albastru " ) . private Choice culori . 100) . red ) .24: Folosirea clasei Choice import java . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . red ) . label .258 ˘ CAPITOLUL 9. exit (0) . import java . awt . culori . setBackground ( Color . add ( " Verde " ) . setBackground ( Color . addItemListener ( this ) .*. break . INTERFATA GRAFICA CU UTILIZATORUL ¸ Listing 9. this . case 1: label . select ( " Rosu " ) .

private List culori .25: Folosirea clasei List import java .*.7. awt . class Fereastra extends Frame implements ItemListener { private Label label . } } 259 9. public Fereastra ( String titlu ) { super ( titlu ) . f .6 Clasa List Un obiect de tip List define¸te o list˘ de optiuni care poate fi setat˘ astfel s a ¸ a ˆ at utilizatorul s˘ poat˘ selecta o singur˘ optiune sau mai multe. this .*. import java . FOLOSIREA COMPONENTELOR AWT } } } public class TestChoice { public static void main ( String args []) { Fereastra f = new Fereastra ( " Choice " ) . show () . addWindowListener ( new WindowAdapter () { . awt . Toate ıncˆ a a a ¸ elementele listei sunt vizibile ˆ limita dimensiunilor grafice ale componentei. event .9.7. ın Listing 9.

addItemListener ( this ) .260 ˘ CAPITOLUL 9. add ( " Rosu " ) . add ( culori ) . } } } public class TestList { public static void main ( String args []) { Fereastra f = new Fereastra ( " List " ) . add ( label ) . label . red ) . setBackground ( Color . select (3) . culori = new List (3) . culori . label = new Label ( " Alegeti culoarea " . INTERFATA GRAFICA CU UTILIZATORUL ¸ public void windowClosing ( WindowEvent e ) { System . setBackground ( Color . culori . show () . } }) . 200) . Label . getSelectedIndex () ) { case 0: label . setBackground ( Color . add ( " Albastru " ) . setBackground ( Color . case 1: label . } // Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e ) { switch ( culori . break . culori . culori . setLayout ( new GridLayout (2 . add ( " Verde " ) . break . exit (0) . CENTER ) . 1) ) . case 2: label . f . red ) . } } . blue ) . green ) . setSize (200 . culori .

public Fereastra ( String titlu ) { super ( titlu ) . scroll = new Scrollbar ( Scrollbar .*. setSize (200 .9. 0 .*. addWindowListener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System .7 Clasa ScrollBar Un obiect de tip Scrollbar define¸te o bar˘ de defilare pe vertical˘ sau s a a orizontal˘. awt . CENTER ) . this .26: Folosirea clasei ScrollBar import java . } // Metoda interfetei Adju st me ntL is te ne r . FOLOSIREA COMPONENTELOR AWT 261 9. HORIZONTAL . 101) . at a Listing 9. valoare . add ( scroll ) . valoare = new Label ( " " . 0 . import java . class Fereastra extends Frame implements Ad ju st me nt Lis te ne r { private Scrollbar scroll . awt . setBackground ( Color . event . lightGray ) . 80) . private Label valoare . add ( valoare ) .7. } }) . 1 . 1) ) . setLayout ( new GridLayout (2 . exit (0) . Label .7. add Adjus tmen tLis t e n e r ( this ) . Este util˘ pentru punerea la dispozitia utilizatorului a unei a a ¸ modalit˘¸i sugestive de a alege o anumit˘ valoare dintr-un interval. scroll .

*. a Listing 9. setText ( scroll . awt . } } 9. } } public class TestScrollbar { public static void main ( String args []) { Fereastra f = new Fereastra ( " Scrollbar " ) .262 ˘ CAPITOLUL 9. Acest lucru este util as a a pentru acele componente care nu au implementat˘ functionalitatea de defia ¸ lare automat˘. cum ar fi listele (obiecte din clasa List). private List list . event . import java . getValue () + " % " ) . show () .7. . public Fereastra ( String titlu ) { super ( titlu ) . exit (0) . class Fereastra extends Frame { private ScrollPane sp .27: Folosirea clasei ScrollPane import java . f . awt . this . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . INTERFATA GRAFICA CU UTILIZATORUL ¸ public void ad ju st m e n t V a lu eC ha n g e d ( AdjustmentEvent e ) { valoare .8 Clasa ScrollPane Un obiect de tip ScrollPane permite ata¸area unor bare de defilare (oris zontal˘ ¸si/sau vertical˘) oric˘rei componente grafice.*.

CENTER ) . list . list . Este util pentru interogarea utilizatorului asupra unor valori. a . list . } } public class TestScrollPane { public static void main ( String args []) { Fereastra f = new Fereastra ( " ScrollPane " ) . list .7.9 Clasa TextField Un obiect de tip TextField define¸te un control de editare a textului pe o s singur˘ linie. list . BorderLayout . add ( " Joi " ) . list . show () . add ( list ) . add ( " Miercuri " ) . 200) . add ( " Sambata " ) . add ( " Marti " ) . add ( " Duminica " ) . add ( " Luni " ) . SC ROLLBAR S_ALWAY S ) . select (1) . add ( " Vineri " ) . sp = new ScrollPane ( ScrollPane . FOLOSIREA COMPONENTELOR AWT } }) . f . list . } } 263 9. setSize (200 . list .9. sp . list = new List (7) .7. add ( sp .

add ( parola ) . this . setLayout ( new FlowLayout ( FlowLayout . 100) . lightGray ) . parola . } }) . parola = new TextField ( " " . p1 . 1) ) . class Fereastra extends Frame implements TextListener { private TextField nume . parola . add ( nume ) . Panel p2 = new Panel () .28: Folosirea clasei TextField import java . private Label acces . LEFT ) ) . setSize (350 . setBackground ( Color . p1 . 30) . CENTER ) . add ( new Label ( " Nume : " ) ) . INTERFATA GRAFICA CU UTILIZATORUL ¸ Listing 9. p2 . LEFT ) ) . exit (0) . Panel p1 = new Panel () . p2 . event . acces = new Label ( " Introduceti numele si parola ! " . setLayout ( new GridLayout (3 . add ( p2 ) . private static final String UID = " Duke " . setLayout ( new FlowLayout ( FlowLayout . add ( p1 ) .*.264 ˘ CAPITOLUL 9. addTextListener ( this ) . parola . PWD = " java " . addTextListener ( this ) . } . add ( acces ) . Label . p1 . p2 . nume = new TextField ( " " . awt . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . awt . nume . public Fereastra ( String titlu ) { super ( titlu ) . import java . 10) . setEchoChar ( ’* ’) . add ( new Label ( " Parola : " ) ) .*.

setText ( " Acces permis ! " ) . } if ( nume .7. equals ( PWD ) ) acces . Listing 9. getText () . FOLOSIREA COMPONENTELOR AWT 265 // Metoda interfetei TextListener public void textValueChanged ( TextEvent e ) { if ( nume . getText () . length () == 0) { acces . length () == 0 || parola . awt . f . getText () . . equals ( UID ) && parola . show () . return . getText () .9. etc . introducerea unor comentarii. } } 9.*. } } public class TestTextField { public static void main ( String args []) { Fereastra f = new Fereastra ( " TextField " ) . setText ( " " ) . setText ( " Acces interzis ! " ) .7. else acces . Este util pentru editarea de texte.29: Folosirea clasei TextArea import java .10 Clasa TextArea Un obiect de tip TextArea define¸te un control de editare a textului pe mai s multe linii.

this . } }) . 200) . NORTH ) . salvare . . getText () . text . fisier . Panel fisier = new Panel () . io . add ( fisier . add ( salvare . salvare . 12) . lightGray ) . BorderLayout . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . setEnabled ( false ) . else salvare .*. exit (0) . setBackground ( Color . public Fereastra ( String titlu ) { super ( titlu ) . private Button salvare . setSize (300 . fisier . TextArea . add ( nume ) . add ( text . event . length () == 0 || nume . nume = new TextField ( " " . BorderLayout . addTextListener ( this ) . ActionListener { private TextArea text . setEnabled ( true ) . BorderLayout .266 ˘ CAPITOLUL 9. class Fereastra extends Frame implements TextListener . import java . text = new TextArea ( " " . awt . getText () . CENTER ) . } // Metoda interfetei TextListener public void textValueChanged ( TextEvent e ) { if ( text . 30 .*. salvare = new Button ( " Salveaza text " ) . private TextField nume . SOUTH ) . length () == 0) salvare . setEnabled ( false ) . addActionLi stener ( this ) . INTERFATA GRAFICA CU UTILIZATORUL ¸ import java . add ( new Label ( " Fisier : " ) ) . 10 . S C RO L L BA R S _ VE R T I C A L _ O N L Y ) .

print ( continut ) . getText () . printStackTrace () . out . getText () ) ) . FOLOSIREA COMPONENTELOR AWT } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e ) { String continut = text . } } } public class TestTextArea { public static void main ( String args []) { Fereastra f = new Fereastra ( " TextArea " ) . try { PrintWriter out = new PrintWriter ( new FileWriter ( nume . text . close () . requestFocus () .7. out . show () .9. } catch ( IOException ex ) { ex . } } 267 . f .

268 ˘ CAPITOLUL 9. INTERFATA GRAFICA CU UTILIZATORUL ¸ .

redimensionare a suprafetei de ¸ ¸ afi¸are.Actualizeaz˘ starea grafic˘ a unei coma a ponente. s a • void update(Graphics g) . Actiunea acestei metode se realizeaz˘ ˆ trei pa¸i: ¸ a ın s 1. s 269 .Capitolul 10 Desenarea 10.1 Conceptul de desenare Un program Java care are interfat˘ grafic˘ cu utilizatorul trebuie s˘ deseneze ¸a a a pe ecran toate componentele sale care au o reprezentare vizual˘. Desenarea componentelor se face automat ¸i a s este un proces care se execut˘ ˆ urm˘toarele situatii: a ın a ¸ • la afi¸area pentru prima dat˘ a unei componente. s a • la operatii de minimizare. Metoda este apelat˘ de fiecare dat˘ cˆnd continutul a a a a a ¸ componentei trebuie desenat sau redesenat ¸i nu va fi apelat˘ explicit.Deseneaz˘ o component˘. maximizare. a a Metodele care controleaz˘ procesul de desenare se g˘sesc ˆ clasa Component a a ın ¸i sunt urm˘toarele: s a • void paint(Graphics g) . ¸terge componenta prin supradesenarea ei cu culoarea fundalului. Este o metod˘ a a a supradefinit˘ de fiecare component˘ ˆ parte pentru a furniza reprezentarea a a ın sa grafic˘ specific˘. Aceast˘ a a desenare include componentele standard folosite ˆ aplicatie precum ¸i cele ın ¸ s definite de c˘tre programator. s • ca r˘spuns al unei solicit˘ri explicite a programului.

270 CAPITOLUL 10. avˆnd ˆ a grij˘ s˘ apel˘m ¸i s a ıns˘ a a a s metoda superclasei care se ocup˘ cu desenarea efectiv˘ a componentei. Exist˘ posibilitatea de a desena ¸i ˆ afara metodei paint. orice obiect grafic care dore¸te s˘ se deseneze trebuie s˘ o suprades a a fineasc˘ pentru a-¸i crea propria sa reprezentare. s 3. stabile¸te culoarea (foreground) a componentei.1 Metoda paint Dup˘ cum am spus.clasa a Graphics”). ¸ redimensionare a suprafetei de afi¸are. ˆ general apelat˘ automat sau a ın ın a explicit cu metoda repaint ori de cˆte ori componenta respectiv˘ trebuie a a redesenat˘. Acesta reprezint˘ contextul grafic ˆ care se a ın execut˘ desenarea componentelor (vezi ”Contextul grafic de desenare . Metoda paint este s a ın definit˘ ˆ superclasa Component ˆ a nu are nici o implementare ¸i. din acest a ın ıns˘ s motiv. a • void repaint() . redefinim metoda paint pentru un obiect de tip Frame. Atentie ¸ Toate desenele care trebuie s˘ apar˘ pe o suprafata de desenare se reala a ¸ izeaz˘ ˆ metoda paint a unei componente. a ın ¸ a s . singurul argument al metodelor paint ¸i update a a s este un obiect de tip Graphics. apeleaz˘ metoda paint pentru a redesena componenta. toate desenele care trebuie s˘ apar˘ pe o suprafat˘ de a a a ¸a afi¸are se realizeaz˘ ˆ metoda paint a unei componente. DESENAREA 2. ˆ a putem modifica reprezentarea lor grafic˘ prin crearea ıns˘ a unei subclase ¸i supradefinirea metodei paint. pentru a crea o clas˘ ce instantiaz˘ ferestre pentru o aplicatie a ¸ a ¸ demonstrativ˘ (ˆ coltul stˆnga sus este afi¸at textul ”Aplicatie DEMO”).1. a Dup˘ cum se observ˘. Componentele standard a s AWT au deja supradefinit˘ aceast˘ metod˘ deci nu trebuie s˘ ne preocupe a a a a desenarea lor. a a In exemplul de mai jos. maximizare.Execut˘ explicit un apel al metodei update pentru a a actualiza reprezentarea grafic˘ a unei componente. ˆ a a a s ın ıns˘ aceste desene se vor pierde la prima operatie de minimizare. ¸ s 10.

Dac˘ desenarea acestui text ar fi fost facut˘ oriunde ˆ alt˘ a a ın a parte decˆt ˆ metoda paint. s respectiv desenarea a diferite forme grafice direct pe suprafata unei compo¸ nente. f .clasa Canvas ¸ In afara posibilit˘¸ii de a utiliza componente grafice standard. De¸i este posibil. al c˘rei scop este de a fi extins˘ pentru a implementa a a a a . setSize (200 . g . ˆ general nu se deseneaz˘ la nivel de pixel direct s ın a pe suprafata ferestrelor sau a altor containere. CONCEPTUL DE DESENARE Listing 10. 11) ) . la prima redimensionare a ferestrei acesta s-ar a ın pierde. 100) . } } 271 Observati c˘ la orice redimensionare a ferestrei textul ”Aplicatie DEMO” ¸ a va fi redesenat. In AWT a fost definit un tip special de component˘ numit˘ Canvas a a (pˆnz˘ de pictor). } public void paint ( Graphics g ) { // Apelam metoda paint a clasei Frame super . show () .1. ci vor fi folosite clase dedicate ¸ acestui scop. g .1. A¸adar.1: Supradefinirea metodei paint import java .2 Suprafete de desenare . awt . class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . paint ( g ) .*. setFont ( new Font ( " Arial " . 5 . red ) . BOLD . Java ofer˘ at a ¸i posibilitatea controlului la nivel de punct (pixel) pe dispozitivul grafic. } } public class TestPaint { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test paint " ) . drawString ( " Aplicatie DEMO " . desenarea ˆ Java trebuie s˘ se fac˘ doar ˆ cadrul metodelor s ın a a ın paint ale componentelor grafice.10. Font . g . 10. setColor ( Color . 35) .

adic˘ o subclas˘ a lui Canvas. este recomandat ca o plan¸a s˘ redefineasca metoda getPreferredSize. Canvas este o clas˘ generic˘ a ınf˘t s s a a din care se deriveaz˘ subclase pentru crearea suprafetelor de desenare (plan¸e). Dimensiunile sale implicite sunt 0 ¸i.Listener { //Eventual. sunt: a ınf˘t s • crearea unei plan¸e de desenare. sau mai bine zis a unei componente cu o anumit˘ ˆ a¸i¸are. deoarece acestea vor fi apelate s de c˘tre gestionarii de pozitionare. a Definirea generic˘ a unei plan¸e are urm˘torul format: a s a class Plansa extends Canvas implements . din acest mos tiv. a • redefinirea metodelor getPreferredSize. o plan¸˘ este o suprafat˘ dreptunghiular˘ de culoare alb˘. } // Metodele folosite de gestionarii de pozitionare public Dimension getPreferredSize() { // Dimensiunea implicita a plansei . pe sa ¸a a a care se poate desena. s a eventual ¸i getMinimumSize. ele fiind utilizate doar ca s ¸ suprafete de desenat sau ca fundal pentru animatie. Desenarea pe o plan¸a ¸ ¸ s se face prin supradefinirea metodei paint a acesteia. eventual getMinimumSize. s a a • redefinirea metodei paint din clasa respectiv˘.. DESENAREA obiecte grafice cu o anumit˘ ˆ a¸i¸are.... KeyEvent..272 CAPITOLUL 10. a ¸ Etapele uzuale care trebuie parcurse pentru crearea unui desen. a s • tratarea evenimentelor de tip FocusEvent. Concret. A¸adar. ComponentEvent. getMaximumSize. • ad˘ugarea plan¸ei pe un container cu metoda add. unul sau mai multi constructori public Plansa() { . getMaximumSize. dac˘ este cazul. MouseEvent. a ¸ s Plan¸ele nu pot contine alte componente grafice.. } // Metode de desenare a componentei public void paint(Graphics g) { .

} public Dimension getMinimumSize() { return . g .. vom interschimba cele dou˘ culori a ˆ ıntre ele. } // Implementarea metodelor interfetelor de tip Listener . public Plansa () { this . private Color color [] = { Color ..index ]) . 0 . La fiecare click de mouse. width . awt . class Plansa extends Canvas { Dimension dim = new Dimension (100 . height ) . repaint () .index . a sa a a s a colorate diferite. setColor ( color [1 . height ) .. Listing 10. red .1. private int index = 0... drawRect (0 .*. dim . dim . g . addMouseListener ( new MouseAdapter () { public void mouseClicked ( MouseEvent e ) { index = 1 . g . blue }. Color .. width .10.2: Folosirea clasei Canvas import java . } }) . } public void paint ( Graphics g ) { g . event . dim ..*. } 273 S˘ definim o plan¸˘ pe care desen˘m un p˘trat ¸i cercul s˘u circumscris. 0 . dim . } public Dimension getMaximumSize() { return . fillOval (0 . } public Dimension getPreferredSize () { . setColor ( color [ index ]) . CONCEPTUL DE DESENARE return . import java . awt .. 100) ..

adic˘ stabilirea: at a . In general. de fapt. } } public class TestCanvas { public static void main ( String args []) { new Fereastra ( " Test Canvas " ) . } } 10. In functie de dispoziın s ¸ tivul fizic pe care se face afi¸area (ecran.274 return dim .2 Contextul grafic de desenare Inainte ca utilizatorul s˘ poat˘ desena. ¸ • la imprimant˘ sau a •ˆ ıntr-o zon˘ virtual˘ de memorie. imprimant˘. show () . a Clasa Graphics pune la dispozitie metode pentru: ¸ • primitive grafice: desenarea de figuri geometrice. texte ¸i imagini s • stabilirea propriet˘¸ilor contextului grafic. desenarea se poate face: • pe o portiune de ecran. CENTER ) . a a Un context grafic este specificat prin intermediul unui obiect de tip Graphics primit ca parametru ˆ metodele paint ¸i update. un obiect prin intermediul c˘ruia putem a controla procesul de desenare a unui obiect. add ( new Plansa () . setSize (200 . plotter. DESENAREA class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . ¸ a ıi ¸ Un context grafic este. etc) metodele s a de desenare au implement˘ri interne diferite. } } CAPITOLUL 10. BorderLayout . transparente utilizatorului. 200) . el trebuie s˘ obtin˘ un context grafic a a a ¸ a de desenare pentru suprafata c˘reia ˆ apartine regiunea pe care se va desena.

etc. 10. vor fi specificati ¸ ¸ pentru contextul grafic ˆ care se face desenarea ¸i nu vor fi trimi¸i ca arın s s gumente metodelor respective de desenare. 275 10. drawString("Hello". ın care permit desenarea de figuri geometrice ¸i texte. font. 20). CONTEXTUL GRAFIC DE DESENARE – culorii ¸i fontului curente cu care se face desenarea. ¸ ın – modului de desenare. enumer˘m aceste a propriet˘¸i ¸i metodele asociate lor din clasa Graphics. Textul va fi desenat s s ¸ a cu fontul ¸i culoarea curente ale contextului grafic.2.10. Desenarea figurilor geometrice se realizeaz˘ cu urm˘toarele metode: a a .2. ¸ – suprafetei ˆ care sunt vizibile componentelor desenate. s – originii coordonatelor suprafetei de desenare. s Desenarea textelor se face cu uzual cu metoda drawString care prime¸te s ca argumente un ¸ir ¸i coltul din stˆnga-jos al textului. at s Metode Color getColor() void setColor(Color c) Fontul de scriere a textelor Font getFont() void setFont(Font f) Originea coordonatelor translate(int x.2.2 Primitive grafice Prin primitive grafice ne vom referi ˆ continuare la metodele clasei Graphics. y=20. int y) Zona de decupare Shape getClip() (zona ˆ care sunt vizibile desenele) void setClip(Shape s) ın Modul de desenare void setXorMode(Color c) void setPaintMode(Color c) Proprietate Culoarea de desenare 10.1 Propriet˘¸ile contextului grafic at La orice tip de desenare parametrii legati de culoare. In continuare. s // Desenam la coordonatele x=10.

a Cei mai importanti parametri ce caracterizeaz˘ un font sunt: ¸ a • Numele fontului: Helvetica Bold. adic˘ ”umplut” cu culoarea curent˘ a contextului de desenare. pentru a scrie un text pe ecran avem dou˘ posibilit˘¸i. cum ar fi drawString. • Familia din care face parte fontul: Helvetica.276 Figur˘ geometric˘ a a Linie CAPITOLUL 10. fie din Graphics. Arial. etc. putem a specifica prin intermediul fonturilor cum s˘ arate textul respectiv.3 Folosirea fonturilor Dup˘ cum vazut. ˆ s ınclinat (italic). Arial Bold Italic. cum ar a a a fi Label. ın˘ ¸ • Stilul fontului: ˆ ıngro¸at (bold). • Dimensiunea fontului: ˆ altimea sa. etc. . DESENAREA Metode drawLine drawPolyline Dreptunghi simplu drawRect fillRect clearRect Dreptunghi cu chenar draw3DRect ”ridicat” sau ”adˆncit” fill3DRect a Dreptunghi cu colturi ¸ drawRoundRect retunjite fillRoundRect Poligon drawPolygon fillPolygon Oval (Elips˘ a drawOval fillOval Arc circular sau drawArc eliptic fillArc Metodele care ˆ ıncep cu ”fill” vor desena figuri geometrice care au interiorul colorat. iar a doua s˘ apel˘m la metodele clasei Graphics de desenare a a a textelor. Indiferent de modalitatea aleas˘. a a ˆ timp ce metodele care ˆ ın ıncep cu ”draw” vor desena doar conturul figurii respective. 10. acest lucru a realizˆndu-se prin metoda setFont fie din clasa Component. a a at Prima dintre acestea este s˘ folosim o component˘ orientat˘-text.

PLAIN. Font.BOLD.1 Clasa Font Un obiect de tip Font ˆ ıncapsuleaz˘ informatii despre toti parametrii unui a ¸ ¸ font. Textul fiec˘rui nume de font va fi scris cu fontul s˘u a a a corespunz˘tor. o serie ˆ a ıntreag˘ de a fonturi care sunt disponibile pentru scrierea textelor.10.getAllFonts(). Lista acestor fonturi se poate obtine astfel: ¸ Font[] fonturi = GraphicsEnvironment. int style. // In metoda paint(Graphics g) g. la un moment dat.3. new Font("Courier". 20). 10)). mai putin despre metrica acestuia. Folosirea unui obiect de tip Font se realizeaz˘ uzual astfel: a // Pentru componente etichetate Label label = new Label("Un text"). FOLOSIREA FONTURILOR • Metrica fontului. ın at 10. 10).3. Font.BOLD. 14).ITALIC. a s ˆ continuare fiind prezentate modalit˘¸ile de lucru cu acestea. int size) Stilul unui font este specificat prin intermediul constantelor: Font. new Font("Arial". O platform˘ de lucru are instalate. 10.ITALIC iar dimensiunea printr-un ˆ ıntreg. label. ca ˆ exemplele ın de mai jos: new Font("Dialog".BOLD. Font. Font.PLAIN. Font. Font. a . Exemplul urmator afi¸eaz˘ lista tuturor fonturilor disponibile pe plats a forma curent˘ de lucru.setFont(new Font("Courier". getLocalGraphicsEnvironment(). Font. 277 Clasele care ofer˘ suport pentru lucrul cu fonturi sunt Font ¸i FontMetrics. Constructorul uzual al clasei este ¸ cel care prime¸te ca argument numele fontului.setFont(new Font("Dialog". 12). g. dimensiunea ¸i stilul acestuia: s s Font(String name.drawString("Alt text".PLAIN. 12)).

drawString ( i + " . length ) * 20. 400) . pack () . } } public class TestAllFonts { public static void main ( String args []) { new Fereastra ( " All fonts " ) . 20 . i < fonturi . ScrollPane sp = new ScrollPane () . Dimension canvasSize = new Dimension (400 . g . add ( sp . sp . i ++) { nume = fonturi [ i ].278 CAPITOLUL 10. } } public Dimension getPreferredSize () { return canvasSize . getAllFonts () . 14) ) . } } . " + nume .*. getFontName () . canvasSize . BorderLayout . DESENAREA Listing 10.3: Lucrul cu fonturi import java . add ( new Fonturi () ) . sp . length . for ( int i =0. awt . 400) . PLAIN . ( i + 1) * 20) . height = (1 + fonturi . Font . setFont ( new Font ( nume . public Fonturi () { fonturi = Graphi c sE n v ir o nm e n t . } } class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . class Fonturi extends Canvas { private Font [] fonturi . show () . CENTER ) . setSize (400 . g . } public void paint ( Graphics g ) { String nume . g e t L o c a l G r a p h i c s E n v i r o n m e n t () .

s • In˘ltimea: distanta dintre liniile de baz˘ (leading+ascent+descent). Un obiect din aceast˘ clas˘ a a a se construie¸te pornind de la un obiect de tip Font ¸i pune la dispozitie s s ¸ informatii despre dimensiunile ˆ pixeli pe care le au caracterele fontului ¸ ın respectiv ˆ ıntr-un anumit context de desenare. • Ascendentul: distanta ˆ ¸ ıntre linia de baz˘ ¸i linia de ascendent˘. indiferent de fontul ¸ a ¸a folosit de acestea. at at • Distanta ˆ ¸ ıntre linii (”leading”): distanta optim˘ ˆ ¸ a ıntre dou˘ linii de text a scrise cu acela¸i font. a¸ ¸ a Figura de mai jos prezint˘ o imagine reprezentativ˘ asupra metricii unui a a font: . un obiect de tip FontMetrics ˆ s ıncapsuleaz˘ informatii despre a ¸ metrica unui font. Metrica unui font const˘ ˆ urm˘toarele atribute pe care le au caracterele a ın a sale: • Linia de baz˘: este linia dup˘ care sunt aliniate caracterele unui font.3. as ¸a • Descendentul: distanta ˆ ¸ ıntre linia de baz˘ ¸i linia de descendent˘. a a • Linia de ascendent˘: linia superioara pe care nu o depaseste nici un ¸a caracter din font • Linia de descendent˘: linia inferioar˘ sub care nu coboar˘ nici un car¸a a a acter din font. A¸adar. Utilitatea principal˘ a acestei clase const˘ ˆ faptul c˘ permite a a ın a pozitionarea precis˘ a textelor pe o suprafat˘ de desenare. cu alte cuvinte despre dimensiunile ˆ pixeli ale caracın terelor sale.10. s ın ¸ s ınalt ın Pentru aceasta este folosit˘ clasa FontMetrics. trebuie s˘ calcul˘m pozitiile s a a ¸ lor de afi¸are ˆ functie de lungimea ¸i ˆ ¸imea ˆ pixeli a celorlalte texte.2 Clasa FontMetrics La afi¸area unui ¸ir cu metoda drawString trebuie s˘ specific˘m pozitia la s s a a ¸ care s˘ apar˘ textul respectiv pe ecran. FOLOSIREA FONTURILOR 279 10.3. sau unele sub altele. In momentul ˆ care avem de afi¸at a a ın s mai multe ¸iruri consecutiv. as ¸a • L˘¸imea: l˘¸imea unui anumit caracter din font.

determin˘ l˘¸imea total˘ ˆ pixeli a unui ¸ir de caractere a at a ın s specificat. pornind de la fontul curent al contextului grafic: public void paint(Graphics g) { Font f = new Font("Arial". • charWidth . } Cele mai folosite metode ale clasei FontMetrics sunt: • getHeight . Ca s˘ fim mai s a ¸ a a preci¸i.determin˘ l˘¸imea unui anumit caracter din font. s a ¸ a Un context grafic pune la dispozitie o metod˘ special˘ getFontMetrics ¸ a a de creare a unui obiect de tip FontMetrics. int y) argua mentele x ¸i y repreznit˘ coltul din stˆnga-jos al textului.determin˘ ˆ altimea unei linii pe care vor fi scrise caractere a ın˘ ¸ ale unui font. DESENAREA Reamintim c˘ la metoda drawString(String s. 11).getFontMetrics(). y reprezint˘ pozitia liniei de baz˘ a textului care va fi scris. int x. a at In exemplul urm˘tor sunt afi¸ate pe ecran zilele s˘pt˘mˆnii ¸i lunile ana s a a a s ului: .BOLD. Font.280 CAPITOLUL 10. • stringWidth . FontMetrics fm = g.

i < zile . x += fm . " Noiembrie " . private String [] zile = { " Luni " .4: Folosirea clasei FontMetrics import java . " Joi " .10. " Februarie " . x += fm . Font . g . " Septembrie " . Font . y ) . length . 14) ) . x += fm .1) text += " . drawString ( etLuni . String etZile = " Zilele saptamanii : " . 100) . 20) ) . y ) . // Alegem un font si aflam metrica sa g . " Vineri " . i ++) { text = luni [ i ]. length . " August " . " Iunie " . drawString ( text . " Miercuri " . class Texte extends Canvas { Dimension canvasSize = new Dimension (800 . BOLD . stringWidth ( text ) . x = 0. int x . " Decembrie " }. y = fm . awt . " Duminica " }. " . length . text . stringWidth ( etZile ) . getHeight () . " Martie " . x = 0. x . i < luni .3. i ++) { text = zile [ i ]. getFontMetrics () . " Marti " .1) 281 . y += fm . private String [] luni = { " Ianuarie " . setFont ( new Font ( " Arial " . y ) . length . PLAIN . stringWidth ( etLuni ) . for ( int i =0. fm = g . getFontMetrics () . for ( int i =0. g . FOLOSIREA FONTURILOR Listing 10. if ( i < zile .*. drawString ( etZile . setFont ( new Font ( " Dialog " . " Aprilie " . " Octombrie " . x . " Iulie " . fm = g . " Mai " . " Sambata " . getHeight () . etLuni = " Lunile anului : " . } // Schimbam fontul g . y . g . public void paint ( Graphics g ) { FontMetrics fm . x . if ( i < luni .

0 (dac˘ dorim s˘ specific˘m valorile prin numere s a a a reale). CAPITOLUL 10. pack () . show () .4 Folosirea culorilor Orice culoare este format˘ prin combinatia culorilor standard ro¸u (red). stringWidth ( text ) . Pentru a crea o culoare avem dou˘ posibilit˘¸i: a at • S˘ folosim una din constantele definite ˆ cele dou˘ clase. la care se adaug˘ un anumit grad de transparent˘ s a ¸a (alpha). drawString ( text . BorderLayout . DESENAREA } } public Dimension getPreferredSize () { return canvasSize . } } class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . Fiecare din ace¸ti patru parametri poate varia ˆ s ıntr-un interval cuprins fie ˆ ıntre 0 ¸i 255 (dac˘ dorim s˘ specific˘m valorile prin numere s a a a ˆ ıntregi). a ın a • S˘ folosim unul din constructorii clasei Color. CENTER ) . x += fm . " . f . a S˘ vedem mai ˆ ai care sunt constantele definite ˆ aceste clase: a ıntˆ ın . g . y ) . a ¸ s verde (green) ¸i albastru (blue).282 text += " . x . add ( new Texte () . } } public class TestFontMetrics { public static void main ( String args []) { Fereastra f = new Fereastra ( " FontMetrics " ) . fie ˆ ıntre 0. } } 10. O culoare este reprezentat˘ printr-o instant˘ a clasei Color sau a suba ¸a clasei sale SystemColor.0 ¸i 1.

meniuri. 0-7 albastru.0) specific˘ transparent˘ total˘. respectiv 0. verde.. int blue) Color(int red.4. alpha sunt valorile pentru ro¸u. int green. culorile sunt complet opace. float blue. etc) ale platformei curente de lucru. Color galben = Color. a ¸a a . Folosirea acestor constante se face ca ˆ exemplele de mai jos: ın Color rosu = Color. int alpha) Color(int rgb) unde red.desktop. texte.0) pentru transparent˘ ¸a specific˘ faptul c˘ respectiva culoare este complet opac˘.red. atunci putem crea noi culori prin intermediul constructorilor clasei Color: Color(float red.0 − 1.10.yellow. Implicit. ¸ s Valorile argumentelor variaz˘ ˆ a ıntre 0 − 255 pentru tipul int. blue.. albastru ¸i s s transparent˘ iar parametrul ”rgb” de la ultimul constructor reprezint˘ un ¸a a ˆ ıntreg format din: bitii 16-23 ro¸u. 283 Observati c˘ ˆ clasa Color sunt definite culori uzuale din paleta standard ¸ a ın de culori. iar valoarea 0 (sau a a a 0. ˆ timp ce ˆ clasa SystemColor sunt definite culorile componenın ın telor standard (ferestre. 8-15 verde. Dac˘ nici una din aceste culori predefinite nu corespunde preferintelor noasa ¸ tre. float green. Valoarea 255 (sau 1. int green.0 pentru tipul float. green. float blue) Color(flot red. FOLOSIREA CULORILOR Color black blue cyan darkGray gray green lightGray magenta orange pink red white yellow SystemColor activeCaption activeCaptionBorder activeCaptionText control controlHighlight controlShadow contolText desktop menu text textHighlight window . flot green. float alpha) Color(int red. int blue. Color fundal = SystemColor.

black ) . ¸ ¸ a Aplicatia va ar˘ta astfel: ¸ a Listing 10. 0-7 albastru) a ¸ s S˘ consider˘m o aplicatie cu ajutorul c˘reia putem vizualiza dinamic cua a ¸ a lorile obtinute prin diferite combinatii ale parametrilor ce formeaz˘ o culoare. 255) . Color negru = new Color(0.284 CAPITOLUL 10. . 255. awt . import java . Metodele cele mai folosite ale clasei Color sunt: brighter darker getRed getGreen getBlue getAlpha getRGB Creeaz˘ o noua versiune a culorii curente a mai deschis˘. 0. awt . 0). Color rosuTransparent = new Color(255. 0. 0. 255). 128). public void paint ( Graphics g ) { g . class Culoare extends Canvas { public Color color = new Color (0 . 50) .*. event . 0. 8-15 verde. setColor ( Color . Dimension canvasSize = new Dimension (150 .5: Folosirea clasei Color import java .*. 0 . 0 . Color rosu = new Color(255. 0). DESENAREA // Exemple de folosire a constructorilor: Color alb = new Color(255. respectiv mai ˆ a ınchis˘ a Determin˘ parametrii din care a este alcatuit˘ culoarea a Determin˘ valoarea ce reprezint˘ culoarea a a respectiv˘ (bitii 16-23 ro¸u.

HORIZONTAL . this . green ) . rValue . 0 . private Culoare culoare . . aValue . getAlpha () . setBackground ( Color . setBackground ( Color . getRed () . text += " A = " + color . g . 1 . text += " B = " + color . 0 . 0 . rgbValues . bValue = new Scrollbar ( Scrollbar . setLayout ( new GridLayout (4 . setFont ( new Font ( " Arial " . 1 . HORIZONTAL . 256) . width . String text = " " . blue ) . 0 . text += " G = " + color . 0 . gValue = new Scrollbar ( Scrollbar . 0 . canvasSize . text += " R = " + color . HORIZONTAL . rValue = new Scrollbar ( Scrollbar . bValue .4. 1) ) . bValue . 30) . canvasSize . 256) . 256) . public Fereastra ( String titlu ) { super ( titlu ) . fillRect (0 . addWindowListener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . 0 . Font . Panel rgbValues = new Panel () . 256) . FOLOSIREA CULORILOR g . height ) . setColor ( color ) . aValue = new Scrollbar ( Scrollbar . BOLD . drawString ( text . 1 . } }) . HORIZONTAL . g . } public Dimension getPreferredSize () { return canvasSize . 0 . 1 . gValue . exit (0) . gValue . 0 . g . 12) ) .10. red ) . } } 285 class Fereastra extends Frame implements Ad ju st me nt Lis te ne r { private Scrollbar rValue . setBackground ( Color . getBlue () . getGreen () . 0 .

add ( rgbValues . CENTER ) . add Adjus t m e n t L i s t e n e r ( this ) . b . bValue . add Adjus t m e n t L i s t e n e r ( this ) . Color c = new Color (r . add Adjus t m e n t L i s t e n e r ( this ) .5 Folosirea imaginilor Aceasta este o imagine: . rValue . rgbValues . getValue () . int a = aValue . add ( gValue ) . } } public class TestColor { public static void main ( String args []) { Fereastra f = new Fereastra ( " Color " ) . add ( rValue ) . rgbValues . add ( bValue ) . setBackground ( Color . repaint () .286 CAPITOLUL 10. rgbValues . BorderLayout . NORTH ) . BorderLayout . setValue (255) . culoare . culoare . f . color = c . rgbValues . } public void ad ju stm en tV al u e C h an ge d ( AdjustmentEvent e ) { int r = rValue . add Adjus t m e n t L i s t e n e r ( this ) . add ( culoare . g . culoare = new Culoare () . int g = gValue . DESENAREA aValue . lightGray ) . setSize (200 . getValue () . aValue . getValue () . int b = bValue . getValue () . 100) . } } 10. a ) . rgbValues . pack () . show () . add ( aValue ) . gValue . aValue .

ro/~acf/poza. ¸ ca ˆ exemplul de mai jos: ın Toolkit toolkit = Toolkit.5. Orice imagine va fi reprezentat˘ ca o instant˘ a clasei Image.5. 2. . fie aflat la o anumit˘ adres˘ Web s a a a (URL). FOLOSIREA IMAGINILOR 287 In AWT este posibil˘ folosirea imaginilor create extern ˆ format gif sau a ın jpeg. Image image2 = toolkit.gif"). Metodele pentru ˆ arcarea unei imagini dintr-un fi¸ier se g˘sesc ınc˘ s a ˆ clasele Applet ¸i Toolkit. String fisier) getImage(String fisier) Pentru a obtine un obiect de tip Toolkit se va folosi metoda getDefaultToolkit. Aceasta a ¸a nu este o clas˘ de componente (nu extinde Component) ci implementeaz˘ a a obiecte care pot fi desenate pe suprafata unor componente cu metode specifice ¸ unui context grafic pentru componenta respectiva (similar modului cum se deseneaz˘ o linie sau un cerc). Crearea unui obiect de tip Image se face folosind o imagine dintr-un fi¸ier s fie aflat pe ma¸ina pe care se lucreaz˘.getImage("poza.1 Afi¸area imaginilor s Afi¸area unei imagini presupune realizarea urm˘toarilor doi pa¸i: s a s 1.infoiasi. Image image1 = toolkit. Crearea unui obiect de tip Image. a 10.getImage( new URL("http://www.getDefaultToolkit(). avˆnd ˆ a aceea¸i denumire getImage ¸i ın s a ıns˘ s s urm˘toarele formate: a Applet Toolkit getImage(URL url) getImage(URL url) getImage(URL url. Afi¸area propriu-zis˘ ˆ s a ıntr-un context grafic.10.gif")).

aceste operatiuni a ın ¸ fiind f˘cute abia ˆ momentul ˆ care se va realiza afi¸area imaginii pentru a ın ın s prima dat˘. ¸a a a Afi¸area unei imagini ˆ s ıntr-un context grafic se realizeaz˘ prin intermediul a metodei drawImage din clasa Graphics ¸i. a a In exemplul urm˘tor afi¸am aceea¸i imagine de trei ori. Color bgcolor. this). 200. int y. int boolean drawImage(Image img. int height. ImageObserver unde: • img este obiectul ce reprezint˘ imaginea. y sunt coordonatele stˆnga-sus la care va fi afi¸at˘ imaginea. ImageObserver observer) x.gif"). 0. a • x.drawImage(img. int Color bgcolor. 200. int ImageObserver observer) boolean drawImage(Image img. a a • width. int width. Cele mai uzuale formate ale metodei sunt: boolean drawImage(Image img. g. a s a • bgColor reprezint˘ culoarea cu care vor fi colorati pixelii transparenti a ¸ ¸ ai imaginii (poate s˘ lipseasc˘). 400.getDefaultToolkit(). relative a s a la spatiul de coordonate al contextului grafic. int y. this). Color. Metoda nu face decˆt s˘ creeze un obiect de tip Image care face a a a referint˘ la o anumit˘ imagine extern˘. 100. g. heigth reprezint˘ ˆ ¸imea ¸i l˘¸imea la care trebuie scalat˘ a ınalt s at a imaginea (dac˘ lipsesc.288 CAPITOLUL 10. int y. 200. int width.getImage("taz. imaginea va fi afi¸at˘ la dimensiunile ei reale).drawImage(img. this). x. ˆ general. int ImageObserver observer) boolean drawImage(Image img. 0. 0.drawImage(img. folosind forme a s s diferite ale metodei drawImage: Image img = Toolkit. 100. x.yellow. g. int y. observer) . x. ¸ • observer este un obiect care ”observ˘” ˆ arcarea imaginii ¸i va fi ina ınc˘ s format pe m˘sura derul˘rii acesteia. va fi facut˘ ˆ metoda s ın a ın paint a unei componente. DESENAREA Metoda getImage nu verific˘ dac˘ fi¸ierul sau adresa specificata reprezint˘ a a s a o imagine valid˘ ¸i nici nu ˆ as ıncarc˘ efectiv imaginea ˆ memorie. int height. 0.

FOLOSIREA IMAGINILOR 289 Metoda drawImage returneaz˘ true dac˘ imaginea a fost afi¸at˘ ˆ ˆ a a s a ın ıntregime ¸i false ˆ caz contrar. int flags. Acest mecanism este realizat prin intermediul interfetei s a ¸ ImageObserver. int y. Aceste informatii pot fi aflate prin intermediul constantelor ¸ definite de interfat˘: ¸a . Intregul f lags furnizeaz˘ informatii despre starea ¸ a ¸ transferului.5. Formatul acestei metode este: ınc˘ boolean imageUpdate (Image img. int w. a Interfata ImageObserver are o singur˘ metod˘ numit˘ imageUpdate. implementat˘ de clasa Component ¸i deci de toate compoa s nentele. Ca urmare. ¸ a 10.2 Monitorizarea ˆ arc˘rii imaginilor ınc˘ a In cazul ˆ care se afi¸eaz˘ o imagine care se g˘se¸te pe Internet sau imaginea ın s a a s afi¸ata este de dimensiuni mari se va observa c˘ aceasta nu apare complet de s a la ˆ ınceput ci este desenat˘ treptat. In sectiunea urm˘toare vom detalia acest aspect. cu alte cuvinte metoda nu a¸tept˘ ca o imagine s˘ s ın s a a fie complet afi¸at˘ ci se termin˘ imediat ce procesul de afi¸are a ˆ s a a s ınceput. ¸ a a a ce va fi apelat˘ periodic de firul de executie (creat automat) care se ocup˘ a ¸ a cu ˆ arcarea imaginii. Acest a aa ¸ lucru se ˆ ampl˘ deoarece metoda drawImage nu face decˆt s˘ declan¸eze ıntˆ a a a s procesul de ˆ arcare ¸i desenare a imaginii. De aceea a ¸ s a trebuie s˘ existe un mecanism prin care componenta s˘ fie redesenat˘ aua a a tomat ˆ momentul ˆ care au mai sosit informatii legate de imagine. Aceast˘ interfat˘ descrie obiecte care au ˆ a ¸a ınceput s˘ utilizeze o imaga ine incomplet˘ ¸i care trebuie anuntate de noile date obtinute ˆ legatur˘ cu as ¸ ¸ ın a imaginea respectiv˘. f˘r˘ interventia programatorului.10. int h ) Implementarea implicit˘ const˘ dintr-un apel la metoda repaint pentru a a dreptunghiul specificat la apel ¸i care reprezint˘ zona din imagine pentru care s a se cunosc noi informatii. lucru deosebit de util ˆ ıntrucˆt procesul de ˆ arcare a a ınc˘ unei imagini poate dura mult ¸i nu este de dorit ca ˆ acest interval de timp s ın (pˆn˘ la ˆ arcarea complet˘ a imaginii) aplicatia s˘ fie blocat˘. pˆn˘ la ın ın ¸ a a afi¸area sa complet˘.5. dup˘ care red˘ imediat conınc˘ s a a trolul apelantului. a a ınc˘ a ¸ a a la apelul metodei drawImage va fi desenat˘ numai portiunea de imagine care a ¸ este disponibil˘ la momentul initial ¸i care poate fi incomplet˘. int x.

int h) { // Desenam imaginea numai daca toti bitii sunt disponibili if (( flags & ALLBITS) != 0) repaint(). DESENAREA Inc˘rcarea imaginii a fost ˆ a ıntrerupt˘.290 ABORT CAPITOLUL 10. } De asemenea. int w. a // Imaginea este completa (flags & ALLBITS) != 0 // Eroare sau transferul imaginii a fost intrerupt (flags & ERROR | ABORT ) != 0 Metoda imageUpdate poate fi redefint˘ de o component˘ pentru a pera a sonaliza procesul de afi¸are al imaginii. . int getHeight(ImageObserver observer) int getWidth(ImageObserver observer) Dac˘ desenarea se face folosind clasa Canvas. se observ˘ c˘ metodele clasei Image pentru determinarea a a dimensiunilor unei imagini au ca argument un obiect de tip ImageObserver. atunci argumentul observer a al metodelor referitoare la imagini va fi this. int flags. int y. a ˆ ınainte de completarea sa ALLBITS Imaginea a fost ˆ ıncarcat˘ complet a ERROR A ap˘rut o eroare ˆ timpul a ın ˆ arc˘rii imaginii ınc˘ a FRAMEBITS Toti bitii cadrului curent sunt disponibili ¸ ¸ HEIGHT In˘ltimea imaginii este disponibil˘ a¸ a PROPERTIES Propriet˘¸ile imaginii sunt disponibile at SOMEBITS Au fost receptionati noi pixeli ai imaginii ¸ ¸ WIDTH L˘¸imea imaginii este disponibil˘ at a Prezenta ˆ parametrul f lags a unui bit de valoare 1 pe pozitia reprezen¸ ın ¸ tata de o constant˘ ˆ a ınseamn˘ c˘ respectiva conditie este ˆ a a ¸ ındeplinit˘. // Daca sunt toti bitii nu mai sunt necesare noi update-uri return ( (flags & (ALLBITS | ABORT)) == 0). a a public boolean imageUpdate(Image img. int x. Aceasta va fi apelat˘ apelat˘ asincron s a a de fiecare dat˘ cˆnd sunt disponibili noi pixeli.

). Graphics gmem = img.fillOval(.5. FOLOSIREA IMAGINILOR 291 10.jpeg din distributia standard Java ofer˘ ¸ a suport pentru salvarea unei imagini aflate ˆ memorie ˆ ın ıntr-un fi¸ier ˆ fors ın .). this). . 0. pentru a elimina efectul nepl˘cut de ”clipire” (”flicka a ering”) rezultat atunci cˆnd sunt efectuate redesen˘ri repetate la intervale a a mici de timp.. h).5. /* Realizam desenul folosind gmem gmem. } } 10.codec.dispose()..drawImage(img.getGraphics(). 0.setColor(.sun.4 Salvarea desenelor ˆ format JPEG ın Pachetul com.10. O situatie frecvent˘ ˆ care se apeleaz˘ la double-buffering este ¸ a ın a crearea de animatii.. gmem.3 Mecanismul de ”double-buffering” Tehnica de double-buffering implic˘ realizarea unui desen ˆ memorie ¸i apoi a ın s transferul s˘u pe ecran. gmem.image. */ // Transferam desenul din memorie pe ecran // desenand de fapt imaginea creata g...5. } public void paint(Graphics g) { // Desenam in memorie pe un obiect de tip Image // w si h sunt dimensiunile desenului Image img = createImage(w. ¸ Secventa general˘ de implementare a mecanismului de double-buffering ¸ a este urm˘toarea: a // Supradefinim update pentru a elimina stergerea desenului public void update(Graphics g) { paint(g)..

java.printStackTrace().5. // Folosim setarile de codare jpeg implicite encoder.createJPEGEncoder(out).jpeg. } catch( Exception e ) { e. java.awt.9f. class JPEGWriter { static float quality = 0.getDefaultJPEGEncodeParam(img).awt.*.image. a s aflata ˆ pachetul java. DESENAREA mat JPEG. jep.BufferedImage. O clas˘ responsabil˘ cu realizarea acestei operatiuni ar putea fi a a ¸ definit˘ astfel: a import import import import com. JPEGEncodeParam jep = encoder. String filename) { try { FileOutputStream out = new FileOutputStream(filename). java.io.image. encoder.image.encode(img).awt.5 Crearea imaginilor ˆ memorie ın In cazul ˆ care dorim s˘ folosim o anumit˘ imagine creat˘ direct din proın a a a gram ¸i nu ˆ s ıncarcat˘ dintr-un fi¸ier vom folosi clasa MemoryImageSource.*.close().292 CAPITOLUL 10. false). Pentru aceasta va trebui s˘ definim un ın a .setJPEGEncodeParam(jep). JPEGImageEncoder encoder = JPEGCodec. //intre 0 si 1 public static void write(BufferedImage img.setQuality(quality.sun. out. } } } 10.*.codec.

normal aceste valori sunt off = 0. x++) { int red = (int) (Math. this). iar clasa principal˘ a a a care controleaz˘ procesul de tip˘rire este PrinterJob. for (int y = 0. scan = w In exemplul urmator vom crea o imagine cu pixeli de culori aleatorii ¸i o s vom afi¸a pe ecran: s int w = 100. int[] pix = new int[w * h]. O aplicatie va apela a a ¸ metode ale acestei clase pentru: . int blue = (int) (Math.˘ 10. pix. w)). blue). h reprezint˘ dimensiunile imaginii (l˘¸imea ¸i ˆ altimea).drawImage(img. y++) { for (int x = 0. int h = 100. • of f. scan reprezint˘ modalitatea de construire a matricii imaginii pornind a de la vectorul cu pixeli. Constructorul clasei ¸ a at ın MemoryImageSource este: MemoryImageSource(int w. y < h.6.6 Tip˘rirea a Tip˘rirea ˆ Java este tratat˘ ˆ aceea¸i manier˘ ca ¸i desenarea. int scan) unde: • w.awt. singurul a ın a ın s a s lucru diferit fiind contextul grafic ˆ care se execut˘ operatiile. 0.random() * 255). int off. pix[index++] = new Color(red. green. int h. int[] pixeli.print. } img = createImage(new MemoryImageSource(w. g. int index = 0. a at s ın˘ ¸ • pixeli[] este vectorul cu culorile imaginii. h.getRGB(). // g este un context grafic 10. int green = (int) (Math. TIPARIREA 293 vector de numere ˆ ıntregi ˆ care vom scrie valorile ˆ ın ıntregi (RGB) ale culorilor pixelilor ce definesc imaginea noastr˘. Dimensiunea vectorului va a fi ˆ altimea ˆ ın˘ ¸ ınmultit˘ cu l˘¸imea ˆ pixeli a imaginii. x < w.random() * 255). 0.random() * 255). Pachetul ın a ¸ care ofer˘ suport pentru tip˘rire este java. 0.

orice informatii care trebuie atˆt afi¸ate cˆt ¸i tip˘rite.PAGE_EXISTS.294 CAPITOLUL 10.getPrinterJob a 2.NO_SUCH_PAGE. a a ¸ care contine o singur˘ metod˘ print. metodele paint ¸i print pot specifica aceea¸i a s s secvent˘ de cod. } Pa¸ii care trebuie efectuati pentru tip˘rirea unui obiect sunt: s ¸ a 1. DESENAREA • Crearea unei sesiuni de tip˘rire (job). ¸ a • Tip˘rirea efectiv˘. care are o reprezentare vizual˘ descris˘ a a a de metoda paint ¸i care va specifica ¸i modalitatea de reprezentare a sa la s s imprimant˘. ¸ a . metoda print are urm˘torul format: ¸a a public int print(Graphics g. In gena s a s a a eral. a • Invocarea dialogului cu utilizatorul pentru specificarea unor parametri legati de tip˘rire. initierea unui dialog cu utilizatorul pentru precizarea unor ¸ ¸ parametri legati de tip˘rire: printDialog. responsabil˘ cu descrierea modalit˘¸ii ¸ a a a at de tip˘rire a obiectului. a a Orice component˘ care poate fi afi¸at˘ pe ecran poate fi ¸i tip˘rit˘. a ¸ 3. vor fi ˆ ¸ a s a s a ıncapsulate ˆ ıntr-un obiect grafic . a Un obiect care va fi tip˘rit trebuie s˘ implementeze interfata Printable. int pageIndex) throws PrinterException { // Descrirea imaginii obiectului ce va fi afisata la imprimanta // Poate fi un apel la metoda paint: paint(g) if (ceva nu este in regula}) { return Printable. Specificarea obiectului care va fi tip˘rit: setPrintable. } return Printable. Crearea unei sesiuni de tip˘rire: PrinterJob. In cazul cˆnd imaginea de pe ecran coincide cu a a imaginea de la imprimant˘. acesta trebuie a s˘ implementeze interfata Printable.component˘. In general. Optional. PageFormat pf.

public Dimension getPreferredSize () { return d . java . 200 . drawString ( " Hello " .*. } } class Fereastra extends Frame implements ActionListener { private Plansa plansa = new Plansa () . awt . 200 . drawString ( " Numai la imprimanta " .6. } public void paint ( Graphics g ) { g . paint ( g ) . private Button print = new Button ( " Print " ) .*. addWindowListener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { . 100) . awt . g . PageFormat pf . int pi ) throws PrinterException { if ( pi >= 1) return Printable . s a Listing 10. 100 . 200 . 100) . 200) . drawOval (200 . print . drawRect (200 . PAGE_EXISTS .*. java . 300) . public Fereastra ( String titlu ) { super ( titlu ) . event . } public int print ( Graphics g .*. ˆ a s a a ınsotite de un text) ¸i vom tip˘ri obiectul respectiv. awt . io . class Plansa extends Canvas implements Printable { Dimension d = new Dimension (400 . a a 295 In exemplul urm˘tor vom defini un obiect care are aceea¸i reprezentare a s pe ecran cˆt ¸i la imprimant˘ (un cerc circumscris unui p˘trat.˘ 10.6: Tip˘rirea unei componente a import import import import java . g . g . TIPARIREA 4. 200 . NO_SUCH_PAGE . 400) . return Printable . Tip˘rirea efectiv˘: print. 100 . java .

} public void actionPerformed ( ActionEvent e ) { // 1. Initierea dialogului cu utilizatorul if ( printJob . DESENAREA add ( plansa . } }) . south . print () . Stabilirea obiectului ce va fi tiparit printJob . CENTER ) . Tiparirea efectiva printJob . } } . south . Panel south = new Panel () . } catch ( PrinterException ex ) { System . // 2. getPrinterJob () . Crearea unei sesiuni de tiparire PrinterJob printJob = PrinterJob . add ( south . ex . print . println ( " Exceptie la tiparire ! " ) . exit (0) . CENTER ) ) . // 3. pack () . BorderLayout . BorderLayout . out . } } } } public class TestPrint { public static void main ( String args []) throws Exception { Fereastra f = new Fereastra ( " Test Print " ) . SOUTH ) . addActionListe ner ( this ) .296 System . show () . f . printStackTrace () . setLayout ( new FlowLayout ( FlowLayout . CAPITOLUL 10. printDialog () ) { try { // 4. add ( print ) . setPrintable ( plansa ) .

imp .*. iar ˆ Unix prin ”/dev/lp”. In sistemul de operare Windows. // pentru UNIX // PrintWriter imp = new PrintWriter ( new FileWriter ("/ dev / lp ") ) . } } .˘ 10. TIPARIREA 297 Tiparirea textelor O alt˘ variant˘ pentru tip˘rirea de texte este deschiderea unui flux c˘tre a a a a dispozitivul special reprezentat de imprimant˘ ¸i scrierea informatiilor. pe acest flux. imp . imp . imprimanta poate fi referit˘ prin ”lpt1”. import java .6. deoarece necesit˘ tratare special˘ ˆ functie de a a a ın ¸ sistemul de operare folosit. println ( " Test imprimanta " ) . awt . Observati c˘ aceast˘ a ın ¸ a a abordare nu este portabil˘.*. println ( " ABCDE " ) . close () .7: Tip˘rirea textelor a import java . linie as ¸ cu linie. Listing 10. io . class TestPrintText { public static void main ( String args []) throws Exception { // pentru Windows PrintWriter imp = new PrintWriter ( new FileWriter ( " lpt1 " ) ) .

DESENAREA .298 CAPITOLUL 10.

cum ar fi cititoare a de ecran. Motif sau altele oferite de diver¸i dezvoltatori. a ¸ • Accessibility API Permite dezvoltarea de aplicatii care s˘ comunice cu dispozitive uti¸ a lizate de c˘tre persoane cu diverse tipuri de handicap. ecrane Braille. cum ar fi cele standard Windows.Capitolul 11 Swing 11.1 Introducere JFC Tehnologia Swing face parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) care pune la dispozitie o serie ˆ ¸ ıntreag˘ de facilit˘¸i pena at tru scrierea de aplicatii cu o interfat˘ grafic˘ mult ˆ ¸ ¸a a ımbog˘¸it˘ functional ¸i at a ¸ s estetic fat˘ de vechiul model AWT. Acela¸i program poate utiliza diın ¸ ¸ a s verse moduri Look-and-Feel.1. • Look-and-Feel Permite schimbarea ˆ a¸i¸˘rii ¸i a modului de interactiune cu aplicatia ınf˘t sa s ¸ ¸ ˆ functie de preferintele fiec˘ruia. In JFC sunt incluse urm˘toarele: ¸a a • Componente Swing Sunt componente ce ˆ ınlocuiesc ¸i ˆ acela¸i timp extind vechiul set oferit s ın s de modelul AWT. etc. dispozitive de recunoa¸tere a vocii. Mac. s • Java 2D API Folosind Java 2D pot fi create aplicatii care utilizeaz˘ grafic˘ la un ¸ a a 299 .1 11. Java. acestea putˆnd fi s a interschimbate de c˘tre utilizator chiar la momentul executiei .

300

CAPITOLUL 11. SWING nivel avansat. Clasele puse la dispozitie permit crearea de desene com¸ plexe, efectuarea de operatii geometrice (rotiri, scal˘ri, translatii, etc.), ¸ a ¸ prelucrarea de imagini, tip˘rire, etc. a

• Drag-and-Drop Ofer˘ posibilitatea de a efectua operatii drag-and-drop ˆ a ¸ ıntre aplicatii ¸ Java ¸i aplicatii native. s ¸ • Internationalizare ¸ Internationalizarea ¸i localizarea aplicatiilor sunt dou˘ facilit˘¸i extrem ¸ s ¸ a at de importante care permit dezvoltarea de aplicatii care s˘ poat˘ fi con¸ a a figurate pentru exploatarea lor ˆ diverse zone ale globului, utilizˆnd ın a limba ¸i particularit˘¸ile legate de formatarea datei, numerelor sau a s at monedei din zona respectiv˘. a In aceste capitol vom face o prezentare scurt˘ a componentelor Swing, a deoarece prezentarea detaliata a tuturor facilit˘¸ilor oferite de JFC ar oferi at suficient material pentru un volum de sine st˘t˘tor. aa

11.1.2

Swing API

Unul din principalele deziderate ale tehnologiei Swing a fost s˘ pun˘ la a a dispozitie un set de componente GUI extensibile care s˘ permit˘ dezvoltarea ¸ a a rapid˘ de aplicatii Java cu interfat˘ grafic˘ competitiv˘ din punct de vedere a ¸ ¸a a a comercial. Pentru a realiza acest lucru, API-ul oferit de Swing este deosebit de complex avˆnd 17 pachete ˆ care se g˘sesc sute de clase ¸i interfete. Lista a ın a s ¸ complet˘ a pacehetelor din distributia standard 1.4 este dat˘ ˆ tabelul de a ¸ a ın mai jos: javax.accessibility javax.swing.text.html javax.swing.plaf.basic javax.swing.border javax.swing.text.rtf javax.swing.plaf.multi javax.swing.event javax.swing.undo javax.swing.text javax.swing.plaf javax.swing javax.swing.text.parser javax.swing.plaf.metal javax.swing.colorchooser javax.swing.tree javax.swing.table javax.swing.filechooser

11.1. INTRODUCERE

301

Evident, nu toate aceste pachete sunt necesare la dezvolatarea unei aplicatii, ¸ cel mai important ¸i care contine componentele de baz˘ fiind javax.swing. s ¸ a

Componentele folosite pentru crearea interfetelor grafice Swing pot fi gru¸ pate astfel: • Componente atomice JLabel, JButton, JCheckBox, JRadioButton, JToggleButton, JScrollBar, JSlider, JProgressBar, JSeparator • Componente complexe JTable, JTree, JComboBox, JSpinner, JList, JFileChooser, JColorChooser, JOptionPane • Componente pentru editare de text JTextField, JFormattedTextField, JPasswordField, JTextArea, JEditorPane, JTextPane • Meniuri JMenuBar, JMenu, JPopupMenu, JMenuItem, JCheckboxMenuItem, JRadioButtonMenuItem • Containere intermediare JPanel, JScrollPane, JSplitPane, JTabbedPane, JDesktopPane, JToolBar • Containere de nivel ˆ ınalt JFrame, JDialog, JWindow, JInternalFrame, JApplet

11.1.3

Asem˘n˘ri ¸i deosebiri cu AWT a a s

Nu se poate spune c˘ Swing ˆ a ınlocuie¸te modelul AWT ci ˆ extinde pe acesta s ıl din urm˘ ad˘ugˆndu-i noi componente care fie ˆ a a a ınlocuiesc unele vechi fie sunt cu totul noi. O conventie ˆ general respectat˘ este prefixarea numelui unei ¸ ın a clase AWT cu litera ”J” pentru a denumi clasa corespondent˘ din Swing. a Astfel, ˆ locul clasei java.awt.Button putem folosi javax.swing.JButton, ın ˆ loc de java.awt.Label putem folosi javax.swing.JLabel, etc. Este recoın mandat ca o aplicatie cu interfat˘ grafic˘ s˘ foloseasc˘ fie componente AWT, ¸ ¸a a a a fie Swing, amestecarea lor fiind mai putin uzual˘. ¸ a

302

CAPITOLUL 11. SWING

Aplicatiile GUI vor avea ˆ continuare nevoie de pachetul java.awt deoarece ¸ ın aici sunt definite unele clase utilitare cum ar fi Color, Font, Dimension, etc. care nu au fost rescrise ˆ Swing. ın De asemenea, pachetul java.awt.event r˘mˆne ˆ continuare esential a a ın ¸ pentru tratarea evenimentelor generate atˆt de componente AWT cˆt ¸i de a a s cele din Swing. Pe lˆng˘ acesta mai poate fi necesar ¸i javax.swing.event a a s care descrie tipuri de evenimente specifice unor componente Swing, mecanismul de tratare a lor fiind ˆ a acela¸i ca ˆ AWT. ıns˘ s ın Pozitionarea componentelor este preluat˘ din AWT, fiind ad˘ugate ˆ a ¸ a a ıns˘ noi clase care descriu gestionari de pozitionare ˆ completarea celor exis¸ ın tente, cum ar fi BoxLayout ¸i SpringLayout. Difer˘ ˆ a modul de lucru cu s a ıns˘ containere, dup˘ cum vom vedea ˆ sectiunea dedicat˘ acestora. a ın ¸ a Majoritatea componentelor Swing care permit afi¸area unui text ca parte s a reprezent˘rii lor GUI pot specifica acel text fie ˆ mod normal folosind un a ın anumit font ¸i o anumit˘ culoare ce pot fi setate cu metodele setFont ¸i s a s setColor, fie prin intermediul limbajului HTML. Folosirea HTML aduce o flexibilitatea deosebit˘ ˆ realizarea interfetei grafice, ˆ a ın ¸ ıntrucˆt putem aplica a format˘ri multiple unui text, descompunerea acestuia pe mai multe linii, etc., a singurul dezavantaj fiind ˆ ıncetinirea etapei de afi¸are a componentelor. s JButton simplu = new JButton("Text simplu"); JButton html = new JButton( "<html><u>Text</u> <i>formatat</i></html>"); S˘ descriem o aplictie simpl˘ folosind AWT ¸i apoi Swing, pentru a ne a ¸ a s crea o prim˘ impresie asupra diferentelor ¸i asem˘n˘rilor dintre cele dou˘ a ¸ s a a a modele. Listing 11.1: O aplicatie simpl˘ AWT ¸ a
import java . awt .*; import java . awt . event .*; public class ExempluAWT extends Frame implements ActionListener { public ExempluAWT ( String titlu ) { super ( titlu ) ; setLayout ( new FlowLayout () ) ; add ( new Label ( " Hello AWT " ) ) ; Button b = new Button ( " Close " ) ; b . addActionListener ( this ) ;

11.1. INTRODUCERE
add ( b ) ; pack () ; show () ; } public void actionPerformed ( ActionEvent e ) { System . exit (0) ; } public static void main ( String args []) { new ExempluAWT ( " Hello " ) ; } }

303

Listing 11.2: Aplicatia rescris˘ folosind Swing ¸ a
import javax . swing .*; import java . awt .*; import java . awt . event .*; public class ExempluSwing extends JFrame implements ActionListener { public ExempluSwing ( String titlu ) { super ( titlu ) ; // Metoda setLayout nu se aplica direct ferestrei getContentPane () . setLayout ( new FlowLayout () ) ; // Componentele au denumiri ce incep cu litera J // Textul poate fi si in format HTML getContentPane () . add ( new JLabel ( " < html > <u > Hello </ u > <i > Swing </ i > </ html > " ) ) ; JButton b = new JButton ( " Close " ) ; b . addActionListener ( this ) ; // Metoda add nu se aplica direct ferestrei getContentPane () . add ( b ) ; pack () ; show () ; } public void actionPerformed ( ActionEvent e ) { // Tratarea evenimentelor se face ca in AWT System . exit (0) ; } public static void main ( String args []) { new ExempluSwing ( " Hello " ) ; }

304
}

CAPITOLUL 11. SWING

11.2

Folosirea ferestrelor

Pentru a fi afi¸ate pe ecran componentele grafice ale unei aplicatii trebuie s ¸ plasate pe o suprafat˘ de afi¸are (container). Fiecare component˘ poate fi ¸a s a continut˘ doar ˆ ¸ a ıntr-un singur container, ad˘ugarea ei pe o supraft˘ nou˘ a ¸a a de afi¸are determinˆnd eliminarea ei de pe vechiul container pe care fusese s a plasat˘. Intrucˆt containerele pot fi ˆ a a ıncapsulate ˆ alte containere, o comın ponent˘ va face parte la un moment dat dintr-o ierarhie. R˘d˘cina acestei a a a ierarhii trebuie s˘ fie un a¸a numit container de nivel ˆ a s ınalt, care este reprezentat de una din clasele JFrame, JDialog sau JApplet. Intrucˆt de appleturi a ne vom ocupa separat, vom analiza ˆ continuare primele dou˘ clase. ın a In general orice aplicatie Java independent˘ bazat˘ pe Swing contine ¸ a a ¸ cel putin un container de nivel ˆ ¸ ınalt reprezentat de fereastra principal˘ a a programului, instant˘ a clasei JFrame. ¸a Simplificat, un obiect care reprezint˘ o fereastr˘ Swing contine o zon˘ a a ¸ a care este rezervat˘ barei de meniuri ¸i care este situat˘ de obieci ˆ partea sa a s a ın superioar˘ ¸i corpul ferestrei pe care vor fi plasate componentele. Imaginea as de mai jos pune ˆ evident˘ aceast˘ separare, valabil˘ de altfel pentru orice ın ¸a a a container de nivel ˆ ınalt:

Corpul ferestrei este o instant˘ a clasei Container ce poate fi obtinut˘ cu ¸a ¸ a metoda getContentPane. Plasarea ¸i aranjarea componentelor pe suprafata s ¸

11.2. FOLOSIREA FERESTRELOR

305

ferestrei se va face deci folosind obiectul de tip Container ¸i nu direct fereass tra. A¸adar, de¸i este derivat˘ din Frame, clasa JFrame este folosit˘ ˆ s s a a ıntr-un mod diferit fat˘ de p˘rintele s˘u: ¸a a a Frame f = new Frame(); f.setLayout(new FlowLayout()); f.add(new Button("OK")); JFrame jf = new JFrame(); jf.getContentPane().setLayout(new FlowLayout()); jf.getContentPane().add(new JButton("OK")); Spre deosebire de Frame, un obiect JFrame are un comportament implicit la ˆ ınchiderea ferestrei care const˘ ˆ ascunderea ferestrei atunci cˆnd utilizaa ın a torul apas˘ butonul de ˆ a ınchidere. Acest comportament poate fi modificat prin apelarea metodei setDefaultCloseOperation care prime¸te ca argus ment diverse constante ce se g˘sesc fie ˆ clasa WindowConstants, fie chiar a ın ˆ JFrame. ın jf.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); jf.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Ad˘ugarea unei bare de meniuri se realizeaz˘ cu metoda setJMenuBar, a a care prime¸te o instant˘ de tip JMenuBar. Crearea meniurilor este similar˘ s ¸a a cu modelul AWT.

11.2.1

Ferestre interne

Din punctul de vedere al folosirii ferestrelor, aplicatiile pot fi ˆ artite ˆ ¸ ımp˘ ¸ ın dou˘ categorii: a • SDI (Single Document Interface) • MDI (Multiple Document Interface) Programele din prima categorie gestioneaz˘ la un moment dat o singur˘ a a fereastr˘ ˆ care se g˘sesc componentele cu care interactioneaz˘ utilizatorul. a ın a ¸ a In a doua categorie, fereastra principal˘ a aplicatiei ˆ a ¸ ınglobeaz˘ la rˆndul ei a a alte ferestre, uzual cu functionalit˘¸i similare, ce permit lucrul concurent pe ¸ at mai multe planuri.

306

CAPITOLUL 11. SWING

In Swing, clasa JInternalFrame pune la dispozitie o modalitate de a ¸ crea ferestre ˆ cadrul altor ferestre. Ferestrele interne au aproximativ aceea¸i ın s ˆ a¸i¸are ¸i functionalitate cu ferestrele de tip JFrame, singura diferent˘ fiind ınf˘t s s ¸ ¸a modul de gestionare a acestora. Uzual, obiectele de tip JInternalFrame vor fi plasate pe un container de tip DesktopPane, care va fi apoi plasat pe o fereastr˘ de tip JFrame. a Folosirea clasei DesktopPane este necesar˘ deoarece aceasta ”¸tie” cum s˘ a s a gestioneze ferestrele interne, avˆnd ˆ vedere c˘ acestea se pot suprapune ¸i a ın a s la un moment dat doar una singur˘ este activ˘. a a Exemplul urm˘tor pune ˆ evident˘ modelul general de creare ¸i afi¸are a ın ¸a s s a ferestrelor interne: Listing 11.3: Folosirea ferestrelor interne
import javax . swing .*; import java . awt .*; class FereastraPrinci pal a extends JFrame { public Fereastra Pr i nc i p al a ( String titlu ) { super ( titlu ) ; setSize (300 , 200) ; s e tD e f au l t C lo s e O p e r a t i o n ( JFrame . EXIT_ON_CLOSE ) ; FereastraInterna fin1 = new FereastraInterna () ; fin1 . setVisible ( true ) ; FereastraInterna fin2 = new FereastraInterna () ; fin2 . setVisible ( true ) ; JDesktopPane desktop = new JDesktopPane () ; desktop . add ( fin1 ) ; desktop . add ( fin2 ) ; setContentPane ( desktop ) ; fin2 . moveToFront () ; } } class FereastraInterna extends JInternalFrame { static int n = 0; // nr . de ferestre interne static final int x = 30 , y = 30; public FereastraInterna () { super ( " Document # " + (++ n ) ,

11.3. CLASA JCOMPONENT
true , // resizable true , // closable true , // maximizable true ) ; // iconifiable setLocation ( x *n , y * n ) ; setSize ( new Dimension (200 , 100) ) ;

307

} } public class TestInternalFrame { public static void main ( String args []) { new FereastraPrincipala ( " Test ferestre interne " ) . show () ; } }

Ferestrele create de acest program vor ar˘ta ca ˆ figura de mai jos: a ın

11.3

Clasa JComponent

JComponent este superclasa tuturor componentelor Swing, mai putin a celor ¸ care descriu containere de nivel ˆ ınalt JFrame, JDialog, JApplet. Deoarece JComponent extinde clasa Container, deci ¸i Component, ea mo¸tene¸te functionalitatea s s s ¸ general˘ a containerelor ¸i componentelor AWT, furnizˆnd bineˆ ¸eles ¸i o sea s a ınt s rie ˆ ıntreag˘ de noi facilit˘¸i. a at Dintre nout˘¸ile oferite de JComponent amintim: at • ToolTips Folosind metoda setToolTip poate fi ata¸at unei componente un text s cu explicatii legate de componenta respectiv˘. Cˆnd utilizatorul trece ¸ a a

308

CAPITOLUL 11. SWING cu mouse-ul deasupra componentei va fi afi¸at, pentru o perioad˘ de s a timp, textul ajut˘tor specificat. a

• Chenare Orice component˘ Swing poate avea unul sau mai multe chenare. Specia ficarea unui chenar se realizeaz˘ cu metoda setBorder. a • Suport pentru plasare ¸i dimensionare s Folosind metodele setPreferredSize, setMinimumSize, setMaximumSize, setAlignmentX, setAlignmentY pot fi controlati parametrii folositi ¸ ¸ de gestionarii de pozitionare pentru plasarea ¸i dimensionarea automat˘ ¸ s a a componentelor ˆ cadrul unui container. ın • Controlul opacit˘¸ii at Folosind metoda setOpaque vom specifica dac˘ o component˘ trebuie a a sau nu s˘ deseneze toti pixelii din interiorul s˘u. Implicit, valoarea a ¸ a propriet˘¸ii de opacitate este false, ceea ce ˆ at ınseamn˘ c˘ este posibil a a s˘ nu fie desenati unii sau chiar toti pixelii, permitˆnd pixelilor de sub a ¸ ¸ ¸a component˘ s˘ r˘mˆn˘ vizibili (componenta nu este opac˘). Valoarea a a a a a a propriet˘¸ii pentru clasele derivate din JComponent depinde ˆ general at ın de Look-and-Feel-ul folosit. • Asocierea de actiuni tastelor ¸ Pentru componentele Swing exist˘ posibilitatea de specifica anumite a actiuni care s˘ se execute atunci cˆnd utilizatorul apas˘ o anumit˘ ¸ a a a a combinatie de taste ¸i componenta respectiv˘ este activ˘ (are focus¸ s a a ul). Aceast˘ facilitate simplific˘ varianta initial˘ de lucru, ¸i anume a a ¸ a s tratarea evenimentelor de tip KeyEvent printr-un obiect KeyListener. • Double-Buffering Tehnica de double-buffering, care implic˘ desenarea componentei ˆ a ın memorie ¸i apoi transferul ˆ s ıntregului desen pe ecran, este implementat˘ a automat de componentele Swing, spre deosebire de cele AWT unde trebuia realizat˘ manual dac˘ era cazul. a a Exemplul urm˘tor ilustreaz˘ modul de folosire a cˆtorva dintre facilit˘¸ile a a a at amintite mai sus: Listing 11.4: Facilit˘¸i oferite de clasa JComponent at

setLayout ( new FlowLayout () ) . raised = BorderFactory . setBorder ( lowered ) . add ( panel ) . c r e a t e L o w e r e d B e v e l B o r d e r () . javax . swing . java . blue ) .200) ) . label2 . setBorder ( raised ) . JButton btn2 = new JButton ( " Transparent " ) . // ToolTips label1 . setBackground ( Color .*. setOpaque ( true ) . s e tD e f au l t C lo s e Op e r at i o n ( JFrame . event .3.11. border . raised . add ( btn1 ) . panel . panel . swing . // implicit panel . c re at eT it led Bo rd er ( " Borders " ) . title = BorderFactory . lowered = BorderFactory . final JPanel panel = new JPanel () . getContentPane () . JLabel label1 = new JLabel ( " Lowered " ) . JLabel label2 = new JLabel ( " Raised " ) . add ( btn2 ) . panel .*. btn1 . add ( label2 ) . setOpaque ( false ) . java . awt . add ( label1 ) . setToolTipText ( " Eticheta coborata " ) . CLASA JCOMPONENT import import import import javax . EXIT_ON_CLOSE ) . setToolTipText ( " Eticheta ridicata " ) .*. setBorder ( title ) . panel . setPreferredSize ( new Dimension (400 . panel . label1 . awt . 309 class Fereastra extends JFrame { public Fereastra ( String titlu ) { super ( titlu ) . label2 . panel . .*. TitledBorder title . // Controlul opacitatii JButton btn1 = new JButton ( " Opaque " ) . btn2 . c r e a t e R a i s e d B e v e l B o r d e r () . getContentPane () . // Folosirea chenarelor Border lowered .

new AbstractAction () { private Color color = Color . // Textul poate fi HTML btn2 . blue : Color .4 11. getKeyStroke ( " F2 " ) . color = ( color == Color . } } 11. SWING btn1 . " schimbaCuloare " ) . } } public class TestJComponent { public static void main ( String args []) { new Fereastra ( " Facilitati JComponent " ) . // Asocierea unor actiuni ( KeyBindings ) /* Apasarea tastei F2 cand focusul este pe butonul al doilea va determina schimbarea culorii panelului */ btn2 . pack () .5 Arhitectura modelului Swing Folosirea modelelor Modelul Swing este bazat pe o arhitectur˘ asem˘n˘toare cu MVC (modela a a view-controller). ¸ . put ( " schimbaCuloare " . show () . getActionMap () . put ( KeyStroke . setToolTipText ( " < html > <b > Apasati < font color = red > F2 </ font > " + " cand butonul are <u > focusul </ u > " ) . Arhitectura MVC specific˘ descompunerea unei aplicatii a ¸ vizuale ˆ trei p˘rti separate: ın a¸ • Modelul . red ? Color .care va reprezenta datele aplicatiei. btn2 . red . red ) . getInputMap () .310 CAPITOLUL 11. setBackground ( color ) . public void actionPerformed ( ActionEvent e ) { panel . setToolTipText ( " Buton opac " ) . } }) .

JTextPane. ˆ Swing p˘rtile de prezentare ¸i control au fost cuın a¸ s plate deoarece exista o leg˘tur˘ prea strˆns˘ ˆ a a a a ıntre ele pentru a fi concepute ca entit˘¸i separate. ˆ a are posibilitatea a ¸ ıns˘ de a-l ˆ ınlocui cu unul nou atunci cˆnd este cazul. JRadioButtomMenuItem JComboBox ComboBoxModel BoundedRangeModel JProgressBar. ˆ care datele componentelor (modelul) sunt separate de ın reprezentarea lor vizual˘. JMenu. JPasswordField Fiecare component˘ are un model initial implicit. arhitectura Swing este de fapt o arhitectur˘ at s a cu model separabil. Aceast˘ abordare este logic˘ ¸i din perspectiva a a a s faptului c˘. Pentru a realiza separarea modelului de prezentare. JScrollBarm. JRadioButton. Din motive practice. fiec˘rui obiect corea spunz˘tor unei clase ce descrie o component˘ Swing ˆ este asociat un obiect a a ıi care gestioneaz˘ datele sale ¸i care implementeaz˘ o interfat˘ care reprezint˘ a s a ¸a a modelul componentei respective.transformarea actiunilor utilizatorului asupra componen¸ telor vizuale ˆ evenimente care s˘ actualizeze automat modelul acesın a tora (datele). ˆ general.modul de reprezentare vizual˘ a datelor. componente cu reprezent˘ri diferite pot avea acela¸i tip de model. FOLOSIREA MODELELOR • Prezentarea . JCheckBox.5. dar a s exist˘ ¸i componente care au asociate mai multe modele: as Model ButtonModel Component˘ a JButton. JCheckBoxMenuItem. JTextArea. JTextField. Metodele care acceseaz˘ a a . JSlider JTabbedPane SingleSelectionModel ListModel JList ListSelectionModel JList JTable TableModel JTable TableColumnModel JTree TreeModel JTree TreeSelectionModel Document JEditorPane.11. Dup˘ cum se observ˘ din tabelul de mai a a jos. JMenuItem. A¸adar. JToggleButton. modul de concepere a unei aplicatii trebuie s˘ fie oria ın ¸ a entat asupra reprezent˘rii ¸i manipul˘rii informatiilor ¸i nu asupra interfetei a s a ¸ s ¸ grafice cu utilizatorul. a 311 • Controlul .

add ( lst . model2 . swing . getContentPane () . border . CENTER ) . " galben " . " blue " }. int tipModel = 1. public Fereastra ( String titlu ) { super ( titlu ) . getContentPane () . event . EXIT_ON_CLOSE ) . setModel ( model1 ) . BorderLayout . awt . swing .*. cu argumente specifice fiec˘rei componente ˆ parte. s e tD e f au l t C lo s e O p e r a t i o n ( JFrame . class Fereastra extends JFrame implements ActionListener { String data1 [] = { " rosu " . addActionListene r ( this ) .*. SOUTH ) .312 CAPITOLUL 11. In functie a s ¸ de necesit˘¸i. String data2 [] = { " red " . btn . java . Listing 11.*. " yellow " . // La apasara butonului schimbam modelul JButton btn = new JButton ( " Schimba modelul " ) . Crearea unei clase care s˘ reprezinte a ın a un model se va face extinzˆnd interfata corespunz˘toare ¸i implementˆnd a ¸ a s a metodele definite de aceasta sau extinzˆnd clasa implicit˘ oferit˘ de API-ul a a a Swing ¸i supradefinind metodele care ne intereseaz˘. Pentru modelele mai s a complexe. JTree sau JList exist˘ a clase abstracte care implementeaz˘ interfata ce descrie modelul respectiv De a ¸ exemplu. javax .*. . // Cream obiectele corespunzatoare celor doua modele model1 = new Model1 () . " albastru " }. interfata model a clasei JList este ListModel care este imple¸ mentat˘ de clasele DefaultListModel ¸i AbstractListModel.5: Folosirea mai multor modele pentru o componenta import import import import javax . respectiv getModel. awt . add ( btn . lst . BorderLayout . java . cum ar fi cele asociate claselor JTable. JList lst . oricare din aceste clase poate fi extins˘ pentru a crea un nou at a model. // Lista initiala nu are nici un model lst = new JList () . model2 = new Model2 () . ListModel model1 . SWING modelul unui obiect sunt: setModel.

} public Object getElementAt ( int index ) { return data2 [ index ]. tipModel = 1. } } Multe componente Swing furnizeaz˘ metode care s˘ obtin˘ starea obieca a ¸ a tului f˘r˘ a mai fi nevoie s˘ obtinem instanta modelului ¸i s˘ apel˘m metodele aa a ¸ ¸ s a a . setModel ( model2 ) . } } class Model2 extends Abst ractLis tModel { public int getSize () { return data2 .11. } } } public class TestModel { public static void main ( String args []) { new Fereastra ( " Test Model " ) . FOLOSIREA MODELELOR 313 pack () . } else { lst . } public void actionPerformed ( ActionEvent e ) { if ( tipModel == 1) { lst . show () . length . setModel ( model1 ) . tipModel = 2. } } // Clasele corespunzatoare celor doua modele class Model1 extends Abst ractLis tModel { public int getSize () { return data1 . } public Object getElementAt ( int index ) { return data1 [ index ].5. length .

5. Acest lucru se realizeaz˘ prin intefata a ¸ ChangeListener iar evenimentele sunt de tip ChangeEvent. ¸ ¸ a ın a Inregistrarea ¸i eliminarea obiectelor de tip listener se realizeaz˘ cu metodele s a addChangeListener. singura informatie continut˘ ˆ eveniment fiind componenta surs˘. // Trebuie sa interogam sursa asupra schimbarii .314 CAPITOLUL 11. In multe situatii ˆ a. mai ¸ ıns˘ ales pentru clase cum ar fi JTable sau JTree.1 Tratarea evenimentelor Modelele componentelor trebuie s˘ notifice aparitia unor schimb˘ri ale datelor a ¸ a gestionate astfel ˆ at s˘ poat˘ fi reactualizat˘ prezentarea lor sau s˘ fie exıncˆ a a a a ecutat un anumti cod ˆ cadrul unui obiect de tip listener.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { // Sursa este de tip BoundedRangeModel BoundedRangeModel m = (BoundedRangeModel)e. ButtonModel ¸i a a s SingleSelectionModel.Modelele trimit un eveniment prin care sunt informati ascult˘torii c˘ a survenit o anumit˘ schimbare a datelor. modelele care suport˘ aceast˘ abordare fiind BoundedRangeModel. Model BoundedRangeModel ButtonModel SingleSelectionModelModel Listener ChangeListener ChangeListener ChangeListener Tip Eveniment ChangeEvent ChangeEvent ChangeEvent Interfata ChangeListener are o singur˘ metod˘: ¸ a a public void stateChanged(ChangeEvent e). Informativ (lightweight) . SWING acesteia. model. f˘r˘ ¸ a a a aa a include ˆ eveniment detalii legate de schimbarea survenit˘. aceast˘ ın a notificare este realizat˘ ˆ dou˘ moduri: a ın a 1. respectiv removeChangeListener. Un exemplu este metoda getValue a clasei JSlider care este de fapt un apel de genul getModel(). JSlider slider = new JSlider().getSource(). folosirea modelelor aduce flexibilitate sporit˘ programului ¸i este recomandat˘ utilizarea lor. a s a 11. BoundedRangeModel model = slider. Obiectele ın a de tip listener vor trebui s˘ apeleze metode specifice componentelor pena tru a afla ce anume s-a schimbat.getModel(). In Swing.getValue().

println("Valoare noua: " + s. "albastru"). Consistent(statefull) .getSelectionModel(). sModel. Model ListModel ListSelectionModel ComboBoxModel TreeModel TreeSelectionModel TableModel TableColumnModel Document Document Listener ListDataListener ListSelectionListener ListDataListener TreeModelListener TreeSelectionListener TableModelListener TableColumnModelListener DocumentListener UndoableEditListener Tip Eveniment ListDataEvent ListSelectionEvent ListDataEvent TreeModelEvent TreeSelectionEvent TableModelEvent TableColumnModelEvent DocumentEvent UndoableEditEvent Folosirea acestor interfete nu difer˘ cu nimic de cazul general: ¸ a String culori[] = {"rosu".5.getValue()). s Secventa de cod de mai sus poate fi rescris˘ astfel: ¸ a JSlider slider = new JSlider(). } }).getValue()). "galben". singura diferent˘ fat˘ de varianta anterioar˘ constˆnd ˆ faptul c˘ ın ¸a ¸a a a ın a sursa evenimentului este acum de tipul componentei ¸i nu de tipul modelului. System. slider. pentru a nu lucra direct cu instanta modelus ¸ a ¸ lui. } }). FOLOSIREA MODELELOR 315 System.println("Schimbare model: " + m.Modele pun la dispozitie interfete special¸ ¸ izate ¸i tipuri de evenimente specifice ce includ toate informatiile legate de s ¸ schimbarea datelor. unele clase permit ˆ ınregistrarea ascult˘torilor direct pentru componenta a ˆ sine. JList list = new JList(culori).addListSelectionListener( . ListSelectionModel sModel = list.out.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { // Sursa este de tip JSlider JSlider s = (JSlider)e.getSource(). 2.out. Pentru u¸urinta program˘rii.11.

JScrollBar s • Separatori: JSeparator Deoarece utilizarea acestora este ˆ general facil˘.316 CAPITOLUL 11. JRadioButton.1 Componente atomice In categoria componentelor atomice includem componentele Swing cu functionalitate ¸ simpl˘.println("Selectie curenta: " + e. Aici includem: • Etichete: JLabel • Butoane simple sau cu dou˘ st˘ri: JButton.6. • Componente pentru progres ¸i derulare: JSlider. } } }). 11. subliniind diferentele ın ¸a ¸ ¸i ˆ s ımbun˘t˘¸irile fat˘ AWT. a a JToggleButton. JCheckBox. a a a . ci vom a pune ˆ evident˘ doar aspectele specifice acestui model. mai multe butoane radio pot fi grupate folosind clasa ButtonGroup.6 Folosirea componentelor Datorit˘ complexit˘¸ii modelului Swing.swing.getValueIsAdjusting()) { System.text.6. ˆ aceast˘ secttiune nu vom ˆ a at ın a ¸ ıncerca o abordare exhaustiv˘ a modului de utilizare a tuturor componentelor. a at ¸a 11. JProgressBar.out. nu vom analiza ˆ parte ın a ın aceste componente. a c˘ror folosire este ˆ general asem˘n˘toare cu a echivalentelor din a a ın a a AWT. pentru a permite selectarea doar a unuia dintre ele. 11. SWING new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { // Schimbarea este continuta in eveniment if (!e.2 Componente pentru editare de text Componentele Swing pentru afi¸area ¸i editarea textelor sunt grupate ˆ s s ıntr-o ierarhie ce are ca r˘d˘cin˘ clasa JTextComponent din pachetul javax.getFirstIndex()).

Uzual. o component˘ de acest tip va fi inclus˘ ˆ ¸ a a ıntr-un container JScrollPane. – JPasswordField . Este folosit˘ ˆ a ımpreun˘ cu clase a utilitare pentru formatarea textelor. fiind foarte util˘ pentru citirea de a numere. corespunz˘toare tipului textului editat: a • Text simplu pe o singur˘ linie a – JTextField .6. cum ar fi NumberFormatter. etc.Permite introducerea unui text care s˘ a respecte un anumit format. MaskFormatter.Permite editarea unui text simplu. Valoarea continut˘ de o ¸ a astfel de component˘ va fi obtinut˘/setat˘ cu metodele getValue.11. ˆ locul caracterelor introduse fiind afi¸at un caracter ın s simbolic. date calendaristice. DateFormatter. etc.Permite editarea unui text simplu. cum ar fi culoarea sau fontul. a ¸ a a respectiv setValue ¸i nu cu cele uzuale getText. Textul acestora va fi ascuns. s • Text simplu pe mai multe linii – JTextArea . pe mai multe linii. clasele pot ˆ artite ˆ a a ımp˘ ¸ ın trei categorii. cum ar fi ’*’. pentru a permite navigarea pe vertical˘ a . se aplic˘ ˆ a ıntregului text ¸i nu poate fi specificat doar unei anumite s portiuni. setText.Permite editarea de parole. Orice atribut legat de stil. – JFormattedTextField . pe o singur˘ a linie. FOLOSIREA COMPONENTELOR 317 Dup˘ cum se observ˘ din imaginea de mai sus.

Dintre evenimentele ce pot fi generate amintim: • ActionEvent . ¸ a . a s • Un ’controller’. a • O reprezentare. Acest lucru este valabil pentru toate componentele Swing pentru care are sens notiunea de navigare pe orizontal˘ ¸ a sau vertical˘. s s ¸ a Exist˘ diferent fat˘ de AWT ¸i la nivelul trat˘rii evenimentelor generate a ¸ ¸a s a de componentele pentru editarea de texte. referit sub denumirea de document. tratarea evenimentelor generate de cursor ¸ s (caret). ce prime¸te ca argument un URL care poate s referi un fi¸ier text. care este responsabil˘ cu afi¸area textului.Componentele derivate din JTextField vor genera un eveniment de acest tip la ap˘sarea tastei Enter ˆ c˘suta de editare a a ın a ¸ textului. O referint˘ la model poate fi obtinut˘ cu metoda getDocument. care gestioneaz˘ starea a componentei. nici una neoferind suport intrinsec pentru aceast˘ a a operatiune. ¸a ¸ a ce returneaz˘ un obiect de tip Document. a componenta Swing avˆnd caracteristici mult mai complexe cum ar fi suport a pentru operatii de undo ¸i redo. s – JTextPane .Aceast˘ clas˘ extinde JEditorPane. SWING ¸i orizontal˘ dac˘ textul introdus nu ˆ s a a ıncape ˆ suprafata alocat˘ ın ¸ a obiectului. HTML sau RTF. Interfata care trebuie implementat˘ este ActionListener. at s Clasa JTextComponent ˆ ıncearc˘ s˘ p˘streze cˆt mai multe similitudini cu a a a a clasa TextComponent din AWT. ˆ a exist˘ diferente notabile ˆ ıns˘ a ¸ ıntre cele dou˘.318 CAPITOLUL 11. cunoscut sub numele de editor kit care permite scrierea ¸i citirea textului ¸i care permite definirea de actiuni necesare edit˘rii. Implicit.Permite afi¸area ¸i editarea de texte scrise cu stils s uri multiple ¸i care pot include imagini sau chiar diverse alet coms ponente. text/html ¸i text/rtf. Orice obiect derivat din JTextComponent este format din: • Un model. urm˘toarele tipuri de texte sunt recunoscute: a text/plain. ¸ • Text cu stil ˆ ımbog˘¸it pe mai multe linii at – JEditorPane . Una din utiliz˘rile cele mai s a simple ale acestei clase este setarea documentului ce va fi afi¸at s cu metoda setPage. etc. oferind diverse a a facilit˘¸i suplimentare pentru lucrul cu stiluri ¸i paragrafe.

apelat˘ la ad˘ugarea de noi caractere. FOLOSIREA COMPONENTELOR 319 • CaretEvent . ce contine metodele: ¸ – insertUpdate . a din care utilizatorul poate selecta unul sau mai multe.Este un eveniment comun tuturor componentelor de tip JavaBean.3 Componente pentru selectarea unor elemente In aceast˘ categorie vom include clasele care permit selectarea unor valori a (elemente) dintr-o serie prestabilit˘. a • DocumentEvent .Este evenimentul generat la deplasarea cursorului ce gestioneaz˘ pozitia curent˘ ˆ text. Clasa JList Clasa JList descrie o list˘ de elemente dispuse pe una sau mai multe coloane. a a ¸ s – changedUpdate . • PropertyChangeEvent . ¸ 11. ce contine metoda propertyChange. Interfata corespunz˘toare este Docus ın ¸ a mentListener. Interfata corespunz˘toare este Propertyat ¸ a ChangeListener. a a – removeUpdate . Acestea sunt: JList.apelat˘ dup˘ o operatiune de ¸tergere.Evenimentele de acest tip sunt generate la orice schimbare a textului.6.apelat˘ la schimbarea unor atribute legate de a stilul textului. Uzual un obiect de acest tip va fi inclus ˆ ıntr-un container de tip JScrollPane. JComboBox ¸i a s JSpinner. Interfata corespunz˘toare CaretLisa ¸ a ın ¸ a tener contine o singur˘ metod˘: caretUpdate ce va fi apelat˘ ori de ¸ a a a cˆte ori apare o schimbare.6. fiind generat la orice schimbare a unei propriet˘¸i a componentei.11. . sursa lor fiind documentul (modelul) componentei ¸i nu componenta ˆ sine.

addElement(new Integer(3)). model. oferind flexibilitate sporit˘ ˆ lua a a a ın crul cu liste. model. • Folosind un model propriu. JList lista = new JList(model). new Double(4)}. "Doi". a a a aceast˘ variant˘ este mai complex˘. uzual fiind folosit˘ extinderea clasei predefinite ¸ a AbstractListModel ¸i supradefinirea metodelor: getElementAt care s furnizeaz˘ elementul de pe o anumit˘ positie din list˘. Object elemente[] = {"Unu".addElement("Doi"). Acesta este un obiect dintr-o clas˘ ce trebuie s˘ implementeze a a interfata ListModel.320 CAPITOLUL 11. responsabil cu furnizarea elementelor listei. ModelLista model = new ModelLista(). model. . JList lista = new JList(elemente).addElement(new Double(4)). Evident. JList lista = new JList(model).addElement("Unu"). respectiv getSize a a ¸ a care trebuie s˘ returneze num˘rul total de elemente din list˘. model. SWING Initializarea unei liste se realizeaz˘ ˆ mai multe modalit˘¸i: ¸ a ın at • Folosind unul din constructorii care primesc ca argument un vector de elemente. • Folosind constructorul f˘r˘ argumente ¸i ad˘ugˆnd apoi elemente modaa s a a elului implicit listei: DefaultListModel model = new DefaultListModel(). new Integer(3).

} public void valueChanged(ListSelectionEvent e) { if (e.. int index = list. a a a ¸ a class Test implements ListSelectionListener { . } } Gestiunea articolelor selectate dintr-o list˘ se realizeaz˘ prin intermediul a a unui model. /* sau SINGLE_INTERVAL_SELECTION MULTIPLE_INTERVAL_SELECTION */ // Adaugam un ascultator ListSelectionModel model = list.SINGLE_SELECTION). .6. .getSelectedIndex(). public int getSize() { return elemente. model.addListSelectionListener(this). // Stabilim modul de selectie list..11.. Obiectele de tip JList genereaz˘ evenimente de tip ListSelectionEvent. } public Object getElementAt(int index) { return elemente[index]. new Integer(3). FOLOSIREA COMPONENTELOR 321 . new Double(4)}. class ModelLista extends AbstractListModel { Object elemente[] = {"Unu".getSelectionModel(). public Test() { . acesta fiind un obiect de tip ListSelectionModel..length. "Doi"..setSelectionMode(ListSelectionModel.getValueIsAdjusting()) return.. interfata corea ¸ spunz˘toare fiind ListSelectionListener ce contine metoda valueChanged a ¸ apelat˘ ori de cˆte ori va fi schimbat˘ selectia elementelor din list˘...

red : Color. ¸i pentru obtinerea s ¸ celor selectate la un moment dat getSelectedIndex.toString()). clasa ofer˘ metode pentru selectarea unor elemente din cadrul a programului setSelectedIndex. acesta fiind ¸i singurul permanent vizibil.black).white : Color.322 . getSelectedIndices. Implicit toate elementele ın listei sunt afi¸ate ˆ acela¸i fel. Interfata ın ¸ s ¸ ListCellRenderer contine o singur˘ metod˘ getListCellRendererCom¸ a a ponent ce returneaz˘ un obiect de tip Component.white). a class MyCellRenderer extends JLabel implements ListCellRenderer { public MyCellRenderer() { setOpaque(true).. SWING Evident. setBackground(isSelected ? Color. Clasa JComboBox Clasa JComboBox este similar˘ cu JList. boolean cellHasFocus) { setText(value. } } CAPITOLUL 11. Lista s . } } Setarea unui anumit renderer pentru o list˘ se realizeaz˘ cu metoda setCella a Renderer.. etc. ˆ a acest lucru poate fi schimbat prin crearea s ın s ıns˘ unei clase ce implementeaz˘ interfata ListCellRenderer ¸i personalizeaz˘ a ¸ s a reprezentarea elementelor listei ˆ functie de diver¸i parametri. etc. return this. O facilitate extrem de important˘ pe care o au listele este posibilitatea de a a stabili un renderer pentru fiecare articol ˆ parte. setSelectedIndices. Metoda va fi apelat˘ ˆ a a ın parte pentru reprezentarea fiec˘rui element al listei. cu deosebirea c˘ permite doar sea a lectarea unui singur articol. } public Component getListCellRendererComponent( JList list. Object value.. boolean isSelected. setForeground(isSelected ? Color. int index.

acest lucru fiind s a controlat de metoda setEditable. SpinnerNumberModel a a ¸a sau SpinnerDateModel ce pot fi utilizate. ¸ a a s s Initializarea se face dintr-un vector sau folosind un model de tipul Com¸ boBoxModel. respectiv ¸ a a predecesorul element din domeniu. JSpiner se bazeaz˘ exclusiv pe folosirea unui model. lista elementelor nefiind ˆ a vizibil˘. existˆnd o serie de clase predefinite ce implea menteaz˘ aceast˘ interfat˘ cum ar fi SpinnerListModel. a Clasa JSpinner Clasa JSpinner ofer˘ posibilitatea de a selecta o anumit˘ valoare (element) a a dintr-un domeniu prestabilit. fiecare element putˆnd fi de asemenea reprezentat diferit prin a intermediul unui obiect ce implementeaz˘ aceea¸i intefat˘ ca ¸i ˆ cazul lisa s ¸a s ın telor: ListCellRenderer. deoarece ¸a a a ın JComboBox permite ¸i editarea explicit˘ a valorii elementului. Coma ponenta contine dou˘ butoane cu care poate fi selectat urm˘torul. de exemplu: numere intregi intre 1950 si 2050. a a a a JComboBox functioneaz˘ dup˘ acelea¸i principii ca ¸i clasa JList.6.11. Acesta este un a obiect de tip SpinnerModel. Evenimentele generate de obiectele JComboBox sunt de tip ItemEvent generate la navigarea prin list˘. O diferent˘ notabil˘ const˘ ˆ modul de selectare a unui articol. FOLOSIREA COMPONENTELOR 323 celorlalte elemente este afi¸at˘ doar la ap˘sarea unui buton marcat cu o s a a s˘geat˘. . respectiv ActionEvent generate la selectarea a efectiv˘ a unui articol. ce face parte integrant˘ din component˘. Este ıns˘ a folosit atunci cˆnd domeniul din care poate fi f˘cut˘ selectia este foarte mare a a a ¸ sau chiar nem˘rginit.

Acesta este instalat automat pentru fiecare din modelele standard amintite mai sus. coloane). toate derivate din JSpinner.6. JSpinner.swing.4 Tabele Clasa JTable permite crearea de componente care s˘ afi¸eze o serie de elea s mente ˆ ıntr-un format tabelar. Object[][] elemente = { {"Ionescu". "Student"}.DateEditor. o serie de clase ¸i s a s ın s interfete necesare lucrului cu tabele se g˘sesc ˆ pachetul javax. De asemenea. tipul de date al elementelor de pe o coloan˘ este a a a de tip referint˘ ¸i poate fi oricare. a 11.324 CAPITOLUL 11. JTable tabel = new JTable(elemente. Boolean.TRUE}. s Initializarea unui tabel poate fi f˘cut˘ ˆ mai multe moduri.table. ¸ a ın acesta trebuind a¸adar importat. "Varsta". tipul selectiei fiind simplu sau compus. ¸ a a ın Cea mai simpl˘ variant˘ este s˘ folosim unul din constructorii care primesc a a a ca argumente elementele tabelului sub forma unei matrici sau a unei colectii ¸ de tip Vector ¸i denumirile capurilor de coloan˘: s a String[] coloane = {"Nume". tabelele ¸ extinzˆnd astfel functionalitatea listelor. Dup˘ cum se observ˘. Un s tabel poate fi folosit doar pentru afi¸area formatat˘ a unor date.swing. fiind reprezentat de una din clasele JSpinner. generate la schimbarea st˘rii componentei. a ¸ De¸i clasa JTable se g˘se¸te ˆ pachetul javax. articolele fiind dispuse pe linii ¸i coloane. a Evenimentele generate de obiectele de tip JSpinner sunt de tip ChangeEvent. Fiecare din editoarele amintite permite diverse format˘ri specifice.NumberEditor.ListEditor. liniile tabeluas ¸ lui pot fi marcate ca selectate. Boolean. new Integer(20).FALSE}}. {"Popescu".DefaultEditor. dar este s a posibil˘ ¸i editarea informatiei din celulele sale. In cazul ˆ care celulele tabelului sunt ¸a s ın . respectiv JSpinner. new Integer(80). SWING Componentele de acest tip permit ¸i specificarea unui anumit tip de s editor pentru valorile elementelor sale.

Uzual.FALSE}}. new Integer(80). FOLOSIREA COMPONENTELOR 325 editabile trebuie s˘ existe un editor potrivit pentru tipul elementului din a celula respectiv˘.returneaz˘ num˘rul de linii ale tabelului. s s A doua variant˘ de creare a unui tabel este prin implementarea modelua lui acestuia ˆ ıntr-o clas˘ separat˘ ¸i folosirea constructorului corespunz˘tor..11. ele fiind declarate abstracte ˆ ın clasa de baz˘): a • getRowCount .returneaz˘ num˘rul de coloane ale tabelului. } public int getRowCount() { . . a ModelTabel model = new ModelTabel(). a a a a a Modelul mai contine ¸i metoda setValueAt care poate fi folosit˘ pentru ¸ s a setarea explicit˘ a valorii unei celule. Din motive de eficient˘. care implementeaz˘ deja TableModel. a a • isCellEditable . "Varsta". public int getColumnCount() { return coloane. {"Popescu".length. "Student"}.specific˘ dac˘ o anumit˘ celul˘ este editabil˘. a a • getColumnCount .6.. a as a Interfata care descrie modelul clasei JTable este TableModel ¸i contine ¸ s ¸ metodele care vor fi interogate pentru obtinerea informatiei din tabel. Tot ceea ce trebuie s˘ facem a a este s˘ supradefinim metodele care ne intereseaz˘. ceea ce ˆ a a ınseamn˘ c˘ articole de pe o coloan˘ a a a vor fi reprezentate la fel ¸i vor avea acela¸i tip de editor. a a • getValueAt . ¸ ¸ crearea unui model se face prin extinderea clasei predefinite AbstractTableModel. cele mai utilizate fiind a a (primele trei trebuie obligatoriu supradefinite.TRUE}. class ModelTabel extends AbstractTableModel { String[] coloane = {"Nume". new Integer(20). JTable tabel = new JTable(model).returneaz˘ elementul de la o anumit˘ linie ¸i coloan˘. Object[][] elemente = { {"Ionescu". Boolean.returneaz˘ denumirea fiec˘rei coloane. Boolean. a a s a • getColumnName . implementarea acestei clase este a ¸a orientat˘ la nivel de coloan˘.

int col = e. . } } .getFirstRow()... ... } public void tableChanged(TableModelEvent e) { // Aflam celula care a fost modificata int row = e... SWING } public Object getValueAt(int row. tabel. col).length. int col) { // Doar numele este editabil return (col == 0).getValueAt(row.getModel(). public Test() { . TableModel model = (TableModel)e. } } Orice schimbare a datelor tabelului va genera un eveniment de tip TableModelEvent.326 return elemente. Object data = model.getColumn(). } public boolean isCellEditable(int row. int col) { return elemente[row][col]. CAPITOLUL 11.addTableModelListener(this)... Inreg¸ ¸ istrarea unui listener va fi f˘cut˘ pentru modelul tabelului: a a public class Test implements TableModelListener { . } public String getColumnName(int col) { return coloane[col]. Pentru a trata aceste evenimente va trebui s˘ implement˘m a a interfata TableModelListener ce contine metoda tableChanged.getSource().

. .. } public void valueChanged(ListSelectionEvent e) { if (e. fiecare a coloan˘ avˆnd asociat un obiect renderer responsabil cu crearea componena a . gestiunea liniilor selectate fiind realizat˘ prin intermediul unui a model.addListSelectionListener(this). nu neap˘rat a a consecutive. ˆ ¸a a ıntocmai ca la liste. interfata ¸ ListSelectionModel. FOLOSIREA COMPONENTELOR 327 Tabele ofer˘ posibilitatea de a selecta una sau mai multe linii. if (model..SINGLE_SELECTION). public Test() { ..6. // Stabilim modul de selectie tabel. ListSelectionModel model = (ListSelectionModel)e... model. } } } Dup˘ cum am spus. } else { int index = model. celule unei coloane vor fi reprezentare la fel.getSource().getSelectionModel()..setSelectionMode(ListSelectionModel.getMinSelectionIndex(). Tratarea evenimentelor generate de schimbarea selectiei ¸ ˆ tabel se realizeaz˘ prin ˆ ın a ınregistrarea unui ascult˘tor de tip ListSelectiona Listener: class Test implements ListSelectionListener { . Acesta este o instant˘ ce implementeaz˘...11.isSelectionEmpty()) { // Nu este nici o linie selectata .getValueIsAdjusting()) return. // Linia cu numarul index este prima selectata . // Adaugam un ascultator ListSelectionModel model = tabel..

Implicit. exist˘ o a a ıl a a serie de editoare standard pentru tipurile de date mentionate anterior. } } O situatie similar˘ o reg˘sim la nivelul editorului asociat celulelor dintr-o ¸ a a anumit˘ coloan˘. cum ar fi: Boolean. public class MyEditor extends AbstractCellEditor implements TableCellEditor { // Singura metoda abstracta a parintelui public Object getCellEditorValue() { // Returneaza valoarea editata . a Date. ImageIcon. a public class MyRenderer extends JLabel implements TableCellRenderer { public Component getTableCellRendererComponent(.) { .. Implicit. aceasta fiind responsabil˘ cu crearea componentelor ce vor a fi afi¸ate ˆ celulele unei coloane... a ce asociaz˘ un anumit tip de date cu un obiect de tip TableRenderer.. SWING tei ce descrie celulele sale. ce extinde interfata CellEditor care generalizeaz˘ conceptul ¸ a de celul˘ editabil˘ pe care ˆ vom mai reg˘si la arbori. Float. a Crearea unui editor propriu se realizeaz˘ cel mai simplu prin extinderea clasei a utilitare AbstractCellEditor. Acesta este un obiect ce implementeaz˘ interfata Treea a a ¸ CellEditor. } . dar ¸ este posibil˘ specificarea unui editor propriu cu metoda setDefaultEditor. Un astfel de obiect implementeaz˘ interfata a ¸ TableCellRenderer. restul tipurilor avˆnd o reprezentare standard ce a const˘ ˆ a ıntr-o etichet˘ cu reprezentarea obiectului ca ¸ir de caractere. Specifia s carea unui renderer propriu se realizeaz˘ cu metoda setDefaultRenderer. plus implea mentarea metodei specifice din TreeCellEditor. Number.. Double. Icon. care are o singur˘ metod˘ getTableCellRendera a erComponent. exist˘ o serie de tipuri de date s ın a cu reprezent˘ri specifice. return this..328 CAPITOLUL 11. care implementeaz˘ CellEditor.

DefaultMutableTreeNode root = new DefaultMutableTreeNode(text). FOLOSIREA COMPONENTELOR // Metoda definita de TableCellEditor public Component getTableCellEditorComponent(.) { // Returneaza componenta de tip editor . ¸ a ın Clasa care modeleaz˘ notiunea de nod al arborelui este DefaultMutablea ¸ TreeNode..5 Arbori Clasa JTree permite afi¸area unor elemente ˆ s ıntr-o manier˘ ierarhic˘.. ¸ ın a La nivel structural. un arbore este format dintr-o r˘d˘cin˘. } } 329 11.tree. informatia ˆ sine fiind manipulat˘ prin intermediul unui model. o serie de clase ¸i s a s ın s interfete necesare lucrului cu arbori se g˘sesc ˆ pachetul javax. instantierea unui s a a ¸ obiect de tip JTree cu r˘d˘cina creat˘ ¸i ad˘ugarea apoi de noduri frunz˘ ca a a as a a fii ai unor noduri existente.swing. DefaultMutableTreeNode siruri = ..6.swing. String text = "<html><b>Radacina</b></html>". Ca a a orice component˘ Swing netrivial˘. Crearea a unui arbore presupune a¸adar crearea unui nod (r˘d˘cina). aceasta fiind folosit˘ pentru toate tipurile de noduri. ¸ s a De¸i clasa JTree se g˘se¸te ˆ pachetul javax..11. un obiect JTree reprezint˘ doar o imagine a a a a datelor. noduri interne a a a care au cel putin un fiu ¸i noduri frunz˘ . DefaultMutableTreeNode numere = new DefaultMutableTreeNode("Numere").care nu mai au nici un descendent.6.

} . este posibil˘ specificarea unui text ˆ format HTML ¸ a ın ca valoare a unui nod. nodurile arborelui pot fi de tipuri diferite.addTreeSelectionListener(this).330 CAPITOLUL 11.add(numere). ¸ Scopul unei componente de tip arbore este ˆ general selectarea unui nod ın al ierarhiei. i++) { numere... root. JTree tree = new JTree(root). reprezentarea a a lor implicit˘ fiind obtinut˘prin apelarea metodei toString pentru obiectului a ¸ a continut. de tip TreeSelectionListener.SINGLE_TREE_SELECTION). Dac˘ varianta ad˘ug˘rii explicite a nodurilor nu este potrivit˘.. siruri.. ˆ aceast˘ situatie interfata corea ın a ¸ ¸ spunz˘toare fiind TreeSelectionModel. // Stabilim modul de selectie tree. } root. // Adaugam un ascultator tree. public Test() { .getSelectionModel(). Ca ¸i ˆ cazul listelor sau a tabelelor. care s˘ trateze evenimentele a generate la schimbarea selectiei ˆ arbore.setSelectionMode( TreeSelectionModel.add(new DefaultMutableTreeNode(new Integer(i))).add(siruri). se poate a a a a implementa o clas˘ care s˘ descrie modelul arborelui. acesta fiind reprezentat ca atare.. Dup˘ cum se observ˘. gestiunea elementelor s ın selectate se realizeaz˘ printr-un model. ¸ ın class Test implements TreeSelectionListener { . Aceasta trebuie s˘ a a a implementeze intefata TreeModel. . Arborii permit ˆ a ınregistrarea unor obiecte listener. De asemenea.add(new DefaultMutableTreeNode("Sirul " + i)).. i<3. SWING new DefaultMutableTreeNode("Siruri"). for(int i=0.

// sau "Horizontal".11.putClientProperty("JTree. ImageIcon closed = createImageIcon("img/closed. ın ¸ Exist˘ ˆ a ¸i diverse metode de a schimba ˆ a¸i¸area unui arbore f˘r˘ s˘ a ıns˘ s ınf˘t s aa a cre˘m noi clase de tip TreeCellRenderer. ImageIcon open = createImageIcon("img/open. // Obtinem informatia din nod Object nodeInfo = node.. a a a • putClientProperty . cea folosit˘ a ¸ a implicit fiind DefaultTreeCellRenderer.Stabile¸te diverse propriet˘¸i.lineStyle". "Angled").Specific˘ dac˘ nodurile de pe primul nivel au a a simboluri care s˘ permit˘ expandarea sau restrˆngerea lor.Specific˘ dac˘ r˘d˘cina e vizibil˘ sau nu. Aceasta implementeaz˘ interfata TreeCellRenderer. a a a a a • setShowsRootHandles . Prin implementarea interfetei ¸ sau extinderea clasei implicite pot fi create modalit˘¸i de personalizare a at nodurilor arborelui ˆ functie de tipul sau valoarea acestora.gif"). .getLastSelectedPathComponent().gif"). "None" • Specificarea unei iconite pentru nodurile frunz˘ sau interne: ¸ a ImageIcon leaf = createImageIcon("img/leaf. FOLOSIREA COMPONENTELOR public void valueChanged(TreeSelectionEvent e) { // Obtinem nodul selectat DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.. } } 331 Fiecare nod al arborelui este reprezentar prin intermediul unei clase renderer. if (node == null) return.gif"). cum ar fi modul s at de reprezentare a relatiilor (liniilor) dintre nodurile p˘rinte ¸i fiu: ¸ a s tree. Acestea sunt: a • setRootVisible . .6.getUserObject().

6. acesta putˆnd fi schimbat ˆ a chiar ˆ momentul construirii a ıns˘ ın . Containere de nivel ˆ ınalt .setClosedIcon(closed). s a a a ¸ 2. JApplet ¸i reprezint˘ r˘d˘cinile ierarhiilor de componente ale unei aplicatii. Superclasa componentelor de acest tip este Container. 11. containerele reprezint˘ suprafet de afi¸are pe care pot fi a s a ¸ s plasate ale componente. putˆnd a ¸ a fi imbricate. clas˘ despre care am mai discutat ˆ a ın capitolul dedicat modeluli AWT. renderer. fiind folosit s ¸ s pentru gruparea mai multor componente Swing ¸i plasarea lor ˆ s ımpreun˘ a pe o alt˘ suprafat˘ de afi¸are. SWING DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(). renderer.setLeafIcon(leaf).332 CAPITOLUL 11. Containerele pot fi ˆ artite ˆ dou˘ categorii: ımo˘ ¸ ın a 1.Acestea sunt JFrame. renderer.setCellRenderer(renderer). Containere intermediare .Reprezint˘ suprafete de afi¸are cu ajua ¸ s torul c˘rora pot fi organizate mai eficient componentele aplicatiei. eventual chiar alte containere.setOpenIcon(open). Gestionarul de pozitionare implicit este a ¸a s ¸ FlowLayout. tree. JDialog. Cele mai importante clase care descriu astfel de containere sunt: – JPanel – JScrollPane – JTabbedPane – JSplitPane – JLayeredPane – JDesktopPane – JRootPane JPanel are aceea¸i functionalitate ca ¸i clasa Panel din AWT.6 Containere Dup˘ cum ¸tim.

getContentPane().add(new JButton("OK")). deoarece nu mai este construit si un obiect de tip FlowLayout (implicit) */ p. Ad˘ugarea de compoa nente se realizeaz˘ ca pentru orice container. JList lista = new JList(elemente). FOLOSIREA COMPONENTELOR 333 obiectului JPanel sau ulterior cu metoda setLayout. JScrollPane sp = new JScrollPane(lista).add(sp). i<100.6. JScrollPane este o clas˘ foarte important˘ ˆ arhitectura modelului a a ın Swing.add(new JLabel("Hello")).. folosind metoda add.. frame. selectarea s ¸ s . nici o component˘ Swing neoferind suport intrinsec pentru aceast˘ a a a operatie. for(int i=0.11. deoarece ofer˘ suport pentru derularea pe orizontal˘ ¸i vertical˘ a a a s a componentelor a c˘ror reprezentare complet˘ nu ˆ a a ıncape ˆ suprafata asoın ¸ ciat˘. ¸ String elemente[] = new String[100]. . a JPanel p = new JPanel(new BorderLayout()). /* Preferabil. pe acela¸i spatiu de afi¸are. p. a uzual panouri (obiecte de tip JPanel). i++) elemente[i] = "Elementul " + i. JTabbedPane este util˘ pentru suprapunerea mai multor containere.

tabbedPane. "Aici avem o eticheta").VK_1).addTab("Tab 2". KeyEvent.setMnemonicAt(0. icon. JComponent panel1 = new JPanel(). Ca functionalitate. "Doi". . "Aici avem un buton"). JComponent panel2 = new JPanel().VK_2). JList list = new JList(elem). panel2. icon.add(new JLabel("Hello")).setMnemonicAt(1. JSplitPane permite crearea unui container care contine dou˘ compo¸ a nente dispuse fie una lˆng˘ cealalt˘.setOpaque(true). fie una sub alta ¸i separarea acestora a a a s prin intermediul unei bare care s˘ permit˘ configurarea suprafetei alocate a a ¸ fiec˘rei componente.add(new JButton("OK")).334 CAPITOLUL 11. tabbedPane. a String elem[] = {"Unu". ¸ JTabbedPane tabbedPane = new JTabbedPane(). ImageIcon icon = new ImageIcon("smiley. "Trei" }. panel1. panel2. KeyEvent. panel2. tabbedPane. panel1. fiecare panou avˆnd un astfel de bua a ton corespunz˘tor. SWING unuia sau altui panou realizˆndu-se prin intermediul unor butoane dispuse a pe partea superioar˘ a componentei. tabbedPane. ofer˘ o implementare asem˘n˘toare a ¸ a a a gestionarului de pozitionare CardLayout. panel1.setOpaque(true).addTab("Tab 1".gif").

335 11. crearea unui dialog realizˆndu-se prin extinderea acesteia. sp1.add(sp2).VERTICAL_SPLIT.add(new JButton("Salveaza")). FOLOSIREA COMPONENTELOR JPanel panel = new JPanel(new GridLayout(3. s a ¸ .HORIZONTAL_SPLIT. In Swing ın exist˘ ˆ a o serie de clase predefinite ce descriu anumite tipuri de dialoguri. panel). folosite pentru afi¸area unor mesaje.6. JTextArea text = new JTextArea( "Mai multe componente separate prin\n" + "intermediul containerelor JSplitPane").Permite crearea unor dialoguri simple. frame. text). list. a ıns˘ extrem de utile ˆ majoritatea aplicatiilor. panel.getContentPane().add(new JButton("Sterge")).add(new JButton("Adauga")). panel.6. 1)).7 Dialoguri Clasa care descrie ferestre de dialog este JDialog. Acestea sunt: ın ¸ • JOptionPane . ˆ a ıntocmai ca ˆ modelul AWT. realizarea unor interog˘ri de confirmare/renuntare. // Separam lista de grupul celor trei butoane JSplitPane sp1 = new JSplitPane( JSplitPane. panel. // Separam containerul cu lista si butoanele // de componenta pentru editare de text JSplitPane sp2 = new JSplitPane( JSplitPane.11.

JOptionPane. "Eroare de sistem !". "Eroare". r˘d˘cina a a a acestei fiind un container de nivel ˆ ınalt.7. care la rˆndul ei poate fi plasat˘ pe alt˘ suprafat˘ ¸i a¸a mai departe. JOptionPane.336 CAPITOLUL 11.7 11. sunt exemplificate dou˘ modalit˘¸i de utilizare a a at a clasei: JOptionPane.showConfirmDialog(frame. desenarea unei componente este un proces care se executa a s automat ori de cˆte ori este necesar. Procesul ˆ sine este asem˘n˘tor celui a ın a a din modelul AWT. SWING etc. ¸ 11. Cu alte cuvinte. componenta este plasat˘ pe o suprafat˘ de a ¸a afi¸are. . "Intrebare".showMessageDialog(frame.Dialog standard care permite navigarea prin sistemul de fi¸iere ¸i selectarea unui anumit fi¸ier pentru operatii de deschidere. sau chiar pentru introducerea unor valori.Clas˘ utilizat˘ pentru monitorizare˘ progresului a a a unei operatii consumatoare de timp. a a s fie ca urmare a unor actiuni externe sau interne programului. ˆ a ıncepˆnd cu cel de la nivelul a superior. • JFileChooser .QUESTION_MESSAGE). JOptionPane. s s s ¸ respectiv salvare. s a a a ¸a s s Cˆnd este necesar˘ desenarea componentei repsective. fie la prima sa afi¸are.1 Desenarea Metode specifice Dup˘ cum ¸tim. ˆ a exist˘ unele diferente care trebuie mentionate. clasa fiind extrem de configurabil˘.Dialog standard pentru selectarea ˆ ıntr-o manier˘ a facil˘ a unei culori. cum ar fi o fereastr˘ sau suprafata a ¸ unui applet. JOptionPane. "Doriti inchiderea aplicatiei ? ".ERROR_MESSAGE). operatia de de¸ ¸ senare va fi executat˘ pentru toate containerele. Mai jos. ıns˘ a ¸ ¸ Orice component˘ se g˘se¸te ˆ a a s ıntr-o ierarhie format˘ de containere. • JColorChooser .YES_NO_OPTION. a • ProgressMonitor .

dac˘ se dore¸te redesenarea explicit˘ a unei componente s ın a s a se va apela metoda repaint.11. a • paintChildren . Pe perioada ˆ care acesta este ocupat a ın cu transmiterea unui mesaj nu va fi f˘cut˘ nici o desenare. a . acest lucru nu este recomandat. De asemenea. Atentie ¸ Intocmai ca ˆ AWT.7. dup˘ care a a ¸ a va executa desenarea propriu-zis˘. ¸ a pe perioada respectiv˘ nu va fi transmis nici un mesaj. cum ar fi implea mentarea mecanismului de double-buffering.Este principala metod˘ pentru desenare ce este a supradefinit˘ pentru fiecare component˘ Swing ˆ parte pentru a descrie a a ın reprezentarea sa grafic˘. DESENAREA 337 Desenarea se bazeaz˘ pe modelul AWT. din motivele amintite mai sus. De¸i este posibil˘ supradefinirea s a ei. Implicit. Aceasta este responsabil˘ cu apelul metodelor Swing ce a a deseneaz˘ componenta ¸i anume: a s • paintComponent . ˆ cazul ˆ care componenta este a ın ın opac˘ metoda deseneaz˘ suprafata sa cu culoarea de fundal. apelat˘ automat ori de cˆte ori este necesar.Deseneaz˘ chenarele componentei (dac˘ exist˘). In cazul ˆ care dimensiunea sau pozitia comın ¸ ponentei s-au schimbat. aceast˘ metod˘ are ˆ a o implementare specific˘ ¸i nu trebuie a a ıns˘ a s supradefinit˘. desenarea este realizat˘ de firul de executie care se ın a ¸ ocup˘ cu transmiterea evenimentelor. a a a a Metoda paint este responsabil˘ cu apelul metodelor amintite mai sus ¸i a s realizarea unor optimiz˘ri legate de procesul de desenare. Nu trebuie supradefinit˘. Ca ¸i ˆ AWT. apelul metodei revalidate va precede apelul lui repaint. Pentru componentele a a Swing. a a dac˘ acesta este blocat ˆ a ıntr-o operatiune de desenare ce consum˘ mult timp. a • paintBorder . metoda cea mai important˘ fiind a a paint. Nu a a a trebuie supradefinit˘.Solicit˘ desenarea componentelor continute de aceast˘ a ¸ a component˘ (dac˘ exist˘).

a ¸ getHeight. un a a buton circular va fi construit ca fiind transparent (setOpaque(false)) ¸i va s desena ˆ interiorul s˘u o elips˘ umplut˘ cu o anumit˘ culoare. Trabsparenta ˆ a vine cu un anumit pret. In Swing. de fiecare dat˘ cˆnd s a a este cazul. Suprafata ocupat˘ de acestea poate fi aflat˘ cu metoda getInsets a ¸ a a . exist˘ s ın a cˆteva solutii mai simple pentru afi¸area unei imagini.7. a ın Afi¸area imaginilor s In AWT afi¸area unei imagini era realizat˘ uzual prin supradefinirea clasei s a Canvas ¸i desenarea imaginii ˆ metoda paint a acesteia. se recomand˘ setarea componentelor ca fiind opace a (setOpaque(true)). Imaginea respectiv˘ trebuie creat˘ a a ¸ a a folosind clasa ImageIcon. Acestea includ ˆ a ¸i dimsniunile chenarelor. cea mai utilizat˘ fiind a ¸ s a crearea unei etichete (JLabel) sau a unui buton (JButton) care s˘ aib˘ sea a tat˘ o anumit˘ imagine pe suprafata sa. De exemplu. Evident.gif"). ImageIcon img = new ImageIcon("smiley. Dimensiunile componentelor Dup˘ cum ¸tim. JLabel label = new JLabel(img). deoarece pentru componentele ¸ ıns˘ ¸ transparente vor trebui redesenate containerele pe care se g˘se¸te aceasta. a s ˆ ıncetinind astfel procesul de afi¸are.338 CAPITOLUL 11. SWING 11. orice component˘ este definit˘ de o suprafat˘ rectangua s a a ¸a lar˘. getWidth. Transparenta ¸ Cu ajutorul metodei setOpaque poate fi controlat˘ opacitatea componentelor a Swing. Din acest motiv.2 Consideratii generale ¸ In continuare vom prezenta cˆteva consideratii generale legate de diferite a ¸ aspecte ale desen˘rii ˆ cadrul modelului Swing. este ın a a a a necesar˘ implementarea de cod specific pentru a trata ap˘sarea acestui tip a a de buton. evident dac˘ acesıns˘ s a tea exist˘. Dimensiunile acestei pot fi obtinute cu metodele getSize. Aceasta este o facilitate extrem de important˘ deoarece permite a crearea de componente care nu au form˘ rectangular˘.

.top . obiectul de tip Graphics primit ca argument de metoda paintComponent este refolosit pentru desenarea componentei.Explicit Graphics2D g2d = (Graphics2D)g. Pentru a avea acces la API-ul Java2D.. argumentul este ıns˘ de fapt de tip Graphics2D. } Contexte grafice Argumentul metodei paintComponent este de tip Graphics ce ofer˘ prima itivele standard de desenare. Insets insets = getInsets()... DESENAREA 339 ce va returna un obiect de tip Insets ce specific˘ num˘rul de pixeli ocupati a a ¸ cu chenare ˆ jurul componentei. . // revenim la starea initiala .translate(-x.insets. fie folosind o copie a contextului grafic primit ca argument: // 1.11.7. clas˘ ce extinde Graphics ¸i pune la dispozitie a s ¸ metode mai sofisitcate de desenare cunoscute sub numele de Java2D. } In Swing..translate(x. este suficient s˘ facem conversia argumentului a ce descrie contextul grafic: public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D)g.. // modificam contexul . int currentHeight = getHeight() .insets. pentru a eficientiza desenarea. Acest lucru poate fi realizat fie explicit. Din acest motiv este foarte important s a ca atunci cˆnd supradefinim metoda paintComponent s˘ ne asigur˘m c˘ la a a a a terminarea metodei starea obiectului Graphics este aceea¸i ca la ˆ s ınceput.insets. // Desenam apoi cu g2d . ın public void paintComponent(Graphics g) { . g2d. y).. -y)..left .bottom. In majoritatea cazurilor ˆ a.right. a chenarelor ¸i a fiilor s˘i. g2d. int currentWidth = getWidth() .insets.

translate(x.MotifLookAndFeel Specific˘ interfata CDE/Motif..motif.sun. Orice L&F este descris de o clas˘ derivat˘ din LookAndFeel. y). a s • com.metal.plaf.plaf. Distributia a a ¸ standard Java include urm˘toarele clase ce pot fi utilizate pentru selectarea a unui L&F: • javax.windows.java.plaf.GTKLookAndFeel GTK+ reprezint˘ un standard de creare a interfetelor grafice dezvoltat a ¸ independent de limbajul Java.340 CAPITOLUL 11.swing. a ¸ • com. SWING // 2.4.8 Look and Feel Prin sintagma ’Look and Feel’ (L&F) vom ˆ ¸elege modul ˆ care sunt deınt ın senate componentele Swing ¸i felul ˆ care acestea interactioneaz˘ cu utis ın ¸ a lizatorul. (GTK este acronimul de la GNU Image Manipulation Program Toolkit). Posibilitatea de a alege ˆ ıntre diferite moduri L&F are avantajul de a oferi prezentarea unei aplicatii ˆ ¸ ıntr-o form˘ grafic˘ care s˘ corespund˘ a a a a preferintelor utilizatorilor.2 exist˘ ¸i implementarea pentru Windows XP .swing. Incepˆnd cu versia a unea 1.MetalLookAndFeel Este varianta implicit˘ de L&F ¸i are un aspect specific Java. In principiu.swing. a • com.swing. . as • com..dispose(). Folosind acest L&F este posibil˘ ¸i a s .create().sun. variantele originale de L&F furnizate ¸ ˆ distributia standard ofereau modalitatea ca o interfat˘ Swing fie s˘ se ın ¸ ¸a a ˆ ıncadreze ˆ ansamblul grafic al sistemului de operare folosit.gtk.java.java.WindowsLookAndFeel Varianta specific˘ sistemelor de operare Windows.swing.plaf.sun.plaf. g2d. Folosirea unei copii Graphics2D g2d = (Graphics2D)g.mac.sun.java. g2d. 11. fie s˘ aib˘ un ın a a aspect specific Java.MacLookAndFeel Varianta specific˘ sistemelor de operare Mac.

a • getCrossPlatformLookAndFeelClassName .plaf.swing. returnˆnd un obiect de tip ¸ a a LookAndFeel.Obtine varianta curent˘. fie un ¸ir de a a s caractere cu numele complet al clasei L&F. // Exemple: UIManager. LOOK AND FEEL 341 specificarea unei anumite teme prin intermediul unui fi¸ier de resurse s sau folosind variabila swing.11.setLookAndFeel( "com.MotifLookAndFeel").Obtine variant˘ specific˘ sistemu¸ a a lui de operare folosit.java. Setarea propriet˘¸ii swing.Returneaz˘ interfata grafic˘ a ¸ a standard Java (JLF). • setLookAndFeel .defaultlaf at Exist˘ posibilitatea de a specifica varianta de L&F a aplicatie direct de la a ¸ linia de comand˘ prin setarea proprietˆ¸ii swing. UIManager. Metoda prime¸te ca ara s gument un obiect dintr-o clas˘ derivat˘ din LookAndFeel. In cazul ˆ care nu exist˘ nici o astfel de clas˘.getSystemLookAndFeelClassName()).gtkthemefile. at Folosirea clasei UImanager Clasa UIManager pune la dispozitie o serie de metode statice pentru se¸ lectarea la momentul executiei a uni anumit L&F. precum ¸i pentru obtinerea ¸ s ¸ unor variante specifice: • getLookAndFeel .8. • getSystemLookAndFeelClassName .Seteaz˘ modul curet L&F. ca ˆ exemplul de mai jos: ın java -Dswing.motif. ın a a returneaz˘ varianta standard.defaultlaf: a at .setLookAndFeel( UIManager.sun.gtkthemefile=temaSpecifica/gtkrc App Specificare unei anumite interfete L&F poate fi realizat˘ prin mai multe ¸ a modalit˘¸i.

updateComponentTreeUI(f).properties situat ˆ subdirectorul lib al distributiei Java. Proprietatea swing.sun.properties.defaultlaf= com.GTKLookAndFeel App java -Dswing.WindowsLookAndFeel Ordinea ˆ care este aleas˘ clasa L&F este urm˘toarea: ın a a 1. Clasa standard Java (JLF).plaf.updateComponentTreeUI ce va primi ca argument r˘d˘cina unei ierarhii.setLookAndFeel(numeClasaLF). Apelul explicit al metodei UIManager. a ın s 4. Secventa care efectueaz˘ aceast˘ operatie a a ¸ a a ¸ pentru o fereastr˘ f este: a UIManager.plaf. a a 3.windows. s ın ¸ # Swing properties swing. ˆ ıncepˆnd cu containerele de nivel ˆ a ınalt ¸i va fi realizat prin s apelul metodei SwingUtilities. .gtk.defaultlaf= com.pack().swing. 2. SWING java -Dswing.sun.swing.java.sun.WindowsLookAndFeel App O alt˘ variant˘ de a seta aceast˘ proprietate este schimbarea ei direct ˆ a a a ın fi¸ierul swing. f.defaultlaf specificat˘ ˆ fi¸ierul swing. Exist˘ posibilitatea de a schimba varianta de L&F chiar ¸i dup˘ afi¸area a s a s componentelor.defaultlaf specificat˘ de la linia de comand˘.plaf. SwingUtilities.342 CAPITOLUL 11.setLookAndFeel ˆ ınaintea cre˘rii a unei componente Swing.java.windows.defaultlaf= com. Proprietatea swing. Acesta este un proces care trebuie s˘ actualizeze ierarhiile a de componente.java.swing.

a ın 343 . Diferenta dintre un fir de ¸a ¸ s as executie ¸i un proces const˘ ˆ faptul c˘ un fir de executie nu poate rula ¸ s a ın a ¸ independent ci trebuie s˘ ruleze ˆ cadrul unui proces. Un ¸ program aflat ˆ executie se nume¸te proces. ˆ timp ce un sistem de operare multitasking. a ın Un fir de executie este similar unui proces secvential. Un sistem de operare monotaskın ¸ s ing. cum ar fi fi MS-DOS. ˆ sensul c˘ are ¸ ¸ ın a un ˆ ınceput. o secvent˘ de executie a instructiunilor sale ¸i un sfˆr¸it.Capitolul 12 Fire de executie ¸ 12. a ın s folosind diverse strategii de alocare a procesorului fiec˘ruia dintre acestea. Cu alte ¸a ¸ ¸ s as cuvinte. nu este capabil s˘ execute decˆt un singur proces a a la un moment dat. o secvent˘ de executie ¸i un sfˆr¸it.1 Introducere Firele de executie fac trecerea de la programarea secvential˘ la programarea ¸ ¸ a concurent˘. a ın Definitie ¸ Un fir de executie este o succesiune scevential˘ de instructiuni care se ¸ ¸ a ¸ execut˘ ˆ cadrul unui proces. cum ar fi ın UNIX sau Windows. la un moment dat programul are un singur punct de executie. a Am reamintit acest lucru deoarece notiunea de fir de executie nu are sens ¸ ¸ decˆt ˆ cadrul unui sistem de operare multitasking. poate rula oricˆte procese ˆ acela¸i timp (concurent). Un program secvential reprezint˘ modelul clasic de program: are a ¸ a un ˆ ınceput.

Care ar fi ˆ a deosebirile ˆ ıns˘ ıntre un fir de executie ¸i un proces ? In primul. firele ˆsi desf˘¸oar˘ ¸ ı¸ as a activitatea ˆ fundal ˆ a. evident. ın a a toate firele de executie avˆnd acces la acelea¸i date. Firele ¸ ¸a de executie definite de o clas˘ vor avea acela¸i cod ¸i. aceea¸i ¸ a s s s . a¸teptarea eliber˘rii unei resurse. acest lucru nu este obligatoriu.344 Program (proces) CAPITOLUL 12. executia simultan˘ a firelor ˆ cadrul unui ¸ ¸ a ın proces este similar˘ cu executia concurent˘ a proceselor: sistemul de operare a ¸ a va aloca procesorul dup˘ o anumit˘ strategie fiec˘rui fir de executie pˆn˘ la a a a ¸ a a terminarea lor. De multe ori ori. etc. O alt˘ deosebire rezult˘ din faptul c˘ fiecare proces ın a a a are propria sa memorie (propriul s˘u spatiu de adrese) iar la crearea unui nou a ¸ proces (fork) este realizat˘ o copie exact˘ a procesului p˘rinte: cod ¸i date. Un fir de executie poate fi asem˘nat cu o versiune redus˘ a unui proces. ¸ s rˆnd deosebirea major˘ const˘ ˆ faptul c˘ firele de executie nu pot rula decˆt a a a ın a ¸ a ˆ cadrul unui proces. ¸ a a ambele rulˆnd simultan ¸i independent pe o structur˘ secvential˘ format˘ de a s a ¸ a a instructiunile lor. prin urmare. datele procesului original. a a a s ˆ timp ce la crearea unui fir nu este copiat decˆt codul procesului p˘rinte.2 Crearea unui fir de executie ¸ Ca orice alt obiect Java. ın ıns˘ 12. De asemenea. desenarea s a componentelor unei aplicatii GUI. ˆ a uzual ele sunt folosite ¸ ın ¸ ıns˘ pentru executarea unor operatii consumatoare de timp f˘r˘ a bloca procesul ¸ aa principal: calcule matematice. un fir mai poate fi privit ¸i ca un context de executie ˆ cadrul unui s s ¸ ın proces. permitˆnd efectuarea concurent˘ a sarcinilor independente ale ¸ ¸a a acelui program. Din acest motiv firele de executie mai sunt numite ¸i procese ¸ s usoare. un fir de executie este o instant˘ a unei clase. FIRE DE EXECUTIE ¸ Program (proces) Un program ˆsi poate defini ˆ a nu doar un fir de executie ci oricˆte. ¸ a s A¸adar. ceea ı¸ ıns˘ ¸ a ce ˆ ınseamn˘ c˘ ˆ cadrul unui proces se pot executa simultan mai multe fire a a ın de executie. Firele de executie sunt utile ˆ multe privinte.

12. } public void run() { // Codul firului de executie . orice clas˘ ce descrie ¸ a as s a fire de executie va contine metoda run ˆ care este implementat codul ce va fi ¸ ¸ ın rulat. nu a ¸ face nimic. Interfata Runnable este conceput˘ ca fiind un protocol comun pentru ¸ a obiectele care doresc s˘ execute un anumit cod pe durata existentei lor.1 Extinderea clasei Thread Cea mai simpl˘ metod˘ de a crea un fir de executie care s˘ realizeze o anumit˘ a a ¸ a a actiune este prin extinderea clasei Thread ¸i supradefinirea metodei run a ¸ s acesteia.. a ¸ Cea mai important˘ clas˘ care implementeaz˘ interfata Runnable este a a a ¸ Thread. In cazul ˆ care nu vrem s˘ s ¸ ın a d˘m nume firelor pe care le cre˘m. implicit.. Orice fir de ¸ executie este o instant˘ a clasei Thread sau a unei subclase a sa. CREAREA UNUI FIR DE EXECUTIE ¸ 345 secventa de instructiuni. ¸ Orice clas˘ ale c˘rei instante vor fi executate separat ˆ a a ¸ ıntr-un fir propriu trebuie declarat˘ ca fiind de tip Runnable. • prin implementarea interfetei Runnable. atunci putem renunta la supradefinirea a a ¸ .2. cu alte cuvinte.2. Crearea unei clase care s˘ defineasc˘ fire de executie ¸ ¸ a a ¸ poate fi facut˘ prin dou˘ modalit˘¸i: a a at • prin extinderea clasei Thread. } } Prima metod˘ a clasei este constructorul. Aceasta implementeaz˘ un fir de executie generic care. metoda run nu contine nici un cod. ¸ ¸a 12. A¸adar. Formatul general al unei astfel de clase este: public class FirExcecutie extends Thread { public FirExcecutie(String nume) { // Apelam constructorul superclasei super(nume). care prime¸te ca argument un a s ¸ir ce va reprezenta numele firului de executie. Aceasta este o interfat˘ care a ¸a contine o singur˘ metod˘ ¸i anume metoda run.

5) . a = a . 10) . // Numara de la 0 la 100 cu pasul 5 fir2 = new AfisareNumere (100 . se pot defini ¸i alti constructori. 200 . ”inima” oric˘rui fir de a a a executie. lansarea s˘ fiind realizeaz˘ ¸ a a de metoda start. FIRE DE EXECUTIE ¸ acestui constructor ¸i s˘ folosim constructorul implicit.1: Folosirea clasei Thread class AfisareNumere extends Thread { private int a . acesta poate primi un a ¸ aa nume cu metoda setName. i += pas ) System . this . Listing 12. public AfisareNumere ( int a . int b . b = b . A dou˘ metod˘ este metoda run. i <= b . b . cu un anumit pas. ¸ ın a Un fir de executie creat nu este automat pornit. out . . fir2 . care s a aa creeaz˘ un fir de executie f˘r˘ nici un nume.346 CAPITOLUL 12. pas = pas . // Lansam in executie fir. pas . Ulterior.start(). } public void run () { for ( int i = a . print ( i + " " ) . } } public class TestThread { public static void main ( String args []) { AfisareNumere fir1 . this . int pas ) { this . Evident. definit˘ ˆ clasa Thread. 100 . a ın // Cream firul de executie FirExecutie fir = new FirExecutie("simplu"). ˆ care scriem efectiv codul care trebuie s˘ se execute. f˘r˘ argumente. ace¸tia s ¸ s fiinde utili atunci cˆnd vrem s˘ trimitem diver¸i parametri de initializare a a s ¸ firului nostru. fir1 = new AfisareNumere (0 . S˘ consider˘m ˆ continuare un exemplu ˆ care definim un fir de executie a a ın ın ¸ ce afi¸eaz˘ numerele ˆ s a ıntregi dintr-un interval.

s-ar crede c˘ acest program va afi¸a prima dat˘ nua ¸ a s a merele de la 0 la 100 cu pasul 5.2. // Pornim firele de executie // Ele vor fi distruse automat la terminarea lor } } 347 Gˆndind secvential.2 Implementarea interfetei Runnable ¸ Ce facem ˆ a cˆnd dorim s˘ cre˘m o clas˘ care instantiaz˘ fire de executie ıns˘ a a a a ¸ a ¸ dar aceasta are deja o superclas˘. start () . a ¸ a s el fiind controlat de procesor ˆ ıntr-o manier˘ ”aparent” aleatoare. rezultatul obtinut va fi o intercalare de valori produse de ıns˘ ¸ cele dou˘ fire ce ruleaz˘ simultan. deci rezultatul afi¸at pe ecran a a s ar trbui s˘ fie: a 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 100 110 120 130 140 150 160 170 180 190 200 In realitate ˆ a. a ¸ s ¸a a a f˘r˘ a extinde clasa Thread. CREAREA UNUI FIR DE EXECUTIE ¸ // Numara de la 100 la 200 cu pasul 10 fir1 . apoi numerele de la 100 la 200 cu pasul 10. aa Interfata Runnable se g˘se¸te ˆ pachetul java. ˆ ıntrucˆt primul apel este c˘tre contorul fir1. la extinderea ei obtineam implementarea indis ¸ rect˘ a interfetei. Clasa Thread implementeaz˘ ea ˆ a¸i interfata ¸ a ıns˘s ¸ Runnable ¸i.lang ¸i este definit˘ astfel: ¸ a s ın s a . A¸adar.2.12. interfat˘ Runnable permite unei clase s˘ fie activ˘. din acest motiv. start () . Un posibil a rezultat al programului de mai sus: 0 100 5 110 10 120 15 130 20 140 25 150 160 170 180 190 200 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 12. fir2 . nu mai putem extinde clasa Thread ci trebuie s˘ implement˘m a a direct interfata Runnable. ¸tiind c˘ ˆ Java nu este permis˘ mo¸tenirea a s a ın a s multipl˘ ? a class FirExecutie extends Parinte. La rul˘ri diferite se pot obtine rezultate a a a ¸ diferite deoarece timpul alocat fiec˘rui fir de executie poate s˘ nu fie acela¸i. Thread // incorect ! In acest caz.

Dup˘ creare. Aceste operatiuni pot fi f˘cute chiar ˆ cadrul clasei noastre: ¸ a ın public class FirExecutie implements Runnable { private Thread fir = null.start(). } Prin urmare. prin ın a a instructiunea new.348 CAPITOLUL 12. crearea acestora trebuind f˘cut˘ a ¸ a a explicit. Acest lucru se realizeaz˘. firul de executie ¸a a ¸ poate fi lansat printr-un apel al metodei start. Pentru a realiza acest lucru trebuie s˘ instantiem un obiect de tip a ¸ Thread ce va reprezenta firul de executie propriu zis al c˘rui cod se gase¸te ¸ a s ˆ clasa noastr˘. O astfel ¸ a de clas˘ se mai nume¸te clas˘ activ˘ ¸i are urm˘toarea structur˘: a s a as a a public class ClasaActiva implements Runnable { public void run() { //Codul firului de executie . FIRE DE EXECUTIE ¸ public interface Runnable { public abstract void run(). public FirExecutie() if (fir == null) { fir = new Thread(this). ca pentru orice alt obiect. ClasaActiva obiectActiv = new ClasaActiva(). fir. . ˆ a ¸ a ıns˘ nu la oricare dintre ace¸tia. Simpla instantiere a unei clase care implemeneaz˘ interfata ¸ a ¸ Runnable nu creeaz˘ nici un fir de executie. se pierde ˆ a tot suportul oferit a ıns˘ de clasa Thread. } } Spre deosebire de modalitatea anterioar˘.. Thread fir = new Thread(obiectActiv). Trebuie apelat constructorul care s˘ primeasc˘ s a a drept argument o instant˘ a clasei noastre.. urmat˘ de un apel la un constructor al clasei Thread. o clas˘ care instantiaz˘ fire de executie prin implementarea a ¸ a ¸ interfetei Runnable trebuie obligatoriu s˘ implementeze metoda run.

la lansarea sa. event . acest constructor accept˘ ca argument orice instant˘ a s a ¸a a unei clase ”Runnable”. .start().2: Folosirea interfetei Runnable ¸ import java .. va apela metoda run din ¸ clasa curent˘.12. ¸ anumit tip. awt . ¸i nu separat ˆ ıns˘ a a s ıntr-un fir.2.*.*. import java . Atentie ¸ Metoda run nu trebuie apelat˘ explicit. A¸adar. awt .. Apelul explicit al metodei run nu va furniza nici o eroare. ¸ exemplu ˆ care cre˘m dou˘ fire de executie ın a a ¸ Fiecare fir va desena figuri geometrice de un desenare de tip Canvas. lansarea a firului va fi f˘cut˘ automat la instantierea unui obiect al clasei: a a ¸ FirExecutie fir = new FirExecutie(). pe o suprafat˘ de ¸a fire de executie care vor rula ¸ suprafata sa. CREAREA UNUI FIR DE EXECUTIE ¸ fir. Vom porni apoi dou˘ a concurent. desenˆnd figuri diferite. } } public void run() { //Codul firului de executie . ˆ a aceasta va fi executat˘ ca orice alt˘ metoda. S˘ consider˘m urm˘torul a a a folosind interfata Runnable. class Plansa extends Canvas implements Runnable { // Deoarece Plansa extinde Canvas . } } 349 Specificarea argumentului this ˆ constructorul clasei Thread determin˘ ın a crearea unui fir de executie care. Pentru clasa FirExecutie dat˘ mai sus. fiecare pe a Listing 12. acest lucru realizˆndu-se automat a a la apelul metodei start.

setColor ( culoare ) . drawRect (0 . } public void update ( Graphics g ) { paint ( g ) . r ) .350 CAPITOLUL 12. // Desenam figura la coordonatele calculate // de firul de executie g . culoare = culoare . y . r . dim . y =0 . public Plansa ( String figura . Color culoare ) { this . // Supradefinim update ca sa nu mai // fie stearsa suprafata de desenare } public void run () { /* Codul firului de executie : Afisarea a 100 de figuri geometrice la pozitii si dimensiuni calculate aleator . r ) . equals ( " patrat " ) ) g . g . int x =0 . else if ( figura . } public Dimension getPreferredSize () { return dim . y . drawOval (x . Intre doua afisari . } public void paint ( Graphics g ) { // Desenam un chenar g . if ( figura . Color culoare . 0 . black ) . i <100. FIRE DE EXECUTIE ¸ // nu mai putem extinde clasa Thread Dimension dim = new Dimension (300 . facem o pauza de 50 ms */ for ( int i =0. String figura . i ++) { . dim . 300) . drawRect (x . width -1 . height -1) . r . equals ( " cerc " ) ) g . setColor ( Color . r =0. figura = figura . this .

try { Thread . Color . this . } }) . add ( p2 ) . 2) ) . Plansa p2 = new Plansa ( " cerc " . red ) . } catch ( InterruptedEx c e p t i o n e ) {} repaint () .12. show () . addWindowListener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System . CREAREA UNUI FIR DE EXECUTIE ¸ x = ( int ) ( Math . exit (0) . height ) . sleep (50) . // Cream doua obiecte active de tip Plansa Plansa p1 = new Plansa ( " patrat " .2. random () * dim . add ( p1 ) . Color . } } } class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . random () * dim . care vor // actualiza desenul celor doua planse new Thread ( p1 ) . start () . le plasam pe fereastra setLayout ( new GridLayout (1 . } } 351 . start () . f . } } public class TestRunnable { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test Runnable " ) . width ) . pack () . y = ( int ) ( Math . // Pornim doua fire de executie . // Acestea extind Canvas . random () * 100) . r = ( int ) ( Math . new Thread ( p2 ) . blue ) .

cu alte ¸ a s ın a a cuvinte dup˘ instantierea unui obiect din clasa Thread sau dintr-o subclas˘ a ¸ a a sa. devine activ ¸ a ¸a prin lansarea sa ¸i. In continuare.352 CAPITOLUL 12. se termin˘. un fir de executie se poate g˘si ˆ una din urm˘toarele patru s ¸ a ın a st˘ri: a • ”New Thread” • ”Runnable” • ”Not Runnable” • ”Dead” Starea ”New Thread” Un fir de executie se g˘se¸te ˆ aceast˘ stare imediat dup˘ crearea sa. FIRE DE EXECUTIE ¸ 12. // fir se gaseste in starea "New Thread" . la un moment dat. Diagrama a ın a ¸ de mai jos ilustreaz˘ generic aceste st˘ri precum ¸i metodele care provoaca a a s tranzitia dintr-o stare ˆ alta: ¸ ın A¸adar.3 Ciclul de viat˘ al unui fir de executie ¸a ¸ Fiecare fir de executie are propriul s˘u ciclu de viat˘: este creat. vom analiza s a mai ˆ ındeaproape st˘rile ˆ care se poate g˘si un fir de executie. Thread fir = new Thread(obiectActiv).

a Un fir aflat ˆ starea ”Runnable” nu ˆ ın ınseamn˘ neap˘rat c˘ se g˘¸este a a a as efectiv ˆ executie. prin metoda start. a¸teptˆnd ca o anumit˘ conditie s˘ fie satisfas a a ¸ a cut˘. a . ın ¸ fir. s ¸ Starea ”Runnable” Dup˘ apelul metodei start un fir va trece ˆ starea ”Runnable”. • A apelat metoda wait. A¸adar. Pentru a rezolva aceasta problem˘ exist˘ o ın a a planificare care s˘ partajeze dinamic ¸i corect procesorul ˆ a s ıntre toate firele de executie care sunt ˆ starea ”Runnable”.12. //fir se gaseste in starea "Runnable" Metoda start realizez˘ urm˘toarele operatiuni necesare rul˘rii firului de a a ¸ a executie: ¸ • Aloc˘ resursele sistem necesare. a • Planific˘ firul de executie la procesor pentru a fi lansat. Apelul oric˘rei alte metode ˆ afar˘ de start ın ¸ a ın a nu are nici un sens ¸i va provoca o exceptie de tipul IllegalThreadStateException.start(). adic˘ instructiunile sale sunt interpretate de procesor. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ 353 In aceast˘ stare firul este ”vid”. el nu are alocate nici un fel de resurse sisa tem ¸i singura operatiune pe care o putem executa asupra lui este lansarea s ¸ ˆ executie. adic˘ va fi a ın a ˆ executie. ın ¸ a ¸ Acest lucru se ˆ ampl˘ din cauza c˘ majoritatea calculatoarelor au un singur ıntˆ a a procesor iar acesta nu poate rula simultan toate firele de executie care se ¸ gasesc ˆ starea ”Runnable”.3. un fir care ”ruleaz˘” poate ¸ ın s a s˘-¸i a¸tepte de fapt rˆndul la procesor. as s a Starea ”Not Runnable” Un fir de executie poate ajunge ˆ aceaat˘ stare ˆ una din urm˘toarele ¸ ın a ın a situatii: ¸ • Este ”adormit” prin apelul metodei sleep. a ¸ • Apeleaz˘ metoda run a obiectului activ al firului.

Lungimea acestei pauze este specificat˘ a ˆ milisecunde ¸i chiar nanosecunde. • Dac˘ un fir de executie a¸teapt˘ o anumit˘ conditie. apelul acestei metode se face ˆ ıntr-un bloc de tip try-cacth: try { // Facem pauza de o secunda Thread. Dup˘ expirarea intervalului specifia a cat firul revine ˆ starea ”Runnable” iar dac˘ procesorul este ˆ continuare ın a ın disponibil ˆ va continua executia. exist˘ o secvent˘ ın a ¸a specific˘ de ie¸ire din starea repectiv˘. FIRE DE EXECUTIE ¸ • Este blocat ˆ ıntr-o operatie de intrare/ie¸ire. ¸ • Dac˘ un fir de executie este blocat ˆ a ¸ ıntr-o operatiune de intrare/ie¸ire ¸ s atunci el redevine ”Runnable” atunci cˆnd acea operatiune s-a termia ¸ nat. la un moment dat. acesta nu va fi execut ın ¸ chiar dac˘ procesorul devine disponibil. ın ¸ s In intervalul ˆ care un fir de executie ”doarme”. Intrucˆt poate provoca exceptii de tipul ın s a ¸ InterruptedException. un singur fir este ˆ executie ¸i doar pentru acesta are sens ”adormirea” sa. atunci un alt a ¸ s a a ¸ obiect trebuie s˘ ˆ informeze dac˘ acea conditie este ˆ a ıl a ¸ ındeplinit˘ sau a nu. atunci el devine ”Runnable” a ¸ doar dup˘ scurgerea intervalului de timp specificat de instructiunea a ¸ sleep.354 CAPITOLUL 12. care readuce firul de executie ˆ starea a s a ¸ ın ”Runnable”. Acest lucru este foarte normal deoarece. ısi ¸ Pentru fiecare tip de intrare ˆ starea ”Not Runnable”.. .sleep(1000). ¸ s Metoda sleep este o metod˘ static˘ a clasei Thread care provoac˘ o a a a pauz˘ ˆ timpul rul˘rii firului curent aflat ˆ executie. acest lucru se realizeaz˘ prin instructiunile notify sau notifyAll a ¸ (vezi ”Sincronizarea firelor de executie”). Acestea sunt: • Dac˘ un fir de executie a fost ”adormit”. } catch (InterruptedException e) { . } Observati c˘ metoda fiind static˘ apelul ei nu se face pentru o instant˘ anume ¸ a a ¸a a clasei Thread. cu alte cuvinte ˆ a ın a ın ¸ ıl ”adoarme” pentru un timp specificat..

3. a a S˘ consider˘m exemplul unui fir de executie care trebuie s˘ numere sea a ¸ a cundele scurse pˆn˘ la ap˘sarea tastei Enter. se va termina ¸i firul de executie repsectiv. In cazul cˆnd metoda run a trebuie s˘ execute o bucl˘ infinit˘ atunci aceasta trebuie controlat˘ a a a a printr-o variabil˘ care s˘ opreasc˘ ciclul atunci cˆnd dorim ca firul de a a a a executie s˘ se termine. un fir de executie trebuie a s ¸ s˘-¸i ”aranjeze” singur propria sa ”moarte”. acesta intrˆnd ˆ starea Dead. un fir de executie nu poate fi terminat fortat de c˘tre a ¸ ¸ a program ci trebuie s˘-¸i ”aranjeze” singur terminarea sa. Acest lucru poate as fi realizat ˆ dou˘ modalit˘¸i: ın a at 1. A¸adar. s a s ¸ 2. as 12.12. a ın a // Primul exemplu public void run() { for(int i = a. Uzual. Prin scrierea unor metode run care s˘-¸i termine executia ˆ mod natas ¸ ın ural. Prin folosirea unei variabile de terminare.out. i <= b. } Dup˘ afi¸area numerelor din intervalul specificat. Ambele exemple anteriorare ¸ a ın se ˆ ıncadreaz˘ ˆ aceast˘ categorie. ˆ versiunile mai vechi exista metoda ın stop a clasei Thread care termina fortat un fir de executie. metoda se termin˘ a s a ¸i. vom folosi o variabil˘ membr˘ a clasei ¸ a a a care descrie firul de executie care fie este public˘. ci trebuie s˘ se termine a a a ˆ mod natural la ˆ ın ıncheierea metodei run pe care o execut˘. ˆ a aceasta a ¸ ¸ ıns˘ fost eliminat˘ din motive de securitate. La terminarea metodei run se va termina automat ¸i firul de s executie. Spre deosebire de a versiunile curente ale limbajului Java. i += pas) System. a a a .print(i + " " ).3. fie este asociat˘ cu o ¸ a a metod˘ public˘ care permite schimbarea valorii sale. Un fir nu ın ¸ poate fi oprit din program printr-o anumit˘ metod˘.1 Terminarea unui fir de executie ¸ Dup˘ cum am vazut. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ 355 Starea ”Dead” Este starea ˆ care ajunge un fir de executie la terminarea sa. odat˘ cu ea.

sec ++. println ( "S . out . // Folosim o variabila de terminare public boolean executie = true . Sistemul a a ¸ Java de colectare a ”gunoiului” se ocup˘ de acest lucru. FIRE DE EXECUTIE ¸ Listing 12. sec + " secunde " ) .*.exit va oprit fortat toate firele de executie ¸i va termina ¸ ¸ s aplicatia curent˘. System . read () . io . class NumaraSecunde extends Thread { public int sec = 0. System . executie = false . start () . out . sleep (1000) . // Oprim firul de executie fir .3: Folosirea unei variabile de terminare import java . ¸ a . fir . println ( " Apasati tasta Enter " ) . public void run () { while ( executie ) { try { Thread . System . out .au scurs " + fir . System . " ) . } } Nu este necesar˘ distrugerea explicit˘ a unui fir de executie. Setarea valorii a null pentru variabila care referea instanta firului de executie va u¸ura ˆ a ¸ ¸ s ıns˘ activitatea procesului gc. print ( " . in . Metoda System. } catch ( Interr u pt ed Ex ce pt io n e ) {} } } } public class TestTerminare { public static void main ( String args []) throws IOException { NumaraSecunde fir = new NumaraSecunde () .356 CAPITOLUL 12.

start(). repectiv ”New Thread” a sau ”Dead” nu se poate face nici o diferentiere. } catch ( InterruptedEx c e p t i o n e ) {} } . cu metoda setDaemon. beep () . De multe ori a a a ¸ ˆ a dorim s˘ folosim fire care s˘ realizeze diverse activit˘¸i. a Listing 12. ma¸ina virtual˘ Java nu se va ¸ s a opri decˆt atunci cˆnd nu mai exist˘ nici un fir de executie activ.12. un fir de executie poate fi f˘cut demon. // isAlive retuneaza true (starea este Runnable) fir.executie = false.3. Dup˘ crearea sa. Aceste fire de executie se numesc a s ¸ demoni.dac˘ firul este ˆ una din st˘rile ”Runnable” sau ”Not Runnable” a ın a • false . try { Thread .2 Fire de executie de tip ”daemon” ¸ Un proces este considerat ˆ executie dac˘ contine cel putin un fir de executie ın ¸ a ¸ ¸ ¸ activ. Cu alte cuvinte. // isAlive retuneaza false (starea este Dead) 12. sleep (1000) . ıns˘ a a at pe toat˘ durata de executie a programului iar ˆ momentul termin˘rii acestuia a ¸ ın a s˘ se termine automat ¸i firele respective. Toolkit . Metoda returneaz˘: ınc˘ a • true .4: Crearea unui fir de excutie de tip ”daemon” ¸ class Beeper implements Runnable { public void run () { while ( true ) { java .dac˘ firul este ˆ una din starile ”New Thread” sau ”Dead” a ın Intre st˘rile ”Runnable” sau ”Not Runnable”. awt . ¸ NumaraSecunde fir = new NumaraSecunde(). getDef aultToo lkit () . la rularea unei aplicatii. // isAlive retuneaza false (starea este New Thread) fir. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ 357 Pentru a testa dac˘ un fir de executie a fost pornit dar nu s-a terminat a ¸ ˆ a putem folosi metoda isAlive. eventual periodic.3. sau scos din a ¸ a aceast˘ stare.

Implicit. io . public static final int NORM_PRIORITY= 5. in . La nivelul sistemului de operare. determinist de planificare. at Fiecare fir de executie Java prime¸te la crearea sa o anumit˘ priori¸ s a tate. prioritatea unui fir nou creat are valoarea NORM PRIORITY. t . ceea ce ˆ ınseamn˘ c˘ firele a a de executie trebuie s˘-¸i ˆ ¸ a s ımpart˘ accesul la acel procesor.358 } } CAPITOLUL 12. " ) . // " Demonul " se termina automat // la terminarea aplicatiei } } 12. public static final int MIN_PRIORITY = 1... cunoscut sub a numele de planificare cu priorit˘¸i fixate. O prioritate este de fapt un num˘r ˆ a ıntreg cu valori cuprinse ˆ ıntre s MIN PRIORITY ¸i MAX PRIORITY. println ( " Apasati Enter . read () . IOException { Thread t = new Thread ( new Beeper () ) .3 Stabilirea priorit˘¸ilor de executie at ¸ Majoritatea calculatoarelor au un sigur procesor. setDaemon ( true ) . start () .3. Executia ˆ a ¸ ıntr-o anumit˘ ordine a mai multor fire de executie pe un num˘r limitat de procesoare a ¸ a se nume¸te planificare (scheduling). System . FIRE DE EXECUTIE ¸ public class TestDaemon { public static void main ( String args []) throws java . Aceste trei constante sunt definite ˆ clasa Thread ın astfel: public static final int MAX_PRIORITY = 10. System . Schimbarea ulterioar˘ a priorit˘¸ii unui fir de executie se realizeaz˘ cu metoda a at ¸ a setPriority a clasei Thread. out . exist˘ dou˘ modele de lucru cu fire de a a executie: ¸ . t . Sistemul Java de executie a programelor s ¸ implementeaz˘ un algoritm simplu.

programele Java trebuie scrise astfel ˆ at s˘ functioneze corect pe ambele modele. acest s ın ¸ sistem se mai nume¸te cu ”cuante de timp”. Deoarece specificatiile ma¸inii virtuale Java a ¸ s nu impun folosirea unui anumit model. ¸ Planificatorul Java lucreaz˘ ˆ modul urmator: dac˘ la un moment dat a ın a sunt mai multe fire de executie ˆ starea ”Runnable”. Doar cˆnd firul de executie cu prioritate maxim˘ se a ¸ a termin˘. un fir de executie Java cedeaz˘ procesorul ˆ una din situatiile: s ¸ a ın • un fir de executie cu o prioritate mai mare solicit˘ procesorul. dezavantajul acestui model este c˘ unele fire pot acapara proa cesorul. atunci firul cu prioritate mai mare este imediat trecut ˆ a ın executie iar celalalt trecut ˆ asteptare. vom mai detalia ıncˆ a ¸ putin aceste aspecte. In cazul ˆ care toate firele au aceea¸i prioritate ele sunt alese pe a ın s rˆnd.12. a • face explicit acest lucru apelˆnd metoda yield. ¸ a • metoda sa run se termin˘. dezavantajul s˘u fiind s a nevoia de a sincroniza accesul firelor la resursele comune. A¸adar. urmˆnd s˘ fie reluate dup˘ a a a a a a a ce ¸i celelalte fire aflate ˆ executie au avut acces la procesor. adic˘ sunt pregatite ¸ ın a pentru a fi rulate. ˆ care firele de executie decid cˆnd s˘ cedeze proın ¸ a a cesorul. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ 359 • Modelul cooperativ. Planificatorul Java nu va ˆ ¸ ın ıntrerupe ˆ a un fir de executie ˆ favoarea altuia de aceeasi prioritate. ¸a s ¸ a a • Modelul preemptiv. In continuare. planificatorul ˆ va alege pe cel cu prioritatea cea mai ıl mare pentru a-l executa. ¸ a . ˆ modelul cooperativ firele de executie sunt responsabile cu pars ım ¸ tajarea timpului de executie. a dup˘ ce au fost l˘sate s˘ ruleze o perioad˘. ˆ timp ce ˆ modelul preemptiv ele trebuie ¸ ın ın s˘ partajeze resursele comune. A¸adar. a • timpul alocat pentru executia s˘ a expirat (pe SO cu cuante de timp). dup˘ un algoritm simplu de tip ”round-robin”. sau este suspendat din diverse motive.3. De asemenea. ˆ care firele de executie pot fi ˆ ın ¸ ıntrerupte oricˆnd. va fi ales un fir cu o prioritate a mai mic˘. nepermitˆnd ¸i executia altora pˆn˘ la terminarea lor. dac˘ a a a un fir cu prioritate mai mare decˆt firul care se execut˘ la un moment dat a a solicit˘ procesorul. ˆ a acest lucru ıns˘ ¸ ın ıns˘ ˆ poate face sistemul de operare ˆ cazul ˆ care acesta aloc˘ procesorul ˆ ıl ın ın a ın cuante de timp (un astfel de SO este Windows).

// yield () . MAX_PRIORITY ) . } } } public class TestFirEgoist { public static void main ( String args []) { FirEgoist s1 . setPriority ( Thread . s1 .5: Exemplu de fir de executie ”egoist” ¸ class FirEgoist extends Thread { public FirEgoist ( String name ) { super ( name ) . ˆ a nu trebuie s˘ ne baz˘m pe acest a ¸ ıns˘ a a lucru la scrierea unui program. Unele sistemele de oper¸ a a are combat acest tip de comportament prin metoda aloc˘rii procesorului ˆ a ın cuante de timp fiec˘rui fir de executie. } public void run () { int i = 0. s1 = new FirEgoist ( " Firul 1 " ) . Evident. FIRE DE EXECUTIE ¸ Atentie ¸ In nici un caz corectitudinea unui program nu trebuie s˘ se bazeze pe a mecansimul de planificare a firelor de executie. s2 . Un fir de executie de lung˘ durat˘ ¸i care nu cedeaz˘ explicit procesorul la ¸ a as a anumite intervale de timp astfel ˆ at s˘ poata fi executate ¸i celelalte fire de ıncˆ a s executie se nume¸te fir de executie egoist. trebuie evitat˘ scrierea lor ¸ s ¸ a ˆ ıntrucˆt acapareaz˘ pe termen nedefinit procesorul. Un fir de executie trebuie s˘ fie ”corect” ¸ a fat˘de celelalte fire ¸i s˘ cedeze periodic procesorul astfel ˆ at toate s˘ aib˘ ¸a s a ıncˆ a a posibilitatea de a se executa. out . s2 = new FirEgoist ( " Firul 2 " ) . MAX_PRIORITY ) . if ( i % 100 == 0) System . blocˆnd efectiv executia a a a ¸ celorlalte fire de executie pˆn˘ la terminarea sa.360 CAPITOLUL 12. . setPriority ( Thread . println ( getName () + " a ajuns la " + i ) . while ( i < 100000) { // Bucla care acapareaza procesorul i ++. Listing 12. s2 . deoarece acesta poate fi diferit ¸ de la un sistem de operare la altul.

care determin˘ firul de executie curent s˘ se opreasc˘ tema ¸ a a porar. Firul Firul Firul Firul .. start () . fie prin ”adormirea” temporar˘ a s a a a firului curent cu ajutorul metodei sleep. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ s1 . Prin metoda yield un fir de executie nu cedeaz˘ procesorul decˆt firelor de executie care au aceea¸i pri¸ a a ¸ s oritate cu a sa ¸i nu celor cu priorit˘¸i mai mici..3.. Firul Firul 1 a ajuns la 100 1 a ajuns la 200 1 a ajuns la 300 1 1 2 2 a a a a ajuns ajuns ajuns ajuns la la la la 99900 100000 100 200 2 a ajuns la 99900 2 a ajuns la 100000 Rezolvarea acestei probleme se face fie prin intermediul metodei statice yield a clasei Thread.. 1 1 2 1 2 2 a a a a a a ajuns ajuns ajuns ajuns ajuns ajuns la la la la la la 31900 32000 100 32100 200 300 . Decomentˆnd linia ˆ care s at a ın apel˘m yeld din exemplul anterior. s2 . a ¸ a .. Firul Firul Firul Firul Firul Firul . dˆnd ocazia ¸i altor fire s˘ se execute. executia celor dou˘ fire se va intercala. acaparˆnd ¸ a ¸ a efectiv procesorul... Rezultatul va ar˘ta astfel: a Firul Firul Firul . start () .12.. } } 361 Firul de executie s1 are prioritate maxim˘ ¸i pˆn˘ nu-¸i va termina ¸ a s a a s executia nu-i va permite firului s2 s˘ execute nici o instructiune.

respectiv o zon˘ de memorie ¸i. s a S˘ consider˘m de exemplu o aplicatie Java ˆ care un fir de executie (proa a ¸ ın ¸ duc˘torul) scrie date ˆ a ıntr-un fi¸ier ˆ timp ce alt fir de executie (consumas ın ¸ torul) cite¸te date din acela¸i fi¸ier pentru a le prelucra. ˆ a a a s s a a ıntr-un buffer iar consumatorul cite¸te numerele din acel buffer pentru a le procesa.3. FIRE DE EXECUTIE ¸ 12.5 Scenariul produc˘tor / consumator a Pentru a ˆ ıntelege mai bine modalitatea de sincronizare a dou˘ fire de executie a ¸ s˘ implement˘m efectiv o problem˘ de tip produc˘tor/consumator. fiecare la un interval neregulat cuprins ˆ ıntre 0 ¸i 100 de milisecunde.362 CAPITOLUL 12. numerele generate de c˘tre proa a duc˘tor ¸i va afi¸a valoarea lor pe ecran. S˘ cona a a a a sider˘m urm˘toarea situatie: a a ¸ • Produc˘torul genereaz˘ numerele ˆ a a ıntregi de la 1 la 10. Cel mai elocvent scenariu ˆ care firele de executie ın ¸ trebuie s˘ se comunice ˆ a ıntre ele este cunoscut sub numele de problema produc˘torului/consumatorului. din acest motiv.3. a s s Pentru a fi accesibil˘ ambelor fire de executie. vom ˆ a ¸ ıncapsula variabila ce va contine numerele generate ˆ ıntr-un obiect descris de clasa Buffer ¸i care va s avea dou˘ metode put (pentru punerea unui numar ˆ buffer) ¸i get (pentru a ın s obtinerea numarului din buffer). dar care ruleaz˘ concurent. a a s a s ele trebuie sincronizate ˆ ıntr-o manier˘ care s˘ permit˘ decurgerea normal˘ a a a a a activit˘¸ii lor. Pe m˘sura ce s a le genereaz˘ ˆ a ıncearc˘ s˘ le plaseze ˆ a a ıntr-o zon˘ de memorie (o variabil˘ a a ˆ ıntreaga) de unde s˘ fie citite de c˘tre consumator. Exist˘ ˆ a numeroase situatii cˆnd fire de executie a ıns˘ ¸ a ¸ separate. pe rˆnd. a a • Consumatorul va prelua. trebuie s˘ comunice ˆ a a ıntre ele pentru a accesa diferite resurse comune sau pentru a-¸i transmite dinamic rezuls tatele ”muncii” lor. cu alte cuvinte care nu depind ˆ nici un fel de executia sau de ın ¸ rezultatele altor fire. pe rˆnd. In ams bele cazuri avem de-a face cu fire de executie concurente care folosesc o ¸ resurs˘ comun˘: un fi¸ier. s˘ presupunem s s s a c˘ produc˘torul genereaz˘ ni¸te numere ¸i le plaseaz˘. at 12.4 Sincronizarea firelor de executie ¸ Pˆn˘ acum am v˘zut cum putem crea fire de executie independente ¸i asa a a ¸ s incrone. Sau. ˆ care produc˘torul genereaz˘ un flux de date a ın a a care este preluat ¸i prelucrat de c˘tre consumator. .

random () * 100) ) . a ı¸ a Listing 12.7: Clasele Producator ¸i Consumator s class Producator extends Thread { private Buffer buffer . i ++) { buffer . put ( i ) .6: Clasa Buffer f˘r˘ sincronizare aa class Buffer { private int number = -1. try { sleep (( int ) ( Math .12. public int get () { return number . } } Vom implementa acum clasele Producator ¸i Consumator care vor descrie s cele dou˘ fire de executie. } public void run () { for ( int i = 0. public Producator ( Buffer b ) { buffer = b . i < 10. public Consumator ( Buffer b ) { buffer = b . number = number . out . } public void put ( int number ) { this . System .3. . println ( " Producatorul a pus :\ t " + i ) . CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ 363 F˘r˘ a folosi nici un mecanism de sincronizare clasa Buffer arat˘ astfel: aa a Listing 12. Ambele vor avea o referinta comun˘ la un obiect a ¸ ¸ a de tip Buffer prin intermediul c˘ruia ˆsi comunic˘ valorile. } catch ( InterruptedE x c e p t i o n e ) { } } } } class Consumator extends Thread { private Buffer buffer .

Producator p1 = new Producator ( b ) . out . i < 10. p1 . get () . motivul fiind lipsa oric˘rei sina a croniz˘ri ˆ a ıntre cele dou˘ fire de executie. } } Dup˘ cum ne a¸teptam. Consumator c1 = new Consumator ( b ) . rezultatul rul˘rii acestui program nu va rezolva a s a nici pe departe problema propus˘ de noi.364 } CAPITOLUL 12. println ( " Consumatorul a primit :\ t " + value ) . for ( int i = 0. c1 . System . Mai precis. FIRE DE EXECUTIE ¸ public void run () { int value = 0. rezultatul va fi ceva de a ¸ forma: Consumatorul Consumatorul Producatorul Consumatorul Consumatorul Consumatorul Consumatorul Consumatorul Consumatorul Consumatorul Consumatorul Producatorul Producatorul Producatorul Producatorul Producatorul a a a a a a a a a a a a a a a a primit: primit: pus: primit: primit: primit: primit: primit: primit: primit: primit: pus: pus: pus: pus: pus: -1 -1 0 0 0 0 0 0 0 0 0 1 2 3 4 5 . start () . start () . i ++) { value = buffer . } } } public class TestSincron izare1 { public static void main ( String [] args ) { Buffer b = new Buffer () .

12.3. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ Producatorul Producatorul Producatorul Producatorul a a a a pus: pus: pus: pus: 6 7 8 9

365

Ambele fire de executie acceseaz˘ resursa comun˘, adic˘ obiectul de tip ¸ a a a Buffer, ˆ ıntr-o manier˘ haotic˘ ¸i acest lucru se ˆ ampla din dou motive : a as ıntˆ • Consumatorul nu a¸teapt˘ ˆ s a ınainte de a citi ca produc˘torul s˘ genereze a a un num˘r ¸i va prelua de mai multe ori acela¸i num˘r. a s s a • Produc˘torul nu a¸teapt˘ consumatorul s˘ preia num˘rul generat ˆ a s a a a ınainte de a produce un altul, ˆ felul acesta consumatorul va ”rata” cu sigurant˘ ın ¸a unele numere (ˆ cazul nostru aproape pe toate). ın Problema care se ridic˘ ˆ acest moment este: cine trebuie s˘ se ocupe de a ın a sincronizarea celor dou˘ fire de executie : clasele Producator ¸i Consumator a ¸ s sau resursa comuna Buffer ? R˘spunsul este evident: resursa comun˘ a a Buffer, deoarece ea trebuie s˘ permita sau nu accesul la continutul s˘u ¸i a ¸ a s nu firele de executie care o folosesc. In felul acesta efortul sincroniz˘rii este ¸ a transferat de la produc˘tor/consumator la un nivel mai jos, cel al resursei a critice. Activit˘¸ile produc˘torului ¸i consumatorului trebuie sincronizate la nivelul at a s resursei comune ˆ dou˘ privinte: ın a ¸ • Cele dou˘ fire de executie nu trebuie s˘ acceseze simultan buffer-ul; a ¸ a acest lucru se realizeaz˘ prin blocarea obiectului Buffer atunci cˆnd a a este accesat de un fir de executie, astfel ˆ at nici nu alt fir de executie ¸ ıncˆ ¸ s˘ nu-l mai poat˘ accesa (vezi ”Monitoare”). a a • Cele dou˘ fire de executie trebuie s˘ se coordoneze, adic˘ produc˘torul a ¸ a a a trebuie s˘ g˘seasc˘ o modalitate de a ”spune” consumatorului c˘ a a a a a plasat o valoare ˆ buffer, iar consumatorul trebuie s˘ comunice proın a duc˘torului c˘ a preluat aceast˘ valoare, pentru ca acesta s˘ poat˘ gena a a a a era o alta. Pentru a realiza aceasta comunicare, clasa Thread pune la dispozitie metodele wait, notify, notifyAll. (vezi ”Semafoare”). ¸ Folosind sincronizarea clasa Buffer va ar˘ta astfel: a

366

CAPITOLUL 12. FIRE DE EXECUTIE ¸ Listing 12.8: Clasa Buffer cu sincronizare

class Buffer { private int number = -1; private boolean available = false ; public synchronized int get () { while (! available ) { try { wait () ; // Asteapta producatorul sa puna o valoare } catch ( Inter r u p t e d E x c e p t i o n e ) { e . printStackTrace () ; } } available = false ; notifyAll () ; return number ; } public synchronized void put ( int number ) { while ( available ) { try { wait () ; // Asteapta consumatorul sa preia valoarea } catch ( Inter r u p t e d E x c e p t i o n e ) { e . printStackTrace () ; } } this . number = number ; available = true ; notifyAll () ; } }

Rezultatul obtinut va fi cel scontat: Producatorul Consumatorul Producatorul Consumatorul ... Producatorul Consumatorul a a a a pus: primit: pus: primit: 0 0 1 1

a pus: 9 a primit: 9

12.3. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸

367

12.3.6

Monitoare

Definitie ¸ Un segment de cod ce gestioneaz˘ o resurs˘ comun˘ mai multor de fire de a a a executie separate concurente se nume¸te sectiune critic˘. In Java, o sectiune ¸ s ¸ a ¸ critic˘ poate fi un bloc de instructiuni sau o metod˘. a ¸ a Controlul accesului ˆ ıntr-o sectiune critic˘ se face prin cuvˆntul cheie syn¸ a a chronized. Platforma Java asociaz˘ un monitor (”lac˘t”) fiec˘rui obiect al a a a unui program aflat ˆ executie. Acest monitor va indica dac˘ resursa critic˘ ın ¸ a a este accesat˘ de vreun fir de executie sau este liber˘, cu alte cuvinte ”mona ¸ a itorizeaz˘” resursa respectiv˘. In cazul ˆ care este accesat˘, va pune un a a ın a lac˘t pe aceasta, astfel ˆ at s˘ ˆ a ıncˆ a ımpiedice accesul altor fire de executie la ea. ¸ In momentul cˆnd resursa este eliberat˘ ”lac˘tul” va fi eliminat, pentru a a a a permite accesul altor fire de executie. ¸ In exemplul de tip produc˘tor/consumator de mai sus, sectiunile critice a ¸ sunt metodele put ¸i get iar resursa critic˘ comun˘ este obiectul buffer. s a a Consumatorul nu trebuie s˘ acceseze buffer-ul cˆnd producatorul tocmai a a pune o valoare ˆ el, iar produc˘torul nu trebuie s˘ modifice valoarea din ın a a buffer ˆ momentul cˆnd aceasta este citit˘ de c˘tre consumator. ın a a a public synchronized int get() { ... } public synchronized void put(int number) { ... } S˘ observam c˘ ambele metode au fost declarate cu modificatorul synchronized. a a Cu toate acestea, sistemul asociaz˘ un monitor unei instante a clasei Buffer a ¸ ¸i nu unei metode anume. In momentul ˆ care este apelat˘ o metod˘ sins ın a a cronizat˘, firul de executie care a facut apelul va bloca obiectul a c˘rei metod˘ a ¸ a a o acceseaz˘, ceea ce ˆ a ınseamn˘ c˘ celelalte fire de executie nu vor mai putea a a ¸ accesa resursele critice ale acelui obiect. Acesta este un lucru logic, deoarece mai multe sectiuni critice ale unui obiect gestioneaz˘ de fapt o singur˘ resurs˘ ¸ a a a critic˘. a In exemplul nostru, atunci cˆnd producatorul apeleaz˘ metoda put pena a tru a scrie un num˘r, va bloca tot obiectul buffer, astfel c˘ firul de executie a a ¸

368

CAPITOLUL 12. FIRE DE EXECUTIE ¸

consumator nu va avea acces la metoda get, ¸i reciproc. s public synchronized void put(int number) { // buffer blocat de producator ... // buffer deblocat de producator } public synchronized int get() { // buffer blocat de consumator ... // buffer deblocat de consumator }

Monitoare fine Adeseori, folosirea unui monitor pentru ˆ ıntreg obiectul poate fi prea restrictiv˘. De ce s˘ bloc˘m toate resursele unui obiect dac˘ un fir de executie a a a a ¸ nu dore¸te decˆt accesarea uneia sau a cˆtorva dintre ele ? Deoarece orice s a a obiect are un monitor, putem folosi obiecte fictive ca lac˘te pentru fiecare a din resursele obiectului nostru, ca ˆ exemplul de mai jos: ın class MonitoareFine { //Cele doua resurse ale obiectului Resursa x, y; //Folosim monitoarele a doua obiecte fictive Object xLacat = new Object(), yLacat = new Object(); public void metoda() { synchronized(xLacat) { // Accesam resursa x } // Cod care nu foloseste resursele comune ... synchronized(yLacat) { // Accesam resursa y }

12.3. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ ... synchronized(xLacat) { synchronized(yLacat) { // Accesam x si y } } ... synchronized(this) { // Accesam x si y } } }

369

Metoda de mai sus nu a fost declarat˘ cu synchronized ceea ce ar fi dea terminat blocarea tuturor resurselor comune la accesarea obiectului respectiv de un fir de executie, ci au fost folosite monitoarele unor obiecte fictive pentru ¸ a controla folosirea fiec˘rei resurs˘ ˆ parte. a a ın

12.3.7

Semafoare

Obiectul de tip Buffer din exemplul anterior are o variabil˘ membr˘ privat˘ a a a numit˘ number, ˆ care este memorat num˘rul pe care ˆ comunic˘ produa ın a ıl a catorul ¸i pe care ˆ preia consumatorul. De asemenea, mai are o variabil˘ s ıl a privat˘ logic˘ available care ne d˘ starea buffer-ului: dac˘ are valoarea true a a a a ˆ ınseamn˘ c˘ produc˘torul a pus o valoare ˆ buffer ¸i consumatorul nu a a a a ın s preluat-o ˆ ınca; dac˘ este false, consumatorul a preluat valoarea din buffer a dar produc˘torul nu a pus deocamdat˘ alta la loc. Deci, la prima vedere, a a metodele clasei Buffer ar trebui s˘ arate astfel: a public synchronized int get() { while (!available) { // Nimic - asteptam ca variabila sa devina true } available = false; return number; } public synchronized int put(int number) { while (available) {

370

CAPITOLUL 12. FIRE DE EXECUTIE ¸ // Nimic - asteptam ca variabila sa devina false } available = true; this.number = number;

} Varianta de mai sus, de¸i pare corect˘, nu este. Aceasta deoarece ims a plementarea metodelor este ”selfish”, cele dou˘ metode ˆ asteapt˘ ˆ mod a ısi a ın egoist conditia de terminare. Ca urmare, corectitudinea function˘rii va de¸ ¸ a pinde de sistemul de operare pe care programul este rulat, ceea ce reprezint˘ a o gre¸eal˘ de programare. s a Punerea corect˘ a unui fir de executie ˆ asteptare se realizeaz˘ cu metoda a ¸ ın a wait a clasei Thread, care are urm˘toarele forme: a void wait( ) void wait( long timeout ) void wait( long timeout, long nanos ) Dup˘ apelul metodei wait, firul de executie curent elibereaz˘ monitorul a ¸ a asociat obiectului respectiv ¸i a¸teapt˘ ca una din urm˘toarele conditii s˘ fie s s a a ¸ a ˆ ındeplinit˘: a • Un alt fir de executie informeaz˘ pe cei care ”a¸teapt˘” la un anumit ¸ a s a monitor s˘ se ”trezeasc˘” - acest lucru se realizeaz˘ printr-un apel al a a a metodei notifyAll sau notify. • Perioada de a¸tepatare specificat˘ a expirat. s a Metoda wait poate produce exceptii de tipul InterruptedException, ¸ atunci cˆnd firul de executie care a¸teapt˘ (este deci ˆ starea ”Not Runnable”) a ¸ s a ın este ˆ ıntrerupt din a¸teptare ¸i trecut fortat ˆ starea ”Runnable”, de¸i conditia s s ¸ ın s ¸ a¸teptat˘ nu era ˆ a ˆ s a ınc˘ ındeplinit˘. a Metoda notifyAll informeaz˘ toate firele de executie care sunt ˆ asteptare a ¸ ın la monitorul obiectului curent ˆ ındeplinirea conditiei pe care o a¸teptau. Metoda ¸ s notify informeaz˘ doar un singur fir de executie, specificat ca argument. a ¸ Reamintim varianta corect˘ a clasei Buffer: a Listing 12.9: Folosirea semafoarelor
class Buffer { private int number = -1;

12.3. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸
private boolean available = false ; public synchronized int get () { while (! available ) { try { wait () ; // Asteapta producatorul sa puna o valoare } catch ( InterruptedE x ce pt io n e ) { e . printStackTrace () ; } } available = false ; notifyAll () ; return number ; } public synchronized void put ( int number ) { while ( available ) { try { wait () ; // Asteapta consumatorul sa preia valoarea } catch ( InterruptedE x c e p t i o n e ) { e . printStackTrace () ; } } this . number = number ; available = true ; notifyAll () ; } }

371

12.3.8

Probleme legate de sincronizare

Din p˘cate, folosirea monitoarelor ridic˘ ¸i unele probleme. S˘ analiz˘m a a s a a cˆteva dintre ele ¸i posibilele lor solutii: a s ¸ Deadlock Deadlock-ul este o problem˘ clasic˘ ˆ a a ıntr-un mediu ˆ care ruleaz˘ mai multe ın a fire de executie ¸i const˘ ˆ faptul c˘, la un moment dat, ˆ ¸ s a ın a ıntreg procesul se poate bloca deoarece unele fire a¸teapt˘ deblocarea unor monitoare care s a nu se vor debloca niciodat˘. Exist˘ numeroase exemple ˆ acest sens, cea a a ın mai cunoscut˘ fiind ”Problema filozofilor”. Reformulat˘, s˘ ne imagin˘m a a a a dou˘ persoane ”A” ¸i ”B” (fire de executie) care stau la aceea¸i mas˘ ¸i trea s ¸ s as

372

CAPITOLUL 12. FIRE DE EXECUTIE ¸

buie s˘ foloseasc˘ ˆ comun cutitul ¸i furculita (resursele comune) pentru a a a ın ¸ s ¸ mˆnca. Evident, cele dou˘ persoane doresc obtinerea ambelor resurse. S˘ a a ¸ a presupunem c˘ ”A” a otinut cutitul ¸i ”B” furculita. Firul ”A” se va bloca ˆ a ¸ ¸ s ¸ ın a¸teptarea eliber˘rii furculitei iar firul ”A” se va bloca ˆ a¸tepatrea eliber˘rii s a ¸ ın s a cutitului, ceea ce conduce la starea de ”deadlock”. De¸i acest exemplu este ¸ s desprins de realitate, exist˘ numeroase situatii ˆ care fenomenul de ”deada ¸ ın lock” se poate manifesta, multe dintre acestea fiind dificil de detectat. Exist˘ cˆteva reguli ce pot fi aplicate pentru evitarea deadlock-ului: a a • Firele de executie s˘ solicite resursele ˆ aceea¸i ordine. Aceast˘ abor¸ a ın s a dare elimin˘ situatiile de a¸teptare circular˘. a ¸ s a • Folosirea unor monitoare care s˘ controleze accesul la un grup de resurse. a In cazul nostru, putem folosi un monitor ”tacˆmuri” care trebuie blocat a ˆ ınainte de a cere furculita sau cutitul. ¸ ¸ • Folosirea unor variabile care s˘ informeze disponibilitatea resurselor a f˘r˘ a bloca monitoarele asociate acestora. aa • Cel mai importat, conceperea unei arhitecturi a sistemului care s˘ evite a pe cˆt posibil aparitia unor potentiale situatii de deaslock. a ¸ ¸ ¸

Variabile volatile Cuvˆntul cheie volatile a fost introdus pentru a controla unele aspecte a legate de optimiz˘rile efectuate de unele compilatoare. S˘ consider˘m urm˘torul a a a a exemplu: class TestVolatile { boolean test; public void metoda() { test = false; // * if (test) { // Aici se poate ajunge... } } }

12.4. GRUPAREA FIRELOR DE EXECUTIE ¸

373

Un compilator care optimizeaz˘ codul, poate decide c˘ variabila test fia a ind setat˘ pe false, corpul if -ului nu se va executa ¸i s˘ exclud˘ secventa a s a a ¸ respectiv˘ din rezultatul compil˘rii. Dac˘ aceast˘ clas˘ ar fi ˆ a accesat˘ a a a a a ıns˘ a de mai multe fire de executie, variabile test ar putea fi setat˘ pe true de un ¸ a alt fir, exact ˆ ıntre instructiunile de atribuire ¸i if ale firului curent. ¸ s Declararea unei variabile cu modificatorul volatile informeaz˘ compilaa torul s˘ nu optimizeze codul ˆ care aceasta apare, previzionˆnd valoarea pe a ın a care variabila o are la un moment dat.

Fire de executie inaccesibile ¸ Uneori firele de executie sunt blocate din alte motive decˆt a¸teptarea la ¸ a s un monitor, cea mai frecvent˘ situatie de acest tip fiind operatiunile de ina ¸ ¸ trare/ie¸ire (IO) blocante. Cˆnd acest lucru se ˆ ampl˘ celelalte fire de s a ınt˘ a executie trebuie s˘ poat˘ accesa ˆ continuare obiectul. Dar dac˘ operatiunea ¸ a a ın a ¸ IO a fost f˘cut˘ ˆ a a ıntr-o metod˘ sincronizat˘, acest lucru nu mai este posibil, a a monitorul obiectului fiind blocat de firul care a¸teapt˘ de fapt s˘ realizeze s a a operatia de intrare/ie¸ire. Din acest motiv, operatiile IO nu trebuie f˘cute ¸ s ¸ a ˆ metode sincronizate. ın

12.4

Gruparea firelor de executie ¸

Gruparea firelor de executie pune la dispozitie un mecanism pentru manipu¸ ¸ larea acestora ca un tot ¸i nu individual. De exemplu, putem s˘ pornim sau s˘ s a a suspend˘m toate firele dintr-un grup cu un singur apel de metod˘. Gruparea a a firelor de executie se realizeaz˘ prin intermediul clasei ThreadGroup. ¸ a Fiecare fir de executie Java este membru al unui grup, indiferent dac˘ ¸ a specific˘m explicit sau nu acest lucru. Afilierea unui fir la un anumit grup a se realizeaz˘ la crearea sa ¸i devine permanent˘, ˆ sensul c˘ nu vom putea a s a ın a muta un fir dintr-un grup ˆ altul, dup˘ ce acesta a fost creat. In cazul ˆ ın a ın care cre˘m un fir folosind un constructor care nu specific˘ din ce grup face a a parte, el va fi plasat automat ˆ acela¸i grup cu firul de executie care l-a ın s ¸ creat. La pornirea unui program Java se creeaz˘ automat un obiect de tip a ThreadGroup cu numele main, care va reprezenta grupul tuturor firelor de executie create direct din program ¸i care nu au fost ata¸ate explicit altui ¸ s s grup. Cu alte cuvinte, putem s˘ ignor˘m complet plasarea firelor de executie a a ¸ ˆ grupuri ¸i s˘ l˘s˘m sistemul s˘ se ocupe cu aceasta, adunˆndu-le pe toate ın s a aa a a

Thread p1 = new Thread(grup1. new Thread(grup2. "Producator 2"). ceea ce ˆ a ınseamn˘ c˘ firele de a a executie pot fi plasate ˆ ¸ ıntr-o ierarhie de grupuri. String name) public Thread(ThreadGroup group. primul cu a a dou˘ fire de executie iar al doilea cu trei: a ¸ ThreadGroup grup1 = new ThreadGroup("Producatori"). new Thread(grup2. "Consumator 2"). String name) Fiecare din ace¸ti costructori creeaz˘ un fir de executie. ca ˆ figura de mai jos: ın . "Consumator 1"). ˆ care r˘d˘cina este grupul ın a a implicit main. ThreadGroup Thread c1 = Thread c2 = Thread c3 = grup2 = new ThreadGroup("Consumatori"). Un grup poate avea ca p˘rinte un alt grup. Runnable target. FIRE DE EXECUTIE ¸ ˆ grupul main. Thread p2 = new Thread(grup1. ın Exist˘ situatii ˆ a cˆnd gruparea firelor de executie poate u¸ura substantial a ¸ ıns˘ a ¸ s ¸ manevrarea lor. ˆ initializeaz˘ ¸i s a ¸ ıl ¸ a s ˆ plaseaz˘ ˆ ıl a ıntr-un grup specificat ca argument. "Producator 1"). In exemplul urm˘tor vor fi create dou˘ grupuri.374 CAPITOLUL 12. "Consumator 3"). Crearea unui fir de executie ¸i plasarea lui ˆ ¸ s ıntr-un grup (altul decˆt cel implicit) se realizeaz˘ prin urm˘torii constructori ai clasei Thread: a a a public Thread(ThreadGroup group. Runnable target) public Thread(ThreadGroup group. Pentru a afla c˘rui grup a apartine un anumit fir de executie putem folosi metoda getThreadGroup a ¸ ¸ clasei Thread. new Thread(grup2.

GRUPAREA FIRELOR DE EXECUTIE ¸ S˘ consider˘m un exemplu ˆ care list˘m firele de executie active: a a ım a ¸ 375 Listing 12. // Le afisam for ( int i =0. awt . // Obtinem o referinta la grupul curent Thread firCurent = Thread . enumerate ( lista ) .12. i ++) System . // Enumeram firele din grup Thread [] lista = new Thread [ n ]. println ( " Thread # " + i + " = " + lista [ i ]. ThreadGroup grupCurent = firCurent . " Fir de test " ) .10: Folosirea clasei ThreadGroup public class TestThreadGroup { static class Dummy implements Runnable { public void run () { while ( true ) Thread . start () .4. yield () . // Cream un fir propriu new Thread ( new Dummy () . // Aflam numarul firelor de executie active int n = grupCurent . activeCount () . Frame f = new java . grupCurent . getName () ) . currentThread () . } } public static void main ( String args []) { // Cream o fereastra pentru a fi create // automat firele de executie din AWT java . } } . out . Frame ( " Test " ) . getThreadGroup () . awt . i < n .

pr2 = new PipedReader().5 Comunicarea prin fluxuri de tip ”pipe” O modalitate deosebit de util˘ prin care dou˘ fire de executie pot comunica a a ¸ este realizat˘ prin intermediul canalelor de comunicatii (pipes).pentru caractere. firele a a de executie comunicˆnd printr-un canal. pr1 = new PipedReader(pw1). pw2 = new PipedWriter(pr2). La citire. PipedInputStream . dac˘ nu sunt date disponibile a a firul de executie se va bloca pˆn˘ ce acestea vor deveni disponibile. ¸ a Realizarea conexiunii se face astfel: PipedWriter PipedReader // sau PipedReader PipedWriter // sau pw1 = new PipedWriter(). Acestea sunt a implementate prin fluxuri descrise de clasele: • PipedReader. respectiv • PipedOutputStream.376 CAPITOLUL 12. Fiecare cap˘t a a a al unui canal este utilizat dintr-un fir de executie separat. Se observ˘ ¸ a a a c˘ acesta este un comportament tipic produc˘tor-consumator asincron. la cel˘lalt se citesc. La un cap˘t se ¸ a scriu caractere. ¸ Fluxurile ”pipe” de ie¸ire ¸i cele de intrare pot fi conectate pentru a s s efectua transmiterea datelor. FIRE DE EXECUTIE ¸ 12. ¸ Functionarea obicetelor care instantiaz˘ PipedWriter ¸i PipedReader ¸ ¸ a s este asem˘n˘toare cu a canalelor de comunicare UNIX (pipes). folosirea lor se va face din cadrul unor fire ¸ de executie. conectarea unui ın aa flux de intrare cu un flux de ie¸ire se face prin metoda connect: s public void connect(PipedWriterpw) public void connect(PipedReaderpr) Intrucˆt fluxurile care sunt conectate printr-un pipe trebuie s˘ execute a a simultan operatii de scriere/citire. Acest lucru se realizeaz˘ uzual prin intemediul a constructorilor: public PipedReader(PipedWriterpw) public PipedWriter(PipedReaderpr) In cazul ˆ care este folosit un constructor f˘r˘ argumente. . PipedWriter .pentru octeti.

11: Folosirea fluxurilor de tip ”pipe” import java . Produc˘torul trimite datele printr-un ¸ a flux de ie¸ire de tip DataOutputStream c˘tre consumator. io . i < 10.12. folosind canale de comunicatie. PipedWriter pw = new PipedWirter(). } catch ( IOException e ) { e . public Consumator ( DataInputStream in ) { this . out . pr. care le prime¸te s a s printr-un flux de intrare de tip DataInputStream. } public void run () { for ( int i = 0. out = out . Listing 12.5. } catch ( InterruptedE x c e p t i o n e ) { } } } } class Consumator extends Thread { private DataInputStream in . ın S˘ reconsider˘m acum exemplul produc˘tor/consumator prezentat antea a a rior. random () * 100) ) .*. class Producator extends Thread { private DataOutputStream out . ˆ toate formele lor. COMUNICAREA PRIN FLUXURI DE TIP ”PIPE” PipedReader pr = new PipedReader(). i ++) { try { out . public Producator ( DataOutputStream out ) { this .connect(pw) //echivalent cu pw. writeInt ( i ) . Aceste dou˘ fluxuri vor fi a interconectate prin intermediul unor fluxuri de tip ”pipe”. try { sleep (( int ) ( Math . 377 Scrierea ¸i citirea pe/de pe canale se realizeaz˘ prin metodele uzuale read ¸i s a s write. println ( " Producatorul a pus :\ t " + i ) . in = in .connect(pr). . printStackTrace () . } System .

printStackTrace () . println ( " Consumatorul a primit :\ t " + value ) . } } } public class TestPipes { public static void main ( String [] args ) throws IOException { PipedOutputStream pipeOut = new Pipe dOutput Stream () .378 } CAPITOLUL 12. out . i < 10. DataInputStream in = new DataInputStream ( pipeIn ) . Producator p1 = new Producator ( out ) . a ¸ a ın Actiunile unui obiect de tip Timer sunt implementate ca instante ale clasei ¸ ¸ TimerTask ¸i pot fi programate pentru o singur˘ executie sau pentru executii s a ¸ ¸ repetate la intervale regulate. } } 12. DataOutputStream out = new DataOutputStream ( pipeOut ) . FIRE DE EXECUTIE ¸ public void run () { int value = 0.6 Clasele Timer ¸i TimerTask s Clasa Timer ofer˘ o facilitate de a planifica diverse actiuni pentru a fi reala ¸ izate la un anumit moment de c˘tre un fir de executie ce ruleaz˘ ˆ fundal. i ++) { try { value = in . PipedInputStream pipeIn = new PipedInputStream ( pipeOut ) . start () . readInt () . p1 . for ( int i = 0. } catch ( IOException e ) { e . start () . c1 . Consumator c1 = new Consumator ( in ) . Pa¸ii care trebuie f˘cuti pentru folosirea unui timer sunt: s a ¸ . } System .

long period) task.planificare cu ˆ arziere fix˘: dac˘ dintr-un anumit motiv ıntˆ a a actiunea este ˆ arziat˘. De asemenea. Date schedule(TimerTask task. metoda System. long schedule(TimerTask task. folosind metoda ¸ schedule din clasa Timer. Date scheduleAtFixedRate(TimerTask scheduleAtFixedRate(TimerTask time) delay. urm˘toarele actiuni vor fi ¸ ıntˆ a a ¸ executat˘ mai repede. time momentul exact la ¸ care va ˆ ıncepe executia iar period intervalul de timp ˆ ¸ ıntre dou˘ executii. long period) unde. CLASELE TIMER SI TIMERTASK ¸ 379 • Crearea unei subclase Actiune a lui TimerTask ¸i supreadefinirea metodei s run ce va contine actiunea pe care vrem s˘ o planific˘m. ¸ ¸ s ¸ a . ¸a • scheduleAtFixedRate .6. Metodele de planificare pe care le avem la dispozitie au urm˘toarele for¸ a mate: schedule(TimerTask task. Dup˘ cum ¸ ¸ a a a vom vedea.exit ¸ va oprit fortat toate firele de executie ¸i va termina aplicatia curent˘. metodele de planificare se ˆ a a ımpart ˆ dou˘ categorii: ın a • schedule . s • Crearea unui fir de executie prin instantierea clasei Timer. urm˘toarele actiuni vor fi ¸i ele ˆ arziate ˆ ¸ ıntˆ a a ¸ s ıntˆ ın consecint˘.planificare cu num˘r fix de rate: dac˘ dintra a un anumit motiv actiunea este ˆ arziat˘. delay reprezint˘ ˆ arzierea fata ¸ a ıntˆ ¸ de momentul curent dup˘ care va ˆ a ıncepe executia. long delay. Date time. a a s Un timer se va opri natural la terminarea metodei sale run sau poate fi oprit fortat folosind metoda cancel. long period) task.12. long period) time. Dup˘ oprirea sa el nu va mai putea fi ¸ a folosit pentru planificarea altor actiuni. • Planificarea la executie a obiectuluii de tip Actiune. task descrie actiunea ce se va executa. ¸ ¸ • Crearea unui obiect de tip Actiune. astfel ˆ at num˘rul total de actiuni dintr-o pea ıncˆ a ¸ rioad˘ de timp s˘ fie tot timpul acela¸i. pot fi folosite ¸i clase anonime. a ¸ Dup˘ cum se observ˘.

*. import java . class Atentie extends TimerTask { public void run () { Toolkit . println ( mesaj ) . FIRE DE EXECUTIE ¸ Listing 12. util . 0 . 1*1000) . out . " ) . // Setam o actiune pentru ora 22:30 Calendar calendar = Calendar . } } class Alarma extends TimerTask { public String mesaj . } } .12: Folosirea claselor Timer ¸i TimerTask s import java . calendar . cancel () . getTime () . getInstance () . 22) . // Oprim primul timer t1 . calendar . print ( " . 30) . set ( Calendar .380 CAPITOLUL 12. HOUR_OF_DAY . set ( Calendar . MINUTE . 10*1000) .au scurs 10 secunde . } } public class TestTimer { public static void main ( String args []) { // Setam o actiune repetitiva . out . set ( Calendar . mesaj = mesaj . awt . cu rata fixa final Timer t1 = new Timer () . public Alarma ( String mesaj ) { this . Date ora = calendar . SECOND . schedule ( new TimerTask () { public void run () { System . calendar . t2 . println ( "S . t1 . . 0) . } public void run () { System . System . // Folosim o clasa anonima pentru o alta actiune Timer t2 = new Timer () . getDefaultToolkit () . beep () . " ) .*. out . scheduleAtFix e d Ra t e ( new Atentie () .

12. t3 . CLASELE TIMER SI TIMERTASK ¸ 381 Timer t3 = new Timer () . schedule ( new Alarma ( " Toti copiii la culcare ! " ) .6. ora ) . } } .

FIRE DE EXECUTIE ¸ .382 CAPITOLUL 12.

1 Introducere Programarea ˆ retea implic˘ trimiterea de mesaje ¸i date ˆ ın ¸ a s ıntre aplicatii ce ¸ ruleaz˘ pe calculatoare aflate ˆ a ıntr-o retea local˘ sau conectate la Internet. c˘tre destinatie. era nevoie de stabilirea unor a ¸ a ¸ conventii (protocoale) care s˘ fie folosite atˆt de calculatorul care trimite ¸ a a datele cˆt ¸i de cel care le prime¸te. sunt necesare cˆteva notiuni fundamentale a ¸ referitoare la retele cum ar fi: protocol. port.Capitolul 13 Programare ˆ retea ın ¸ 13. ¸ a Pachetul care ofer˘ suport pentru scrierea aplicatiilor de retea este java. a s • TCP (Transport Control Protocol) este un protocol ce furnizeaz˘ un a flux sigur de date ˆ ıntre dou˘ calculatoare aflate ˆ retea. adresa IP. a ¸ Clasele din acest pachet ofer˘ o modalitate facil˘ de programare ˆ retea. socket. ¸ Ce este un protocol ? Un protocol reprezint˘ o conventie de reprezentare a datelor folosit˘ ˆ comua ¸ a ın nicarea ˆ ıntre dou˘ calculatoare.net. f˘r˘ a a ın ¸ aa a fi nevoie de cuno¸tinte prealabile referitoare la comunicarea efectiv˘ ˆ s ¸ a ıntre calculatoare. pentru a se ”ˆ ¸elege” ˆ a s s ınt ıntre ele. Cu toate acestea. Acest protoa ın ¸ col asigur˘ stabilirea unei conexiuni permanente ˆ a ıntre cele dou˘ calcua latoare pe parcursul comunicatiei. ¸ • UDP (User Datagram Protocol) este un protocol bazat pe pachete inde383 . octet cu octet. Dou˘ dintre cele mai utilizate protocoale sunt TCP ¸i UDP. Avˆnd ˆ vedere faptul c˘ orice informatie a a ın a ¸ care trebuie trimis˘ prin retea trebuie serializat˘ astfel ˆ at s˘ poat˘ fi transa ¸ a ıncˆ a a mis˘ secvential.

a Un port este un num˘r pe 16 biti care identific˘ ˆ mod unic procesele a ¸ a ın care ruleaz˘ pe o anumit˘ masin˘.384 CAPITOLUL 13. ın ¸ a ¸ Prin urmare. a a De asemenea. a Cum este identificat un calculator ˆ retea ? ın ¸ Orice calculator conectat la Internet este identificat ˆ mod unic de adresa sa ın IP (IP este acronimul de la Internet Protocol).net permit comunicarea ˆ ıntre procese folosind protocoalele . Corespunz˘toare unei s a a adrese numerice exista ¸i o adresa IP simbolic˘. Ins˘ pe un calculator pot exista concurent mai multe s a procese care au stabilite conexiuni ˆ retea. PROGRAMARE ˆ RETEA IN ¸ pendente de date. cum ar fi thor. uzual sub forma a 4 octeti. a Clasa Java care reprezint˘ notiunea de adres˘ IP este InetAddress. Valorile pe ın ¸ a s a care le poate lua un num˘r de port sunt cuprinse ˆ a ıntre 0 ¸i 65535 (deoarece s sunt numere reprezentate pe 16 biti).net a Clasele din java.131 ¸i este numit adresa IP numeric˘. a ¸ a Ce este un port ? Un calculator are ˆ general o singur˘ leg˘tur˘ fizic˘ la retea. cum ar fi de exemplu: ¸ ¸ 193. ¸ Clase de baz˘ din java. fiecare calculator aflat ˆ ıntr-o retea local˘ are un nume unic ¸ a ce poat fi folosit la identificarea local˘ a acestuia. nu trebuie folosite ˆ ıns˘ s ın aplicatii. din acest motiv. Identificarea proceselor se realizeaz˘ prin intermdiul porturilor. Acest protocol nu stabile¸te o conexiun˘ ın s a permant˘ ˆ a ıntre cele dou˘ calculatoare. asteptˆnd diverse informatii. trimise de la un calculator c˘tre a altul f˘r˘ a se garanta ˆ vreun fel ajungerea acestora la destinatie sau aa ın ¸ ordinea ˆ care acestea ajung.infoiasi.231. Aceasta reprezint˘ un num˘r a a reprezentat pe 32 de biti.ro s a pentru adresa numeric˘ anterioar˘. Orice aplicatie care realizeaz˘ o conexiune a a a ¸ a ˆ retea va trebui s˘ ata¸eze un num˘r de port acelei conexiuni.30. numite datagrame. Orice informatie ın a a a a ¸ ¸ destinat˘ unei anumite ma¸ini trebuie deci s˘ specifice obligatoriu adresa a s a IP a acelei ma¸ini. datele trimise c˘tre o destinatie trebuie s˘ specifice pe lˆnga a ¸ a a adresa IP a calculatorului ¸i procesul c˘tre care se ˆ s a ındreapt˘ informatiile a ¸ respective. numerele cuprinse ˆ ¸ ıntre 0 ¸i 1023 fiind s ˆ a rezervate unor servicii sistem ¸i.

ro/~acf/java/curs/9/prog_retea.ro/index. fi¸ierul ce reprezint˘ ın s a resursa va fi considerat implicit index. Mai jost. un text.ro/~acf/imgs/taz..infoiasi. Acesta are urm˘toarele componente: a – Numele calculatorului gazd˘ (www. ftp. etc. Aceasta este ˆ general un ¸a a a a ın fi¸ier reprezentˆnd o pagin˘ Web.2.2 Lucrul cu URL-uri Termenul URL este acronimul pentru Uniform Resource Locator ¸i reprezint˘ s a o referint˘ (adres˘) la o resurs˘ aflat˘ pe Internet.html.html). etc.sun.com http://students. imagine. ¸ ¸a ın s – Optional.infoiasi. LUCRUL CU URL-URI TCP ¸i UDP ¸i sunt prezentate ˆ tabelul de mai jos. In cazul ˆ care este specificat doar un director. ¸ a . ˆ a un URL poate s a a ıns˘ referi ¸i interog˘ri la baze de date. s s ın TCP URL URLConnection Socket ServerSocket UDP DatagramPacket DatagramSocket MulticastSocket 385 13.infoiasi.infoiasi. o referint˘ de tip anchor ˆ cadrul fi¸ierului referit (#url).ro). sunt prezentate cˆteva exemple de URL-uri sunt: ¸˘ a http://java. • Numele resursei referite.gif http://www. rezultate ale unor comenzi executate la s a distanta.html http://www. un URL are dou˘ coma a a ponente principale: • Identificatorul protocolului folosit (http. a a Notatia user semnific˘ uzual subdirectorul html al directoru¸ a lui rezervat pe un server Web utilizatorului specificat (HOME). – Optional.html#url Dup˘ cum se observ˘ din exemplele de mai sus. portul la care s˘ se realizeze conexiunea. a – Calea complet˘ spre resursa referit˘ ( acf/java/curs/9/prog retea.13. etc).

err. import java . s ¸ Citirea continutului unui URL ¸ Orice obiect de tip URL poate returna un flux de intrare de tip InputStream pentru citirea continutului s˘u. io .*. Dac˘ nu se specific˘ mici un argument.URL. } Un obiect de tip URL poate fi folosit pentru: • Aflarea informatiilor despre resursa referit˘ (numele calculatorului gazd˘. Secventa standard pentru aceast˘ operatiune a ¸ a este prezentat˘ ˆ exemplul de mai jos.386 CAPITOLUL 13. public class CitireURL { public static void main ( String [] args ) throws IOException { String adresa = " http :// www . PROGRAMARE ˆ RETEA IN ¸ Clasa care permite lucrul cu URL-uri este java.abc"). infoiasi .*. cel mai uzual fiind cel care prime¸te ca parametru ın ¸ s un ¸ir de caractere. protocolul folosit. In cazul ˆ care ¸irul nu reprezint˘ un URL valid va fi s ın s a aruncat˘ o exceptie de tipul MalformedURLException. s • Citirea printr-un flux a continutului fi¸ierului respectiv. net .println("URL invalid !\n" + e).1: Citirea continutului unui URL ¸ import java . s • Conectarea la acel URL pentru citirea ¸i scrierea de informatii. a ¸ try { URL adresa = new URL("http://xyz. ro " . s s Listing 13. va fi a a a a afi¸at fi¸ierul index. ˆ care afi¸am continutul resursei a ın ın s ¸ specificat˘ la linia de comand˘. } catch (MalformedURLException e) { System. if ( args . etc). length > 0) adresa = args [0]. .ro. ¸ a a numele fi¸ierului. Aceasta are mai multi constructori pentru crearea de obiecte ce reprezint˘ referinte c˘tre ¸ a ¸ a resurse aflate ˆ retea.html de la adresa: http://www.net.infoiasi.

readLine () ) != null ) { // Afisam linia citita System . println ( " URL invalid !\ n " + e ) . } finally { br . obiectul URL este uzual un proces ce ruleaz˘ a pe serverul Web referit prin URL-ul respectiv (jsp. String linie . Metoda folosit˘ pentru trimitere este a a POST. openStream () . php. InputStream in = url . Aceast˘ conexiune este reprezentat˘ de un obiect de a a a tip URLConnection. err . println ( linie ) . cgi-bin. out .3 Socket-uri Definitie ¸ Un socket (soclu) este o abstractiune software folosit˘ pentru a reprezenta ¸ a fiecare din cele dou˘ ”capete” ale unei conexiuni ˆ a ıntre dou˘ procese ce ruleaz˘ a a ˆ ıntr-o retea. br = new BufferedReader ( new Inpu tStream Reader ( in ) ) . Operatiunea de trimitere de date dintr-un a ¸ program c˘tre un URL este similar˘ cu trimiterea de date dintr-un formular a a de tip FORM aflat ˆ ıntr-o pagin˘ HTML. cˆt ¸i a unui flux de ie¸ire pentru ¸ a s s scrierea de date c˘tre acel URL. In cazul trimiterii de date. etc). ce permite crearea atˆt a unui flux de intrare pentru a citirea informatiilor de la URL-ul specificat. } } } 387 Conectarea la un URL Se realizeaz˘ prin metoda openConnection ce stabile¸te o conexiune bidirectional˘ a s ¸ a cu resursa specificat˘. close () . while (( linie = br . servlet. Fiecare socket este ata¸at unui port astfel ˆ at s˘ poat˘ iden¸ s ıncˆ a a tifica unic programul c˘ruia ˆ sunt destinate datele. } } catch ( Malfo rmedU RLEx c e p t i o n e ) { System . a ıi .13. SOCKET-URI BufferedReader br = null . try { URL url = new URL ( adresa ) . 13.3.

respectiv clienti. PROGRAMARE ˆ RETEA IN ¸ Socket-urile sunt de dou˘ tipuri: a • TCP. din acest motiv. In acest model aplicatia este format˘ ¸ ¸ a din dou˘ categorii distincte de programe numite servere. fiind ˆ stare de a¸teptare atˆta vreme cˆt nici un client nu le solicit˘ ¸ ın s a a a serviciile. O aplicatie de retea ce folose¸te socket-uri se ˆ ¸ ¸ s ıncadreaz˘ ˆ modelul cliena ın t/server de concepere a unei aplicatii. a ¸ Programele de tip server sunt cele care ofer˘ diverse servicii eventualilor a clienti. La nivelul clientului crearea socketului se re¸ alizeaz˘ specificˆnd adresa IP a serverului ¸i portul la care ruleaz˘ acesta. s ¸ a ¸ ın Leg˘tura ˆ a ıntre un client ¸i un server se realizeaz˘ prin intermediul a s a dou˘ obiecte de tip Socket. ¸ a ın ¸ 13. solicitˆnd un anumit serviciu. implementate de clasele Socket ¸i ServerSocket. obiectele sale fiind a utilizate de constructori ¸i metode definite ˆ cadrul claselor ce descriu socks ın eturi. ¸ Incepˆnd cu versiunea 1. Avantajul protocolul ¸ a TCP/IP este c˘ asigur˘ realizarea unei comunic˘ri stabile. s • UDP. Aceasta a a a este InetSocketAddress (derivat˘ din SocketAddress). pentru a specifica cei doi parametri necesari identific˘rii unui proces a care trimite sau receptioneaz˘ date ˆ retea. Uzual. permanente ˆ a a a ın retea. existˆnd siguranta c˘ informatiile trimise de un proces vor fi receptionate ¸ a ¸ a ¸ ¸ corect ¸i complet la destinatie sau va fi semnalat˘ o exceptie ˆ caz contrar. un server trebuie s˘ fie capabil s˘ a a a trateze mai multi clienti simultan ¸i. implementate de clasa DatagramSocket. cˆte unul pentru fiecare cap˘t al ”canalului” a a a de comunicatie dintre cei doi.388 CAPITOLUL 13.4 Comunicarea prin conexiuni In acest model se stabile¸te o conexiune TCP ˆ s ıntre o aplicatie client ¸i o ¸ s aplicatie server care furnizeaz˘ un anumit serviciu. num˘r port). exist˘ o clas˘ utilia a a tar˘ care implementeaz˘ o pereche de tipul (adresa IP. int port) . Programele de tip client sunt cele care initiaz˘ conversatia cu un ¸ a ¸ server.4 a platformei standard Java. fiecare cerere adresat˘ ¸ s a serverului va fi tratat˘ ˆ a ıntr-un fir de executie separat. a a s a constructorul uzual folosit fiind: Socket(InetAddress address.

respectiv scrierea datelor. prin intermediul cˆruia va fi reala a a izat˘ leg˘tura cu clientul. constructorul folosit fiind: a a ServerSocket(int port) Metoda clasei ServerSocket care a¸teapt˘ ”ascult˘” reteaua este accept. COMUNICAREA PRIN CONEXIUNI 389 La nivelul serverului. s • DataInputStream. Pentru fiecare din cele dou˘ socketuri deschise pot fi create apoi dou˘ a a fluxuri pe octeti pentru citirea. DataOutputStream . In functie a ¸ de specificul aplicatiei acestea pot fi perechile: ¸ • BufferedReader.4. s a a ¸ Aceasta blocheaz˘ procesul p˘rinte pˆn˘ la aparitia unui cereri ¸i returneaz˘ a a a a ¸ s a un nou obiect de tip Socket ce va asigura comunicarea cu clientul. ObjectOutputStream . Fluxurile obtinute vor fi folosite ˆ ¸ ımpreun˘ cu fluxuri de procea sare care s˘ asigure o comunicare facil˘ ˆ a a ıntre cele dou˘ procese.pentru comunicare prin date primitive.13. • ObjectInputStream. cu argumentul dat ˆ a ın milisecunde.pentru cominicare prin intermediul obiectelor. . BufferedWriter ¸i PrintWriter . Acest lucru se re¸ alizeaz˘ prin intermediul metodelor getInputStream. Blocarea poate s˘ nu fie permanent˘ ci doar pentru o anumit˘ perioad˘ de timp a a a a aceasta va fi specificat˘ prin metoda setSoTimeout. respectuv getOuta putStream.pentru comunis care prin intermediul ¸irurilor de caractere. Crearea unui obiect de tip ServerSocket se face a a specificˆnd portul la care ruleaz˘ serverul. acesta trebuie s˘ creeze ˆ ai un obiect de tip a ıntˆ ServerSocket. Acest tip de socket nu asigur˘ comunicarea efectiv˘ cu a a clientii ci este responsabil cu ”ascultarea” retelei ¸i crearea unor obiecte de ¸ ¸ s tip Socket pentru fiecare cerere ap˘rut˘.

public ClientThread ( Socket socket ) { this .2 Deschide un flux de intrare si primeste raspunsul. 2. In exemplul urm˘tor vom implementa o aplicatie client-server folosind a ¸ comunicarea prin conexiuni. 3. Citeste sau declara adresa IP a serverului si portul la care acesta ruleaza. . 3. Trateaza cererea venita de la client: 3. folosind metoda accept. ¸ Listing 13. import java .1 Deschide un flux de intrare si primeste cererea 3. socket = socket . Structura general˘ a unui client bazat pe conexiuni este: a 1.*. net . (va fi creat un obiect nou de tip Socket) 3.1 Deschide un flux de iesire si trimite cererea. Clientul va trimite serverului un nume iar acesta va raspunde prin mesajul ”Hello nume”.2 Deschide un flux de iesire si trimite raspunsul 3. Tratarea cererilor se va face ˆ fire ın de executie separate.*. 3. pentru ca metoda accept s˘ poat˘ fi reapelat˘ cˆt mai repede ˆ a a a a ın vederea stabilirii conexiunii cu un alt client. io .3 Inchide fluxurile si socketul nou creat } Este recomandat ca tratarea cererilor s˘ se realizeze ˆ fire de executie a ın ¸ separate.390 CAPITOLUL 13.3 Inchide fluxurile si socketul creat. PROGRAMARE ˆ RETEA IN ¸ Structura general˘ a unui server bazat pe conexiuni este: a 1.2: Structura unui server bazat pe conexiuni import java . class ClientThread extends Thread { Socket socket = null . Creeaza un obiect de tip Socket cu adresa si portul specificate. Comunica cu serverul: 3. Creeaza un obiect de tip ServerSocket la un anumit port while (true) { 2. Asteapta realizarea unei conexiuni cu un client.

getOutputStream () ) .4. // out este flux de iesire catre client PrintWriter out = new PrintWriter ( socket . raspuns . println ( raspuns ) . flush () . } catch ( IOException e ) { System . close () . try { // in este fluxul de intrare de la client BufferedReader in = new BufferedReader ( new InputStreamReader ( socket . println ( " Socketul nu poate fi inchis \ n " + e). println ( " Eroare IO \ n " + e ) . // Primim cerere de la client cerere = in . COMUNICAREA PRIN CONEXIUNI } public void run () { // Executam solicitarea clientului String cerere . out . err . readLine () . . out . // Trimitem raspuns clientului raspuns = " Hello " + cerere + " ! " . } } } } public class SimpleServer { // Definim portul pe care se gaseste serverul // ( in afara intervalului 1 -1024) public static final int PORT = 8100. public SimpleServer () throws IOException { ServerSocket serverSocket = null . getInputStream () ) ) . err . } finally { // Inchidem socketul deschis pentru clientul curent try { socket .13. 391 } catch ( IOException e ) { System .

out . PROGRAMARE ˆ RETEA IN ¸ try { serverSocket = new ServerSocket ( PORT ) .3: Structura unui client bazat pe conexiuni import java . PrintWriter out = null .392 CAPITOLUL 13. try { socket = new Socket ( adresaServer . . close () . } } Listing 13. net .. start () .*.1 " . err . raspuns . io .*. import java . Socket socket = null . while ( true ) { System . BufferedReader in = null .0. // Executam solicitarea clientului intr . String cerere . } finally { serverSocket . // Portul la care serverul ofera serviciul int PORT = 8100. println ( " Eroare IO \ n " + e ) . } } catch ( IOException e ) { System . PORT ) .un fir de executie ClientThread t = new ClientThread ( socket ) .. accept () .0. public class SimpleClient { public static void main ( String [] args ) throws IOException { // Adresa IP a serverului String adresaServer = " 127. } } public static void main ( String [] args ) throws IOException { SimpleServer server = new SimpleServer () . Socket socket = serverSocket . " ) . t . println ( " Asteptam un client .

err . extrage informatiile continute ¸i returneaz˘ r˘spunsul ¸ a ¸ ¸ s a a tot prin intermediul pachetelor. close () . if ( socket != null ) socket . } } } 13. out . COMUNICAREA PRIN DATAGRAME 393 out = new PrintWriter ( socket . System . println ( raspuns ) . out .5 Comunicarea prin datagrame In acest model nu exist˘ o conexiune permanent˘ ˆ a a ıntre client ¸i server prin s intermediul c˘reia s˘ se realizeze comunicarea. } catch ( UnknownHostExc e p t i o n e ) { System . readLine () . Un astfel de pachet se nume¸te datagram˘ s a ¸i este reprezentat printr-un obiect din clasa DatagramPacket. Primirea ¸i trimiterea datagramelor se realizeaz˘ prin ¸ s a intermediul unui socket. } finally { if ( out != null ) out . // Trimitem o cerere la server cerere = " Duke " . close () . if ( in != null ) in . in = new BufferedReader ( new Inpu tStream Reader ( socket . println ( cerere ) .5. Clientul trimite cererea c˘tre a a a server prin intermediul unuia sau mai multor pachete de date independente. exit (1) . getOutputStream () . . close () . modelat prin intermediul clasei DatagramSocket. serverul le receptioneaz˘.13. Rutarea s datagramelor de la o ma¸in˘ la alta se face exclusiv pe baza informatiilor s a ¸ continute de acestea. System . println ( " Serverul nu poate fi gasit \ n " + e ) . getInputStream () ) ) . // Asteaptam raspunsul de la server (" Hello Duke !") raspuns = in . true ) .

InetAddress address. diferenta ˆ ¸ ıntre ele fiind utilizarea claselor InetAddress. int offset. ¸ a a ¸ .394 CAPITOLUL 13. int length. int length) DatagramPacket(byte[] buf. respectiv SocketAddress pentru specificarea adresei desinatie. acesta va fi retrimis automat. int int length. int offset. De a a a s fapt. Pe de alt˘ parte. port) DatagramPacket(byte[] buf. ei nespecificˆnd vreo surs˘ sau destinatie. InetAddress address. SocketAddress address) DatagramPacket(byte[] buf. int length.ˆ cazul ˆ care unul nu a ajuns. cu deosebirea c˘ asigur˘ respectarea ordinii de ın ¸ a a transmitere a mesajelor ¸i verific˘ ajungerea la destinatie a tuturor pachetelor s a ¸ . dezavantajul acestei metode este c˘ nu a ¸ a garanteaz˘ ajungerea la destinatie a pachetelor trimise ¸i nici c˘ vor fi primite a ¸ s a ˆ aceea¸i ordinie ˆ care au fost expediate. SocketAddress address) DatagramPacket(byte[] buf. PROGRAMARE ˆ RETEA IN ¸ Dup˘ cum am mentionat deja. int length) Primele dou˘ perechi de constructori sunt pentru creare pachetelor ce a vor fi expediate. int DatagramPacket(byte[] buf. int length. protocolul TCP/IP folose¸te tot pachete pentru trimiterea informatiilor s ¸ dintr-un nod ˆ altul al retelei. exist˘ situatii ın s ın a a ¸ ˆ care aceste lucruri nu sunt importante ¸i acest model este de preferat celui ın s bazat pe conexiuni care solicit˘ mult mai mult atˆt serverul cˆt ¸i clientul. ¸ A trei pereche de constructori este folosit˘ pentru crearea unui pachet ˆ a ın care vor fi receptionate date. ın ın Clasa DatagramPacket contine urm˘torii constructori: ¸ a DatagramPacket(byte[] buf. port) int offset.

private DatagramSocket socket = null . In cazul ˆ care refolosim pachete. receive ( cerere ) . try { while ( true ) { // Declaram pachetul in care va fi receptionata cererea byte [] buf = new byte [256]. // Construim raspunsul .13. public class DatagramServer { public static final int PORT = 8200. out . net . eventual c˘tre destinatii diferite.5. s Listing 13.. getPort () . " ) . System . Acestea sunt: getAdress. println ( " Asteptam un pachet . int port = cerere . ¸ ın putem schimba continutul acestora cu metoda setData.. COMUNICAREA PRIN DATAGRAME 395 Dup˘ crearea unui pachet procesul de trimitere ¸i primire a acestuia ima s plic˘ apelul metodelor send ¸i receive ale clasei DatagramSocket.4: Structura unui server bazat pe datagrame import java . io . socket . public void start () throws IOException { socket = new DatagramSocket ( PORT ) . precum ¸i adresa la ¸ s care le trimitem prin setAddress. getAddress () . length ) . s Extragerea informatiilor contiunte de un pachet se realizeaz˘ prin metoda ¸ ¸ a getData din clasa DatagramPacket. DatagramPacket cerere . a a getPort ¸i getSocketAddress. raspuns = null .*. buf . De asemenea. // Aflam adresa si portul de la care vine cererea InetAddress adresa = cerere . s pentru a-i putea r˘spunde dac˘ este necesar. aceast˘ clas˘ ofer˘ metode a a a pentru aflarea adresei IP ¸i a portului procesului care a trimis datagrama. cerere = new DatagramPacket ( buf . import java .*. acela¸i socket poate fi folosit atˆt ¸ ın a s a pentru trimiterea de pachete. setPort ¸i setSocketAddress. cˆt ¸i pentru a ¸ a s receptionarea acestora de la diverse surse. Deoarece a s toate informatii sunt incluse ˆ datagram˘.

send ( raspuns ) . getByName ( " 127. close () .0. DatagramSocket socket = null . PROGRAMARE ˆ RETEA IN ¸ String mesaj = " Hello " + new String ( cerere .*. } } finally { if ( socket != null ) socket . int port =8200. . // Trimitem un pachet cu raspunsul catre client raspuns = new DatagramPacket ( buf . } } public static void main ( String [] args ) throws IOException { new DatagramServer () . } } Listing 13. net . public class DatagramClient { public static void main ( String [] args ) throws IOException { // Adresa IP si portul la care ruleaza serverul InetAddress adresa = InetAddress .*. buf .5: Structura unui client bazat pe datagrame import java . start () . port ) .1 " ) . byte buf [].396 CAPITOLUL 13. try { // Construim un socket pentru comunicare socket = new DatagramSocket () . getBytes () . import java . getData () ). io . length . // Construim si trimitem pachetul cu cererea catre server buf = " Duke " .0. DatagramPacket packet = null . buf = mesaj . adresa . socket . getBytes () .

˘ 13. adresa . length ) . extensie a clasei DatagramSocket. socket .1 .6.255.0 este rezervat˘ ¸i nu trebuie folosit˘. TRIMITEREA DE MESAJE CATRE MAI MULTI CLIENTI ¸ ¸ packet = new DatagramPacket ( buf . println ( new String ( packet . descris de clasa Multicasta Socket.239.6 Trimiterea de mesaje c˘tre mai multi a ¸ clienti ¸ Diverse situatii impun gruparea mai multor clienti astfel ˆ at un mesaj (pa¸ ¸ ıncˆ chet) trimis pe adresa grupului s˘ fie receptionat de fiecare dintre ace¸tia.0.0. // Afisam raspunsul (" Hello Duke !") System . // Asteaptam pachetul cu raspunsul de la server buf = new byte [256].255 ¸i un port UDP. packet = new DatagramPacket ( buf . port ) . send ( packet ) . socket . } finally { if ( socket != null ) socket . out . a ¸ s Gruparea mai multor programe ˆ vederea trimiterii multiple de mesaje se ın realizeaz˘ prin intermediul unui socket special. getData () ) ) . buf . Un grup de clienti abonati pentru trimitere multipl˘ este specificat printr¸ ¸ a o adres˘ IP din intervalul 224. a s Adresa 224. receive ( packet ) . length . close () .255. as a .0.0. } } } 397 13. buf .

0. socket . getByName ( " 230. buf . System . io . println ( " Asteptam un pachet . try { // Ne alaturam grupului aflat la adresa si portul specificate socket = new MulticastSocket ( port ) .*. import java .*.398 CAPITOLUL 13.6: Inregistrarea unui client ˆ ıntr-un grup import java . // Asteaptam un pachet venit pe adresa grupului buf = new byte [256]. length ) . public class MulticastClient { public static void main ( String [] args ) throws IOException { // Adresa IP si portul care reprezinta grupul de clienti InetAddress group = InetAddress . byte buf []. joinGroup ( group ) ..1 " ) . MulticastSocket socket = null . " ) . . receive ( packet ) . int port =4444. net . DatagramPacket packet = new DatagramPacket ( buf . out . socket ..0. PROGRAMARE ˆ RETEA IN ¸ Listing 13.

} } } . // Cream un socket cu un numar oarecare DatagramSocket socket = new DatagramSocket (0) .*. socket . socket . out . leaveGroup ( group ) . getByName ( " 230. TRIMITEREA DE MESAJE CATRE MAI MULTI CLIENTI ¸ ¸ 399 System . close () . } finally { socket . getBytes () . int port = 4444. byte [] buf .0.˘ 13.*. close () . grup . try { // Trimitem un pachet catre toti clientii din grup buf = ( new String ( " Salut grup ! " ) ) . println ( new String ( packet .1 " ) .0. send ( packet ) . } finally { if ( socket != null ) { socket . } } } } Listing 13.6. buf . packet = new DatagramPacket ( buf . io . trim () ) .7: Transmiterea unui mesaj c˘tre un grup a import java . DatagramPacket packet = null . import java . port ). getData () ) . public class MulticastSend { public static void main ( String [] args ) throws IOException { InetAddress grup = InetAddress . length . net .

PROGRAMARE ˆ RETEA IN ¸ .400 CAPITOLUL 13.

¸ a fiind dictat de evenimentele generate de c˘tre browser la vizualizarea docua mentului HTML ce contine appletul.applet. care extinde Applet. s Ca orice alt˘ aplicatie Java. Una dintre acestea este principal˘ ¸i extinde clasa Applet. ci va fi executat de browserul ˆ care este ˆ arcat˘ pagina Web ce contine appletul respectiv.swing exist˘ a a a ¸i clasa JApplet. O aplicatie ın ınc˘ a ¸ ¸ independent˘ este executat˘ prin apelul interpretorului java.1 Introducere Definitie ¸ Un applet reprezint˘ un program Java de dimensiuni reduse ce gestioneaz˘ a a o suprafat˘ de afi¸are (container) care poate fi inclus˘ ˆ ¸a s a ıntr-o pagin˘ Web. codul unui applet poate fi format din una sau a ¸ mai multe clase. Un a astfel de program se mai nume¸te miniaplicatie. as aceasta fiind clasa ce trebuie specificat˘ ˆ documentul HTML ce descrie a ın pagina Web ˆ care dorim s˘ includem appletul. oferind suport pentru crearea de s appleturi pe arhitectura de componente JFC/Swing. a cea mai important˘ clas˘ fiind Applet.Capitolul 14 Appleturi 14. clasa principal˘ fiind cea care ¸ a contine metoda main. Ciclul de viat˘ al unui applet este complet diferit. avˆnd ca ara a a gument numele clasei principale a aplicatiei. In pachetul javax. 401 . ın a Diferenta fundamental˘ dintre un applet ¸i o aplicatie const˘ ˆ faptul c˘ ¸ a s ¸ a ın a un applet nu poate fi executat independent. ¸ Pachetul care ofer˘ suport pentru crearea de appleturi este java.

awt. s a s s 1. S˘ parguream ˆ continuare ace¸ti pa¸i pentru a realiza un applet a ın s s extrem de simplu. Difer˘ ˆ schimb structura programului ¸i modul de rulare ¸ a ın s a acestuia.gif").* . public void init() { img = getImage(getCodeBase(). "taz.402 CAPITOLUL 14. APPLETURI Ierarhia claselor din care deriv˘ appleturile este prezentata ˆ figura de a ın mai jos: Fiind derivat˘ din clasa Container. asemenea claselor Frame sau Panel.applet. care afi¸eaz˘ o imagine ¸i un ¸ir de caractere. } .* . Scrierea codului sursa import java. clasa Applet descrie de fapt suprafete a ¸ de afi¸are.2 Crearea unui applet simplu Crearea structurii de fi¸iere ¸i compilarea applet-urilor sunt identice ca ˆ s s ın cazul aplicatiilor. public class FirstApplet extends Applet { Image img. import java. s 14.

a a 2.0. } } 403 Pentru a putea fi executat˘ de browser. s 3. g.java. A¸adar. etc. Mozilla. clasa principal˘ a appletului trea a buie s˘ fie public˘. Netscape.2. Rularea appletului Applet-urile nu ruleaza independent. S˘ cons ın a sider˘m fi¸ierul simplu. 25).class.html. Pentru a executa un applet trebuie s˘ facem dou˘ operatii: a a ¸ • Crearea unui fi¸ier HTML ˆ care vom include applet-ul. Salvarea fisierelor surs˘ a Ca orice clas˘ public˘. folosind compis ¸ latorul javac apelat pentru fi¸ierul ce contine appletul. avˆnd continutul de mai jos: a s a ¸ .drawOval(100. CREAREA UNUI APPLET SIMPLU public void paint (Graphics g) { g.150. vom salva clasa de mai sus s s s s ˆ ıntr-un fi¸ier FirstApplet. 110.java.drawString("Hello! My name is Taz!". Ele pot fi rulate doar prin intermediul unui browser: Internet Explorer. 0.java In cazul ˆ care compilarea a reu¸it va fi generat fisierul FirstApplet. this). ın s 4. Compilarea Compilarea se face la fel ca ¸i la aplicatiile independente. Opera. s ¸ javac FirstApplet.drawImage(img.50). 0. sau printr-un program special cum ar fi appletviewer din kitul de dezvoltare J2SDK. g. clasa principala a appletului va fi salvat˘ ˆ a a a ıntr-un fi¸ier cu acela¸i nume ¸i extensia .14.

ın s Fiecare etap˘ este strˆns legat˘ de un eveniment generat de c˘tre browser ¸i a a a a s determin˘ apelarea unei metode specifice din clasa ce implementeaz˘ applea a tul. • Initializarea ¸ Este apelat˘ metoda init ce permite initializarea diverselor variabile. a ¸ citirea unor parametri de intrare. In unele situatii ˆ ¸ ¸ ıntreaga executie a appletului se consum˘ la ¸ a etapele de initializare ¸i pornire. • Pornirea Este apelat˘ metoda start a • Executia propriu-zis˘ ¸ a Const˘ ˆ interactiunea dintre utilizator ¸i componentele afi¸ate pe a ın ¸ s s suprafata appletului sau ˆ executarea unui anumit cod ˆ ¸ ın ıntr-un fir de executie.html folosind unul din browser-ele amintite sau efectuˆnd apelul: a appletviewer simplu.html. 14. etc. ¸ s .3 Ciclul de viat˘ al unui applet ¸a Executia unui applet ˆ ¸ ıncepe ˆ momentul ˆ care un browser afi¸eaz˘ o pagin˘ ın ın s a a Web ˆ care este inclus appletul respectiv ¸i poate trece prin mai multe etape.class width=400 height=400> </applet> </body> </html> • Vizualizarea appletului: se deschide fisierul simplu.404 CAPITOLUL 14. • Inc˘rcarea ˆ memorie a ın Este creat˘ o instanta a clasei principale a appletului ¸i ˆ a ¸ s ıncarcat˘ ˆ a ın memorie. APPLETURI <html> <head> <title>Primul applet Java</title> </head> <body> <applet code=FirstApplet.

pentru a-i permite s˘ elibereze resursele detinute. ¸ appletul va fi eliminat din memorie ¸i va fi apelat˘ metoda destroy a s a acestuia. va fi reapelat˘ metoda a a start. Acela¸i lucru se ˆ ampl˘ s ıntˆ a dac˘ fereastra browserului este minimizat˘.14. CICLUL DE VIATA AL UNUI APPLET ¸˘ 405 • Oprirea temporar˘ a In cazul ˆ care utilizatorul p˘r˘se¸te pagina Web ˆ care ruleaz˘ appleın aa s ın a tul este apelat˘ metoda stop a acestuia. aceast˘ metod˘ ¸ a a ar trebui s˘ se apeleze o singur˘ dat˘. exist˘ o serie de metode specifice appleturilor ce sunt apelate aus a tomat la diverse evenimente generate de c˘tre browser. s ın a ıns˘ este posibil ca ea s˘ se apeleze de mai multe ori. Teoretic. Acestea sunt definite a ˆ clasa Applet ¸i sunt enumerate ˆ tabelul de mai jos: ın s ın Metoda Situatia ˆ care este apelat˘ ¸ ın a init La initializarea appletului. Metodele specifice appleturilor A¸adar. In momentul cˆnd pagina a a a Web ce contine appletul devine din nou activ˘. dup˘ o oprire temporar˘. a a a stop De fiecare dat˘ cˆnd appletul nu mai este vizibil a a (pagina Web nu mai este vizibil˘. etc) ¸i ˆ a s ınainte de destroy. la unele browsere. destroy La ˆ ınchiderea ultimei instante a browserului ¸ care a ˆ arcat ˆ memorie clasa principal˘ a appletului. pentru ¸ ın a nu consuma inutil din timpul procesorului. a start Imediat dup˘ initializare ¸i de fiecare dat˘ a ¸ s a cˆnd appletul redevine activ.3. ınc˘ ın a Atentie ¸ . dˆndu-i astfel posibilitatea s˘ a a a opreasca temporar executia sa pe perioada ˆ care nu este vizibil. Apelul a ¸ metodei destroy este ˆ ıntotdeauna precedat de apelul lui stop. la prima a a a afi¸are a appletului ˆ pagin˘. fereastra browserului a este minimizat˘. • Oprirea definitiv˘ a La ˆ ınchiderea tuturor instantelor browserului folosit pentru vizualizare. ˆ a.

*.applet. a a ceea ce ˆ ınseamn˘ c˘ appleturile sunt. gestionarea pozition˘rii lor ¸i tratarea evenimentelor ¸ a s generate se realizeaz˘ la fel ca ¸i ˆ cazul aplicatiilor. suprafete de afi¸are. ˆ a a ınainte de toate.awt.awt. import java.event.406 CAPITOLUL 14. ¸ s Plasarea componentelor. . ad˘ugarea coma s ın ¸ a ponentelor pe suprafata appletului precum ¸i stabilirea obiectelor respons¸ s abile cu tratarea evenimentelor generate sunt operatiuni ce vor fi realizate ˆ ¸ ın metoda init.Applet. APPLETURI Aceste metode sunt apelate automat de browser ¸i nu trebuie apelate s explicit din program ! Structura general˘ a unui applet a import java.*. public class StructuraApplet extends Applet { public void init() { } public void start() { } public void stop() { } public void destroy() { } } 14.4 Interfata grafic˘ cu utilizatorul ¸ a Dup˘ cum am v˘zut. Uzual. clasa Applet este o extensie a superclasei Container. import java.

4. INTERFATA GRAFICA CU UTILIZATORUL ¸ 407 Gestionarul de pozitionare implicit este FlowLayout. ˆ a acesta poate fi ¸ ıns˘ schimbat prin metoda setLayout. .˘ 14.

tipul s ın ¸ a parametrilor este ˆ ıntotdeauna ¸ir de caractere.. Definirea parametrilor se face ˆ cadrul tagului APPLET din documenın tul HTML ce contine appletul ¸i sunt identificati prin atributul PARAM..class" WIDTH=100 HEIGHT=50 <PARAM NAME=textAfisat VALUE="Salut"> <PARAM NAME=numeFont VALUE="Times New Roman"> <PARAM NAME=dimFont VALUE=20> </APPLET> Ca ¸i ˆ cazul argumentelor trimise aplicatiilor de la linia de comand˘. a a public void paint(Graphics g) { // Desenare . indiferent dac˘ valoarea s a este ˆ ıntre ghilimele sau nu. a a metoda paint din clasa Applet nu realizeaz˘ nimic. deci. specis ficat˘ prin VALUE.408 CAPITOLUL 14. ˆ cazul ˆ care a ın ın dorim s˘ desen˘m direct pe suprafata unui applet va fi nevoie s˘ supradefinim a a ¸ a aceast˘ metod˘. Implicit. Fiecare applet are ¸i un set de parametri prestabiliti ale c˘ror nume nu s ¸ a vor putea fi folosite pentru definirea de noi parametri folosind metoda de . Ei permit utilizatorului s˘ personalizeze ¸ a aspectul sau comportarea unui applet f˘r˘ a-i schimba codul ¸i recompila aa s clasele. } In cazul ˆ care este aleas˘ aceast˘ solutie. APPLETURI Desenarea pe suprafata unui applet ¸ Exist˘ o categorie ˆ a ıntreag˘ de appleturi ce nu comunic˘ cu utilizatorul a a prin intermediul componentelor ci. a 14. ca ˆ exemplul de mai jos: a ın <APPLET CODE="TestParametri. Reamintim c˘ metoda paint este reın a sponsabil˘ cu definirea aspectului grafic al oric˘rei componente. executia lor se rezum˘ la diverse operatiuni ¸ a ¸ de desenare realizate ˆ metoda paint.5 Definirea ¸i folosirea parametrilor s Parametrii sunt pentru appleturi ceea ce argumentele de la linia de comand˘ a sunt pentru aplicatiile independente. specificat prin NAME ¸i o valoare. evenimentele tratate uzual vor fi ın a a ¸ cele generate de mouse sau tastatur˘. ¸ s ¸ Fiecare parametru are un nume.

caz ˆ care programul trebuie ın s˘ atribuie o valoare implicit˘ variabilei ˆ care se dorea citirea respectivului a a ın parametru. cele trei ¸iruri reprezentˆnd numele parametrului. folosind a a s un font cu numele ¸i dimensiunea specificate de asemenea ca parametri. DEFINIREA SI FOLOSIREA PARAMETRILOR ¸ 409 mai sus. import java . Ace¸tia apar direct ˆ corpul tagului APPLET ¸i definesc informatii s ın s ¸ generale despre applet. De exemplu.5. // valoare implicita numeFont = getParameter ( " numeFont " ) . Orice applet poate pune la dispozitie o ”documentatie” referitoare la para¸ ¸ metrii pe care ˆ suport˘. ın s ¸ etc. tipul s˘u ¸i s a a s o descriere a sa. public void init () { text = getParameter ( " textAfisat " ) . numeFont . if ( numeFont == null ) numeFont = " Arial " . Applet . Fiecare element al vectorului este de fapt un vector cu trei elemente s de tip String. if ( text == null ) text = " Hello " . { . a Folosirea parametrilor primiti de c˘tre un applet se face prin intermediul ¸ a metodei getParameter care prime¸te ca argument numele unui parametru s ¸i returneaz˘ valoarea acestuia. In cazul ˆ care nu exist˘ nici un parametru s a ın a cu numele specificat. int dimFont . care returneaz˘ un vector format din triplete a de ¸iruri. awt . public class TestParametri extends Applet String text .*. WIDTH sau HEIGHT. Aceasta se realizeaz˘ prin supradefinirea a a metodei getParameterInfo. ˆ apın pletviewer informatiile despre parametri pot fi vizualizate la rubrica Info din ¸ meniul Applet. s Listing 14. ˆ Netscape se folose¸te optiunea Page info din meniul View. S˘ scriem un applet care s˘ afi¸eze un text primit ca parametru. Exemple de astfel de parametri sunt CODE.1: Folosirea parametrilor import java . Lista lor complet˘ va fi prezentata la descrierea tagului APPLET. metoda ˆ ıntoarce null. pentru a veni ˆ ajutorul utilizatorilor care doresc s˘ ıi a ın a includ˘ appletul ˆ a ıntr-o pagin˘ Web. Informatiile furnizate de un applet pot fi citite din browserul ¸ folosit pentru vizualizare prin metode specifice acestuia.14. applet .

" Numele fontului " } . BOLD .6 Tag-ul APPLET Sintaxa complet˘ a tagului APPLET.410 CAPITOLUL 14. " int " . drawString ( text . { " dimFont " . 20) . } public String [][] getParameterInfo () { String [][] info = { // Nume Tip Descriere { " textAfisat " . APPLETURI try { dimFont = Integer . cu ajutorul c˘ruia pot fi incluse applea a turi ˆ cadrul paginilor Web este: ın <APPLET CODE = clasaApplet WIDTH = latimeInPixeli HEIGHT = inaltimeInPixeli [ARCHIVE = arhiva. " String " . } } public void paint ( Graphics g ) { g . } catch ( Numb erFo r m at Ex ce pt i o n e ) { dimFont = 16. setFont ( new Font ( numeFont . } } 14. " String " . g . Font . return info . parseInt ( getParameter ( " dimFont " ) ) . " Sirul ce va fi afisat " } . { " numeFont " . " Dimensiunea fontului " } }. 20 . dimFont ) ) .jar] [CODEBASE = URLApplet] [ALT = textAlternativ] [NAME = numeInstantaApplet] [ALIGN = aliniere] [VSPACE = spatiuVertical] .

se ın s consider˘ implicit URL-ul documentului. • ARCHIVE = arhiva.. a a • WIDTH =latimeInPixeli. • ALIGN =aliniere Semnific˘ modalitatea de aliniere a appletului ˆ pagina Web. astfel ˆ at mai multe appleturi aflate pe aceea¸i pagin˘ s˘ poat˘ ıncˆ s a a a comunica ˆ ıntre ele folosindu-se de numele lor.14. HEIGHT =inaltimeInPixeli Specific˘ l˘¸imea ¸i ˆ altimea suprafetei ˆ care va fi afi¸at appletul. a ¸ 411 • CODE = clasaApplet Numele fi¸ierului ce contine clasa principal˘ a appletului. Extensia ”. right. TAG-UL APPLET [HSPACE = spatiuOrizontal] > [< PARAM NAME = parametru1 VALUE = valoare1 >] [< PARAM NAME = parametru2 VALUE = valoare2 >] . top.class” poate sau nu s˘ apar˘. Acesta va s ¸ a fi c˘utat ˆ directorul specificat de CODEBASE. • NAME =numeInstantaApplet Ofer˘ posibilitatea de a da un nume respectivei instante a appletua ¸ lui. a • ALT = textAlternativ Specific˘ textul ce trebuie afi¸at dac˘ browserul ˆ ¸elege tagul APPLET a s a ınt dar nu poate rula appleturi Java. a ın a • CODEBASE = directorApplet Specific˘ URL-ul la care se g˘se¸te clasa appletului. In cazul ˆ care lipse¸te. Uzual se exprim˘ a a s a relativ la directorul documentului HTML. a at s ın˘ ¸ ¸ ın s Sunt obligatorii.6. a .. Nu poate fi absolut ¸i a ın s trebuie obligatoriu specificat. Acest a ın atribut poate primi una din urm˘toarele valori: left. [text HTML alternativ] </APPLET> Atributele puse ˆ ıntre paranteze p˘trate sunt optionale.jar Specific˘ arhiva ˆ care se g˘sesc clasele appletului.

middle. Browserele Java-enabled vor ignora acest text. a a ıntˆ a a s Dorim s˘ cre˘m un applet care s˘ afi¸eze la coordonate aleatoare mesajul a a a s ”Hello”. creat de asemenea automat a s ¸ de c˘tre browser. nici unul nu trebuie s˘ ˆ solicite ˆ mod excesiv. baseline. bottom. • text HTML alternativ Este textul ce va fi afi¸at ˆ cazul ˆ care browserul nu ˆ s ın ın ıntelege tagul APPLET.412 CAPITOLUL 14.7 Folosirea firelor de executie ˆ appleturi ¸ ın La ˆ arcarea unei pagini Web. deoarece va ¸ a ıl ın provoca functionarea anormal˘ sau chiar blocarea celorlalte. cu pauz˘ de o secund˘ ˆ a a ıntre dou˘ afi¸˘ri. Din punctul de vedere al interfetei grafice ˆ a. fiecare applet aflat pe o ¸ ıns˘ pagin˘ Web are acces la un acela¸i fir de executie. gre¸it˘ de a sa a s a altfel. HSPACE = spatiuOrizontal Specific˘ numarul de pixeli dintre applet ¸i marginile suprafetei de a s afi¸are. s s • VSPACE =spatiuVertical. 14. seminificatiile ¸ lor fiind acelea¸i ca ¸i la tagul IMG. ¸ a In cazul ˆ care dorim s˘ efectu˘m operatiuni consumatoare de timp este ın a a ¸ recomandat s˘ le realiz˘m ˆ a a ıntr-un alt fir de executie. ¸i care este responsabil cu desenarea appletului (apelul a s metodelor update ¸i paint) precum ¸i cu transmiterea mesajelor generate s s de c˘tre componente. Intrucˆt toate appleturile de pe pagin˘ ”ˆ a a a ımpart” acest fir de executie. absbottom . pentru a nu bloca ¸ interactiunea utilizatorului cu appletul. ar fi: . a S˘ considerm˘m mai ˆ ai dou˘ abord˘ri gre¸ite de lucru cu appleturi. Acestea vor rula ¸ concurent dup˘ regulile de planificare implementate de ma¸ina virtual˘ Java a s a a platformei folosite. absmiddle. redesenarea acestuia sau activitatea ¸ celorlalte appleturi de pe pagin˘. s • PARAM Tag-urile PARAM sunt folosite pentru specificarea parametrilor unui applet (vezi ”Folosirea parametrilor”). fiec˘rui applet ˆ este creat automat un fir ınc˘ a ıi de executie responsabil cu apelarea metodelor acestuia. APPLETURI texttop. Prima variant˘.

random () * getHeight () ) . random () * getWidth () ) . awt . public class AppletRau1 extends Applet { public void paint ( Graphics g ) { while ( true ) { int x = ( int ) ( Math . y . nu este cazul ˆ appletul de mai sus. import java . x . este a s a urm˘toarea : a Listing 14. random () * getWidth () ) .*. sleep (1000) . sleep (1000) . codul metodei paint trebuie s˘ fie cˆt mai a a a a simplu de executat ceea ce. drawString ( " Hello " .*. ın O alt˘ idee de rezolvare care ne-ar putea veni. de asemenea gre¸it˘. Ca regul˘ general˘. } catch ( InterruptedE x ce pt io n e ) {} } } public void paint ( Graphics g ) { . ˆ a a a ın ıncercˆnd s˘ o a a termine.2: Incorect: blocarea metodei paint import java . } catch ( InterruptedE xc ep ti on e ) {} } } } 413 Motivul pentru care acest applet nu functioneaz˘ corect ¸i probabil va ¸ a s duce la anomalii ˆ functionarea browserului este c˘ firul de executie care ın ¸ a ¸ se ocup˘ cu desenarea va r˘mˆne blocat ˆ metoda paint. import java . applet . public void init () { while ( true ) { x = ( int ) ( Math . public class AppletRau2 extends Applet { int x . random () * getHeight () ) .14. repaint () .7.*.*. applet . g . try { Thread . awt . y = ( int ) ( Math . try { Thread .3: Incorect: appletul nu termin˘ initializarea a ¸ import java . evident. FOLOSIREA FIRELOR DE EXECUTIE ˆ APPLETURI ¸ IN Listing 14. y ) . int y = ( int ) ( Math .

*. In prima situatie appletul porne¸te ¸ a ¸ s firul la initialzarea sa iar acesta va rula. } } public void run () { while ( true ) { x = ( int ) ( Math . indiferent dac˘ appletul mai este sau ¸ a nu vizibil. Structura unui applet care doreste s˘ lanseze un ¸ a fir de executie poate avea dou˘ forme.414 g . trebuie s˘ folosim ¸ a a un fir de executie propriu. awt . x . drawString ( " Hello " . repaint () . start () . applet . APPLETURI Pentru a putea da o solutie corect˘ problemei propuse. try { Thread . random () * getWidth () ) . Listing 14. public void init () { if ( fir == null ) { fir = new Thread ( this ) . fir . sleep (1000) . import java . y ) . random () * getHeight () ) . } } In cazul ˆ care firul de executie pornit de applet efectueaz˘ operatii ce ın ¸ a .*. y . drawString ( " Hello " . } catch ( Inter ru pt ed Ex ce pt io n e ) {} } } public void paint ( Graphics g ) { g . pˆn˘ la oprirea sa natural˘ (terminarea metodei run) sau pˆn˘ la a a a a a ˆ ınchiderea sesiunii de lucru a browserului. y = ( int ) ( Math . y ) . } } CAPITOLUL 14. x . Thread fir = null .4: Corect: folosirea unui fir de executie propriu ¸ import java . public class AppletCorect1 extends Applet implements Runnable { int x .

cum ar fi animatie. awt . Un applet este considerat activ imediat dup˘ apelul a metodei start ¸i devine inactiv la apelul metodei stop.14. } catch ( InterruptedE x c e p t i o n e ) {} . n ++.*. random () * getHeight () ) . fir = null . Thread fir = null . ad˘ugˆnd ¸i un contor care s˘ numere a a a a s a afi¸˘rile de mesaje . repaint () . s S˘ modific˘m programul anterior. Pentru a afla dac˘ s a un applet este activ se folose¸te metoda isActive. ar fi de dorit a ca acesta s˘ se opreasca atunci cˆnd appletul nu mai este vizibil (la apelul a a metodei stop) ¸i s˘ reporneasca atunci cˆnd appletul redevine vizibil (la s a a apelul metodei start). boolean activ = false . activ = true . random () * getWidth () ) .acesta nu va fi incrementat pe perioada ˆ care appletul sa ın nu este activ.*. start () . try { Thread . FOLOSIREA FIRELOR DE EXECUTIE ˆ APPLETURI ¸ IN 415 au sens doar dac˘ appletul este vizibil. import java . fir . public class AppletCorect2 extends Applet implements Runnable { int x . y = ( int ) ( Math . int n = 0. applet . Listing 14.7.5: Folosirea metodelor start ¸i stop s import java . } } public void stop () { activ = false . sleep (1000) . y . public void start () { if ( fir == null ) { fir = new Thread ( this ) . } public void run () { while ( activ ) { x = ( int ) ( Math .

¸ versiunea. APPLETURI public void paint ( Graphics g ) { g .0". Metoda returneaz˘ un sir de caractere continˆnd informatiile a a ¸ respective. destroy. clasa Applet a a a ofer˘ metode specifice applet-urilor cum ar fi: a Punerea la dispozitie a unor informatii despre applet ¸ Similar˘ cu metoda getParameterInfo ce oferea o ”documentatie” despre a ¸ parametrii pe care ˆ accept˘ un applet. public String getAppletInfo() { return "Applet simplist.8 Alte metode oferite de clasa Applet Pe lˆng˘ metodele de baz˘: init.416 } } CAPITOLUL 14. corectitudinea unui a ın ¸ applet nu trebuie s˘ se bazeze pa acest mecanism. ver 1. exist˘ metoda getAppletInfo ce perıi a a mite specificarea unor informatii legate de applet cum ar fi numele. drawString ( " Hello " + n . etc. start. Din acest motiv. stop. y ) . } } Atentie ¸ Este posibil ca unele browsere s˘ nu apele metoda stop ˆ situatiile a ın ¸ prev˘zute ˆ specficiatiile appleturilor. autorul. } Aflarea adreselor URL referitoare la applet Se realizeaz˘ cu metodele: a . autor necunoscut. x . a 14.

8. cum ar fi o suprafat˘ de desenare de tip Canvas. applet . import java . ALTE METODE OFERITE DE CLASA APPLET 417 • getCodeBase . In ambele cazuri.. } . ın Aceste metode sunt foarte utile deoarece permit specificarea relativ˘ a unor a fi¸iere folosite de un applet. awt . cum ar fi cea a directorului a a a ˆ care se g˘se¸te documentul HTML ce contine appletul (getDocumentBase) ın a s ¸ sau a directorului ˆ care se g˘se¸te clasa appletului (getCodeBase).returneaz˘ URL-ul directorului ce contine doca ¸ umentul HTML ˆ care este inclus appletul respectiv.. fie calea relativ˘ la o anumit˘ adres˘ URL. obtinerea unei referinte la imaginea respectiv˘ ¸ ¸ a se va face cu ajutorul metodei getImage din clasa Applet. { public void init () { img = getImage ( getCodeBase () . • getDocumentBase .ce returneaz˘ URL-ul directorului ce contine clasa a ¸ appletului. Aceasta poate primi ca argument fie adresa URL absolut˘ a fi¸ierului ce reprezint˘ imaga s a inea. Applet . " taz . ¸a fie direct ˆ metoda paint a applet-ului.14. gif " ) . ın a s Listing 14. public class Imagini extends Applet Image img = null . cum ar fi imagini sau sunete. folosind metoda drawImage a clasei ın Graphics. } Afi¸area imaginilor s Afi¸area imaginilor ˆ s ıntr-un applet se face fie prin intermediul unei componente ce permite acest lucru.").6: Afi¸area imaginilor s import java .*. s Afi¸area unor mesaje ˆ bara de stare a browserului s ın Acest lucru se realizeaz˘ cu metoda showStatus a public void init() { showStatus("Initializare applet.

try { URL doc = new URL("http://www. 0 . 0 . Afi¸area unor documente ˆ browser s ın Se face cu metoda showDocument ce prime¸te adresa URL a fi¸ierului ce s s contine documentul pe care dorim sa-l deschidem (text. drawImage ( img . la apelul metodei getAppletContext a clasei Applet.println("URL invalid! \n" + e). ¸ a ın a eventual ˆ ımpreun˘ cu alte appleturi. getAppletContext(). ¸i este descris de interfata AppletCona s ¸ text. Crearea unui obiect ce implementeaz˘ aceast˘ interfat˘ se realizeaz˘ de a a ¸a a c˘tre browser.ro").418 CAPITOLUL 14. } Comunicarea cu alte applet-uri Aceast˘ comunicare implic˘ de fapt identificarea unui applet aflat pe aceea¸i a a s pagina ¸i apelarea unei metode sau setarea unei variabile publice a acestuia. s Identificarea se face prin intermediu numelui pe care orice instanta a unui ¸ applet ˆ poate specifica prin atributul NAME. } catch(MalformedURLException e) { System. putˆnd ¸ ın a comunica cu alte applet-uri aflate pe aceeasi pagin˘ sau cere browser-ului s˘ a a deschid˘ diverse documente. Prin a intermediul acestei interfete un applet poate ”vedea” ˆ jurul sau. ¸ Aceast˘ metod˘ este accesat˘ prin intermediul contextului de executie al a a a ¸ appletului. a AppletContext contex = getAppletContext(). } } Aflarea contextului de executie ¸ Contextul de executie al unui applet se refer˘ la pagina ˆ care acesta ruleaz˘. APPLETURI public void paint ( Graphics g ) { g . etc). ıl .err.showDocument(doc). html.infoiasi. imagine. this ) .

public void init () { // Fisierul cu sunetul trebuie sa fie in acelasi // director cu appletul clip = getAudioClip ( getCodeBase () . stop .*. au " ) . loop . addActionListener ( this ) .7: Redarea sunetelor import java . add ( play ) .*.14. Button loop = new Button ( " Loop " ) .*. ALTE METODE OFERITE DE CLASA APPLET 419 Obtinerea unei referinte la un applet al c˘rui nume ˆ cunoa¸tem sau ¸ ¸ a ıl s obtinerea unei enumer˘ri a tuturor applet-urilor din pagin˘ se fac prin in¸ a a termediul contextului de executie.8. acesta poate fi specificat absolut sau a relativ la URL-ul appletului • Crearea unui obiect de tip AudioClip cu metoda getAudioClip apoi apelarea metodelor start. play .applet. Acestea as a ın sunt descrise prin intermediul unor obiecte ce implementeaz˘ interfata Aua ¸ dioClip din pachetul java. Button stop = new Button ( " Stop " ) .au” la un anumit URL exist˘ dou˘ posibilit˘¸i: s a a at • Folosirea metodei play din clasa Applet care prime¸te ca argument s URL-ul la care se afl˘ sunetul. public class Sunete extends Applet implements ActionListener { Button play = new Button ( " Play " ) . loop ¸i stop pentru acesta. Pentru a reda un sunet aflat ˆ ıntr-un fi¸ier ”. add ( stop ) . add ( loop ) . applet . import java .au. AudioClip clip = null . folosind metodele getApplet. import java . s Listing 14. awt . event . . addActionListener ( this ) . " sunet . awt . respectiv ¸ getApplets. Redarea sunetelor Clasa Applet ofer˘ ¸i posibilitatea red˘rii de sunete ˆ format . addActionListener ( this ) .

Mai mult. a 14.class imagine. if ( src == play ) clip .jpg sunet.au . Din aceste motive. getSource () . cea mai eficient˘ modalitate de a distribui ınc˘ a un applet este s˘ arhiv˘m toate fi¸ierele necesare acestuia. a a s Arhivarea fi¸ierelor unui applet se face cu utilitarul jar. cu atˆ ˆ arcarea acestuia se va face mai repede.jar ClasaPrincipala.9 Arhivarea appleturilor Dup˘ cum am v˘zut. sunete. oprind temporar activitatea appletului pˆn˘ la ın a a ˆ arcarea lor. else if ( src == stop ) clip . Deoarece transferul datelor prin retea a s ¸ este un proces lent. } } In cazul ˆ care appletul folose¸te mai multe tipuri de sunete. play () . este recoın s mandat ca ˆ arcarea acestora s˘ fie f˘cut˘ ˆ ınc˘ a a a ıntr-un fir de executie separat. oferit ˆ s ın distributia J2SDK. ¸ // Exemplu jar cvf arhiva. loop () . pentru ca un applet aflat pe o pagin˘ Web s˘ poat˘ a a a a a fi executat codul s˘u va fi transferat de pe serverul care g˘zduie¸te pagina a a s Web solicitat˘ pe ma¸ina clientului. cu cˆt dimensiunea fi¸ierlor care formeaz˘ appletul este a s a mai redus˘. etc).420 } CAPITOLUL 14.jpg *.class AltaClasa.jar *.class *. acestea vor fi transferate prin retea abia ˆ momentul ¸ ın ˆ care va fi nevoie de ele. else if ( src == loop ) clip . stop () . APPLETURI public void actionPerformed ( ActionEvent e ) { Object src = e .au // sau jar cvf arhiva. ¸ pentru a nu bloca temporar activitatea fireasc˘ a programului. dac˘ a a ınc˘ a appletul contine ¸i alte clase ˆ afar˘ de cea principal˘ sau diverse resurse ¸ s ın a a (imagini.

• Deschid˘ conexiuni cu alte ma¸ini ˆ afar˘ de cea de pe care provine a s ın a (host).14. este foarte important s˘ existe anu¸ a mite restrictii de securitate care s˘ controleze activitatea acestuia. etc.11 Appleturi care sunt ¸i aplicatii s ¸ Deoarece clasa Applet este derivat˘ din Container. a s ea descrie o suprafat˘ de afi¸are care poate fi inclus˘ ca orice alt˘ component˘ ¸a s a a a ˆ ıntr-un alt container. aruncˆnd exceptii de tip Security Exception ˆ cazul ˆ care una din acesa ¸ ın ın tea ˆ ıncearc˘ s˘ efectueze o operatie nepermis˘. 14. • Porneasc˘ programe pe ma¸ina client. altele decˆt cea a browserului. indicˆnd faptul c˘ au fost create de un ¸ s a a a applet. RESTRICTII DE SECURITATE ¸ 421 Includerea unui applet arhivat ˆ ıntr-o pagin˘ Web se realizeaz˘ spea a cific˘nd pe lˆng˘ numele clasei principale ¸i numele arhivei care o contine: a a a s ¸ <applet archive=arhiva. deci ¸i din Component. adic˘ un obiect de a a a tip SecurityManager care va ”superviza” activitatea metodelor appletului. a a ¸ a Un applet nu poate s˘: a • Citeasc˘ sau s˘ scrie fi¸iere pe calculatorul pe care a fost ˆ a a s ıncarcat (client). procesul care a ruleaz˘ appleturi instaleaz˘ un manager de securitate.. Un applet poate functiona ¸i ca a ¸ s o aplicatie independent˘ astfel: ¸ a .10 Restrictii de securitate ¸ Deoarece un applet se execut˘ pe ma¸ina utilizatorului care a solicitat paga s ina Web ce contine appletul respectiv.jar code=ClasaPrincipala width=400 height=200 /> 14. Pentru a realiza acest lucru.10. cum ar fi o fereastr˘. a at Ferestrele folosite de un applet. vor ar˘ta a a altfel decˆt ˆ a ıntr-o aplicatie obi¸nuit˘. a s • Citeasc˘ diverse propriet˘¸i ale sistemului de operare al clientului. pentru a ¸ a preveni actiuni r˘u intentionate. cum ar fi ¸tergeri de fi¸iere. care s˘ ¸ a ¸ s s a aduc˘ prejudicii utilizatorului.

a ¸a s a a ¸ • Apel˘m metodele init ¸i start. add ( applet . CENTER ) . applet . a Listing 14. f . public class AppletAplicatie extends Applet public void init () { add ( new Label ( " Applet si aplicatie " ) ) . awt .422 CAPITOLUL 14. APPLETURI • Ad˘ug˘m metoda main clasei care descrie appletul. applet . } public static void main ( String args []) { AppletAplicatie applet = new AppletAplicatie () .8: Applet ¸i aplicatie s ¸ import java . start () . Applet . f . } } { . ˆ care vom face a a ın operatiunile urm˘toare. BorderLayout . 200) . Frame f = new Frame ( " Applet si aplicatie " ) . setSize (200 .*. ¸ a • Cre˘m o instant˘ a appletului ¸i o ad˘ug˘m pe suprafata unei ferestre. a • Facem fereastra vizibil˘. import java . f . care ar fi fost apelate automat de a s c˘tre browser. init () . show () . applet .

Pe lˆnga tabele. s Modelul clasic de baze de date este cel relational. ˆ care datele sunt ¸ ın memorate ˆ tabele.aceste ¸ a atribute corespund coloanelor tabelului. etc. SGBD (Sistem de Gestiune a Bazelor de Date). etc.1.1 15. cu posibilitatea reg˘sirii acestora. o baz˘ de date mai poate contine: proceduri ¸i a a ¸ s functii. Aceste a s produse sunt ˆ general referite prin termenii DBMS (Database Management ın System) sau. Sybase. as a Ce este o baz˘ de date ? a La nivelul cel mai general. fiecare furnizˆnd o a serie ˆ ıntreag˘ de produse ¸i utilitare pentru lucrul cu baze de date. ¸ s Dintre produc˘torii cei mai importanti de baze de date amintim coma ¸ paniile Oracle. o baz˘ de date reprezint˘ o modalitate de stocare a a a unor informatii (date) pe un suport extern. ˆ general. obiecte. o baz˘ de date este memorat˘ ˆ a a ıntr-unul sau mai multe fi¸iere. aplicatii complexe ¸ ın ¸ folosite pentru gestionarea unor informatii de dimensiuni mari ˆ ¸ ıntr-o manier˘ a sigur˘ ¸i eficient˘. ¸ a Uzual. tipuri de date. ˆ timp ce o linie va reprezenta un ın articol. ˆ traducere. utilizatori ¸i grupuri de utilizatori. IBM. Un tabel reprezint˘ o structur˘ de date format˘ dintr-o ın a a a multime de articole. Microsoft. fiecare articol avˆnd definite o serie de atribute . Informix.Capitolul 15 Lucrul cu baze de date 15.1 Introducere Generalit˘¸i despre baze de date at Aplicatiile care folosesc baze de date sunt. In ın acest capitol vom analiza lucrul cu baze de date din perspectiva program˘rii a 423 .

putem crea aplicatii care s˘ a ¸ a ruleze f˘r˘ nici o modificare folosind diverse tipuri de baze care au aceea¸i aa s structur˘. s ¸ ¸ Acesta este standardizat astfel ˆ at diverse tipuri de drivere s˘ se comporte ıncˆ a identic. LUCRUL CU BAZE DE DATE ˆ limbajul Java. folosind Java. ¸ s Limbajul SQL SQL (Structured Query Language) reprezint˘ un limaj de programare ce a permite interogarea ¸i actualizarea informatiilor din baze de date relationale.424 CAPITOLUL 15. Acest aspect ne va s preocupa ˆ a mai putin. exemplele prezentate presupunˆnd c˘ baza a fost ıns˘ ¸ a a creat˘ deja ¸i are o anumit˘ structur˘ specificat˘. a 15. f˘r˘ a descrie particularit˘¸i ale unei solutii de stocare a ın aa at ¸ datelor anume. ducˆnd ˆ felul acesta notiunea de portabilitate ¸i mai departe. a a ın ¸ s Crearea unei baze de date Crearea unei baze de date se face uzual folosind aplicatii specializate oferite ¸ de produc˘torul tipului respectiv de sistem de gestiune a datelor.2 JDBC JDBC (Java Database Connectivity) este o interfat˘ standard SQL de acces ¸a la baze de date. a s a a a Accesul la baza de date Se face prin intermediul unui driver specific tipului respectiv de SGBD. JDBC este constituit˘ dintr-un set de clase ¸i interfete a s ¸ . oferind astfel o modalitate unitar˘ de lucru cu baze de date. Acesta este responsabil cu accesul efectiv la datele stocate.1. Vom vedea c˘. dar exist˘ a a ¸i posibilitatea de a crea o baza folosind un script SQL. fiind legatura dintre aplicatie ¸i baza de date.

ın ¸ . Prelucrarea rezultatelor obtinute.sql. furnizˆnd mecanisme standard pentru proiectantii aplicatiilor ın a ¸ ¸ ce folosesc de baze de date.2 Conectarea la o baz˘ de date a Procesul de conectare la o baz˘ de date implic˘ efectuarea a dou˘ operatii: a a a ¸ 1. alt program pentru a accesa o baz˘ de date a a Sybase ¸i asa mai departe. a 2. a 2. Inregistrarea unui driver corespunz˘tor. nu este necesar s˘ scriem un program pentru a ¸ a accesa o baz˘ de date Oracle. Bineˆ ¸eles. ne este asigurat˘ portabilitatea programului. a s javax. Stabilirea unei conexiuni cu o baz˘ de date. API-ul JDBC ofer˘ urm˘toarele facilit˘¸i: a a at 1.2. trimitˆnd s a ¸a secvente SQL c˘tre baza de date dorit˘. scriind codul surs˘ ˆ ¸ a a ınt a ın Java. Intr-o aplicatie pot exista ¸ s ¸ simultan mai multe conexiuni la baze de date diferite sau la aceea¸i baz˘. CONECTAREA LA O BAZA DE DATE 425 scrise ˆ Java. s a Clasele ¸i interfetele responsabile cu realizarea unei conexiuni sunt: s ¸ • DriverManager . Efectuarea de secvente SQL. Cu alte cuvinte. Folosind JDBC este u¸or s˘ transmitem secvente SQL c˘tre baze de date s a ¸ a relationale.JDBC demn˘ de luat ˆ seam˘. ¸ 3. Realizarea unei conexiuni propriu-zise. ¸ a ın a Pachetele care ofer˘ suport pentru lucrul cu baze de date sunt java. Deci. In linii mari. Este de ajuns s˘ scriem un singur program folosind s a API-ul JDBC ¸i acesta va fi capabil s˘ comunice cu drivere diferite. iat˘ dou˘ motive a a a puternice care fac combinatia Java . Definitie ¸ O conexiune (sesiune) la o baz˘ de date reprezint˘ un context prin care a a sunt trimise secvente SQL ¸i primite rezultate. preluat de pe platforma J2EE. ¸ 15.˘ 15.sql a ce reprezint˘ nucleul tehnologiei JDBC ¸i.este clasa ce se ocup˘ cu ˆ a ınregistrarea driverelor ce vor fi folosite ˆ aplicatie.

"TipDriver").forName ce apeleaz˘ ClassLoader-ul ma¸inii a s virtuale: Class.drivers".interfata pe care trebuie s˘ o implementeze orice clas˘ ce ¸ a a descrie un driver.1 Inregistrarea unui driver Primul lucru pe care trebuie s˘-l fac˘ o aplicatie ˆ procesul de conectare a a ¸ ın la o baz˘ de date este s˘ ˆ a a ınregistreze la ma¸ina virtual˘ ce ruleaz˘ aplicatia s a a ¸ driverul JDBC responsabil cu comunicarea cu respectiva baz˘ de date. b.prin intermediul acestei clase pot fi specificate diverse propriet˘¸i ce vor fi folosite la realizarea conexiunilor. Setarea propriet˘¸ii sistem jdbc.setProperty("jdbc.registerDriver(new TipDriver()). s 2) Driverele ˆ ınregistrate dinamic din aplicatie.forName("TipDriver"). Acest a lucru presupune ˆ arcarea ˆ memorie a clasei ce implementeaz˘ driver-ul ¸i ınc˘ ın a s poate fi realizat˘ ˆ mai multe modalit˘¸i. • DriverPropertyInfo . s a Dac˘ sunt ˆ a ınregistrate mai multe drivere. specificarea mai multor drivere se face separˆnd a a a numele claselor cu punct ¸i virgul˘. at • Connection . c.descrie obiectele ce modeleaz˘ o conexiune propriu-zis˘ a a cu baza de date. care poate fi realizat˘ ˆ dou˘ at a ın a feluri: – De la linia de comand˘: a java -Djdbc.2. ordinea de precedent˘ ˆ alegerea ¸a ın driverului folosit la crearea unei noi conexiuni este: 1) Driverele ˆ ınregistrate folosind proprietatea jdbc.drivers=TipDriver Aplicatie – Din program: System. LUCRUL CU BAZE DE DATE • Driver .newInstance(). Folosind aceast˘ metod˘. Class.426 CAPITOLUL 15. 15. ¸ .drivers la initializarea ¸ ma¸inii virtuale ce va rula procesul.forName("TipDriver"). Folosirea metodei Class.drivers. Folosirea clasei DriverManager: DriverManager. a ın at a.

ˆ sensul c˘ permite specificarea ın a ˆ cadrul URL-ului a unor atribute ce vor fi realizate la crearea unei conexiın uni. In functie a ¸ s a ¸ ¸ de tipul driver-ului acest identificator poate include numele unei ma¸ini s gazd˘. Avˆnd ˆ vedere faptul ca pot exista mai a a ın multe drivere ˆ arcate ˆ memorie.2..˘ 15.com:1521:test jdbc:sybase:test jdbc:db2:test Subprotocolul odbc este un caz specical.atribut=valoare]* jdbc:odbc:test jdbc:odbc:test. Dac˘ nu exista nici unul potrivit. ca a a s ˆ exemplele de mai jos: ın jdbc:odbc:test jdbc:oracle:thin@persistentjava. db2 ¸i a¸a mai departe.2 Specificarea unei baze de date O dat˘ ce un driver JDBC a fost ˆ a ınregistrat.ExtensionCase=LOWER jdbc:odbc:test. oracle. trebuie s˘ avem posibilitea de a specifica ınc˘ ın a pe lˆng˘ un identificator al bazei de date ¸i driverul ce trebuie folosit. numele unui fi¸ier sau al unui director. Sintaxa completa subprotocolului odbc este: jdbc:odbc:identificator[.CacheSize=20. . s s s Identificatorul bazei de date este un indicator specific fiec˘rui driver corea spunz˘tor bazei de date cu care aplicatia dore¸te s˘ interactioneze. DriverManager-ul va parcurge lista driverelor ˆ ınregistrate ˆ memorie. etc. Aceasta a a s se realizeaz˘ prin intermediul unei adrese specifice. numit˘ JDBC URL. ce a a are urm˘torul format: a jdbc:sub-protocol:identificator Cˆmpul sub-protocol denume¸te tipul de driver ce trebuie folosit pentru a s realizarea conexiunii ¸i poate fi odbc. pˆna cˆnd unul dintre ele va recunoa¸te URL-ul reın a a s spectiv. sybase. CONECTAREA LA O BAZA DE DATE 427 15.2.UID=duke. un num˘r de port. acesta poate fi folosit la stabilirea unei conexiuni cu o baz˘ de date.PWD=java La primirea unui JDBC URL. cu mesajul "no suitable driver". atunci va fi lansata o exceptie de a ¸ tipul SQLException.

atˆt ODBC-ul cˆt ¸i driver-ul nativ a a s trebuie s˘ existe pe ma¸ina pe care ruleaz˘ aplicatia.JdbcOdbcDriver ¸i este inclus˘ ˆ distributia standard J2SDK. De asemenea.jdbc. a s a ¸ Clasa Java care descrie acest tip de driver JDBC este: sun. De¸i simplu de utilizat. LUCRUL CU BAZE DE DATE 15.3 Tipuri de drivere Tipurile de drivere existente ce pot fi folosite pentru realizarea unei conexiuni prin intermediul JDBC se ˆ ımpart ˆ urm˘toarele categorii: ın a Tip 1.Driver nativ . Conectarea efectiv˘ la baza de date se va face prin intermediul a a acestui identificator.odbc. JDBC-ODBC Bridge Acest tip de driver permite conectarea la o baz˘ de date care a fost a ˆ ınregistrat˘ ˆ prealabil ˆ ODBC. driver-ul ODBC efectuˆnd comunicarea cu driverul naa tiv al bazei de date. Specificarea bazei de date se s a ın ¸ face printr-un URL de forma: jdbc:odbc:identificator unde identif icator este profilul (DSN) creat bazei de date ˆ ODBC.2. Driver JDBC . asociind a acestora un identificator DSN (Data Source Name) ¸i diver¸i parametri neces s sari conect˘rii. ODBC (Open Database Conectivity) a ın ın reprezint˘ o modalitate de a uniformiza accesul la baze de date.428 CAPITOLUL 15. solutia JDBC-ODBC nu este portabil˘ ¸i comunis ¸ as carea cu baza de date sufer˘ la nivelul vitezei de executie datorit˘ multiplelor a ¸ a redirect˘ri ˆ a ıntre drivere. ın Tip 2.

˘ 15. acestea fiind apoi transormate folosind o aplicatie server ˆ ¸ ıntr-un protocol specfic bazei de date. Driver JDBC . ¸ a Tip 3. care trebuie instalat ˆ prealabil. Introducerea serverului ca nivel intermediar aduce flexibilitate maxim˘ ˆ sensul c˘ vor putea fi realizate conexiuni cu a ın a diferite tipuri de baze. CONECTAREA LA O BAZA DE DATE 429 Acest tip de driver transform˘ cererile JDBC direct ˆ apeluri c˘tre a ın a driverul nativ al bazei de date. a a Tip 4. Clase Java ın care implementeaz˘ astfel de drivere pot fi procurate de la produc˘torii de a a SGBD-uri. f˘r˘ nici o modificare la nivelul clientului.Server Acest tip de driver transform˘ cererile JDBC folosind un protocol de retea a ¸ independent.2. Driver JDBC nativ . distributia standard J2SDK neincluzˆnd nici unul. Protocolul aa folosit este specific fiec˘rui produc˘tor.

JdbcOdbcDriver").getConnection(url.getConnection(url). LUCRUL CU BAZE DE DATE Acest tip de driver transform˘ cererile JDBC direct ˆ cereri c˘tre baza a ın a de date folosind protocolul de retea al acesteia.println("SQLException: " + e).2.jdbc. } Connection con . Connection c = DriverManager. return .odbc. fiind preferat˘ la dezvoltarea aplicatiilor care manevreaz˘ volume a a ¸ a mari de date ¸i viteza de executie este critic˘.err. Drivere de acest tip pot fi s ¸ a procurate de la diver¸i produc˘tori de SGBD-uri. // sau url = "jdbc:odbc:test. "duke".4 Realizarea unei conexiuni Metoda folosit˘ pentru realizarea unei conexiuni este getConnection din a clasa DriverManager ¸i poate avea mai multe forme: s Connection c = DriverManager. "java"). username.forName("sun. dbproperties).err.430 CAPITOLUL 15. Aceast˘ solutie este cea mai ¸ a ¸ rapid˘. try { Class.print("ClassNotFoundException: " + e) .getConnection(url. } catch(SQLException e) { System. } catch(ClassNotFoundException e) { System. password).getConnection(url. s a 15. Connection c = DriverManager. Stabilirea unei conexiuni folosind driverul JDBC-ODBC String url = "jdbc:odbc:test" . try { con = DriverManager.PWD=java" .UID=duke. .

jdbc. try { Class. a 15. } catch(ClassNotFoundException e) { . • Aflarea unor informatii legate de baza de date (meta-date). } } 431 Stabilirea unei conexiuni folosind un driver MySql Folosirea diferitelor tipuri de drivere implic˘ doar schimbarea numelui clasei a ce reprezint˘ driverul ¸i a modalit˘¸ii de specificare a bazei de date.close . // sau url = "jdbc:mysql://localhost/test?user=duke&password=java".15. clasa Connection asigur˘ facilit˘¸i pentru controlul tranzactiilor a at ¸ din memorie c˘tre baza de date prin metodele commit.Driver") .err. ¸ De asemenea..mysql. Cele mai uzuale comenzi ¸ a SQL sunt cele folosite pentru: • Interogarea bazei de date: SELECT .forName("com.. Inchiderea unei conexiuni se realizeaz˘ prin metoda close.PreparedStatement sau CallableStatement cu ajutorul c˘rora a putem trimite secvente SQL c˘tre baza de date.getConection. a s at String url = "jdbc:mysql://localhost/test" .3. EFECTUAREA DE SECVENTE SQL ¸ } finally { try{ con. } catch(SQLException e) { System.3 Efectuarea de secvente SQL ¸ O dat˘ facut˘ conectarea cu metoda DriverManager. se poate a a folosi obiectul Connection rezultat pentru a se crea obiecte de tip Statement. rollback.println(SQLException: " + e) . O conexiune va fi folosit˘ pentru: a • Crearea de secvente SQL utilizate pentru interogarea sau actualizarea ¸ bazei. setAua toCommit.

executeUpdate Este folosit˘ pentru actualizarea datelor (INSERT. Metoda returneaz˘ a a a un obiect de tip ResultSet ce va contine sub o form˘ tabelar˘ rezultatul ¸ a a interog˘rii. ResultSet rs = stmt. DELETE • Actualizarea structurii: CREATE.acestea mai sunt numite instructiuni DDL (Data Definition Language) ¸ • Apelarea unei proceduri stocate: CALL Dup˘ cum vom vedea.createStatement(). ALTER. s Crearea unui obiect Statement se realizeaz˘ prin intermediul metodei a createStatement a clasei Connection. Statement stmt = con. ın ¸ .executeQuery(sql). f˘r˘ nici un argument: aa Connection con = DriverManager.432 CAPITOLUL 15. a 15. ALTER. Executia unei secvente SQL poate fi realizat˘ prin intermediul a trei ¸ ¸ a metode: 1. LUCRUL CU BAZE DE DATE • Actualizarea datelor: INSERT. executeQuery Este folosit˘ pentru realizarea de interog˘ri de tip SELECT.getConnection(url). obtinerea ¸i prelucrarea rezultatelor unei interog˘ri a ¸ s a este realizat˘ prin intermediul obiectelor de tip ResultSet. Metoda va returna un ˆ ıntreg ce semnific˘ num˘rul de linii afectate de operatiunea de actualizare a a a ¸ datelor. a String sql = "SELECT * FROM persoane".1 Interfata Statement ¸ Interfata Statement ofer˘ metodele de baz˘ pentru trimiterea de secvente ¸ a a ¸ SQL c˘tre baza de date ¸i obtinerea rezultatelor. UPDATE. DROP). DROP . celelalte dou˘ interfete: a s ¸ a ¸ PreparedStatement ¸i CallableStatement fiind derivate din aceasta.3. UPDATE. 2. DELETE) sau a a structurii bazei de date (CREATE. sau 0 ˆ cazul unei instructiuni DDL.

continue.3. respectiv a a ¸ −1. sau o combinatie a a ¸ ˆ ıntre aceste cazuri. execute Aceast˘ metod˘ va fi folosit˘ doar dacˆ este posibil ca rezultatul unei ina a a a terog˘ri s˘ fie format din dou˘ sau mai multe obiecte de tip ResultSet sau a a a rezultatul unei actualiz˘ri s˘ fie format din mai mule valori.getUpdateCount(). pot fi apelate metodele: getResultSet sau getUp¸ dateCount pentru a afla efectiv rezultatul comenzii SQL. while(true) { int rowCount = stmt. In functie de aceasta. EFECTUAREA DE SECVENTE SQL ¸ String sql = "DELETE FROM persoane WHERE cod > 100". pˆn˘ la obtinerea valorii null. if(rowCount > 0) { // Este o actualizare datelor System.println("Linii afectate = " + rowCount).15. Metoda ˆ ıntoarce true dac˘ rezultatul obtinut a ¸ este format din obiecte de tip ResultSet ¸i false dac˘ e format din ˆ s a ıntregi. // returneaza 0 433 3. de¸i mai rar˘. Pentru a prelua toate rezultatele va fi apelat˘ metoda getMoreResults.println("Comanda DDL sau 0 actualizari"). stmt. } if(rowCount = 0) { // Comanda DDL sau nici o linie afectata System.getMoreResults(). stmt.out.executeUpdate(sql). dup˘ care vor fi a a apelate din nou metodele amintite. // Nr de articole care au fost afectate (sterse) sql = "DROP TABLE temp". int linii = stmt. .execute(sql). este posibil˘ atunci cˆnd a ¸ s a a a sunt executate proceduri stocate sau secvente SQL cunoscute abia la momen¸ tul executiei. Secventa complet˘ de tratare a metodei execute este prezentat˘ mai ¸ a a jos: String sql = "comanda SQL necunoscuta". stmt.out. programatorul ne¸tiind deci dac˘ va fi vorba de o actualizare ¸ s a a datelor sau a structurii.executeUpdate(sql). Aceast˘ situatie.

LUCRUL CU BAZE DE DATE stmt. String nume = "Popescu". care vor fi specificati a ¸ ¸ prin intermediul unui semn de ˆ ıntrebare (”?”) ˆ locul fiec˘ruia dintre ın a ..executeQuery(sql). nu avem alt˘ solutie decˆt s˘ cre˘m un ¸a a ¸ a a a ¸ir de caractere compus din instructiuni SQL ¸i valorile variabilelor: s ¸ s int cod = 100. if(rs != null) { // Proceseaza rezultatul ..2 Interfata PreparedStatement ¸ Interfata PreparedStatement este derivat˘ din Statement. a • O secvent˘ SQL specificat˘ unui obiect PreparedStatement poate s˘ ¸a a a aib˘ unul sau mai multi parametri de intrare.getMoreResults(). stmt. } // Nu mai avem nici un rezultat break. fiind diferit˘ de ¸ a a aceasta ˆ urm˘toarele privinte: ın a ¸ • Instantele de tip PreparedStatement contin secvente SQL care au fost ¸ ¸ ¸ deja compilate (sunt ”preg˘tite”).getMoreResults().3.434 CAPITOLUL 15. ResultSet rs = stmt. } // rowCount este -1 // Avem unul sau mai multe ResultSet-uri ResultSet rs = stmt. continue. } Folosind clasa Statement. ˆ cazul ˆ care dorim s˘ introducem valorile ın ın a unor variabile ˆ ıntr-o secvent˘ SQL.getResultSet(). continue. String sql = "SELECT * FROM persoane WHERE cod=" + cod + " OR nume=’" + nume + "’". 15.

15. a ¸ a Putem apoi stabili alte valori de intrare ¸i refolosi obiectul PreparedStatement s pentru executii repetate ale comenzii SQL. Este ˆ a posibil ca SGBD-ul ¸ ıns˘ folosit s˘ nu suporte acest tip de operatiune ¸i s˘ nu retin˘ obiectul prea ¸ s a ¸ a compilat pentru executii ulterioare. specificˆn ca ara gument o secvent˘ SQL ce contine c˘te un semn de ˆ ¸a ¸ a ıntrebare pentru fiecare parametru de intrare: Connection con = DriverManager. folosind metode specifice a acestei clase. String sql = "UPDATE persoane SET nume=? WHERE cod=?". ¸ ¸ Executia unei secvente SQL folosind un obiect PreparedStatement se ¸ ¸ realizeaz˘ printr-una din metodele executeQuery. Statement pstmt = con. dar cu parametri diferiti. In aceast˘ situatie folosirea interfetei ¸ a ¸ ¸ PreparedStatement ˆ loc de Statement nu va ˆ ın ımbun˘t˘¸i ˆ nici un fel a at ın performanta codului. Obiectul va pstmt contine o comand˘ SQL precompilat˘ care este trimis˘ ¸ a a a imediat c˘tre baza de date.setString(1. a Trimiterea parametrilor se realizeaz˘ prin metode de tip setXXX.getConnection(url).prepareStatement(sql). . ci a a a refolosim o singur˘ instant˘ precompilat˘ furnizˆndu-i doar alte argumente. pstmt. a unde XXX este tipul corespunz˘tor parametrului. executeUpdate sau a execute.3. din punctul de vedere al vitezei de executie a acestuia. unde va a¸tepta parametri de intrare pentru a a s putea fi executat˘. va ¸ a s ¸ ¸ fi ˆ general mai rapid˘ dac˘ folosim PreparedStatement. s a pstmt. a ¸a a a Crearea unui obiect de tip PreparedStatement se realizeaz˘ prin intera mediul metodei prepareStatement a clasei Connection. 100). iar argumentele metodei a sunt num˘rul de ordine al parametrului de intrare (al semnului de ˆ a ıntrebare) ¸i valoarea pe care dorim s˘ o atribuim.setInt(2. semnificatiile lor fiind acelea¸i ca ¸i ˆ cazul obiectelor de tip ¸ s s ın Statement. cu singura deosebire c˘ ˆ cazul de fat˘ ele nu au nici un ara ın ¸a gument. Executia repetat˘ a aceleia¸i secvente SQL. Dup˘ stabilirea parametrilor de intrare secventa SQL poate fi executat˘. deoarece nu mai ın a a trebuie s˘ cre˘m cˆte un obiect de tip Statement pentru fiecare apel SQL. Inainte ca secventa SQL s˘ poat˘ fi executat˘ fiec˘rui parametru ¸ a a a a de intrare trebuie s˘ i se atribuie o valoare. EFECTUAREA DE SECVENTE SQL ¸ 435 ei. "Ionescu").

executeUpdate(). pstmt. pstmt. 100). pstmt. Types. numite ¸i tipuri JDBC.setString(1. Types. Lista tuturor tipurilor generice disponibile.436 CAPITOLUL 15. pstmt. "Popescu"). a pstmt.setString(1. "Ionescu").setInt(2. atunci cˆnd dorim s˘ folosim maparea a a implicit˘ ˆ a ıntre tipurile Java ¸i cele JDBC sau atunci cˆnd dorim s˘ preciz˘m s a a a explicit un tip JDBC.prepareStatement(sql). Types. "Ionescu". 100). 200). // sau doar pstmt. 100). 100. Exist˘ ˆ a situatii cˆnd este de preferat ca datele de mari dimensia ıns˘ ¸ a uni s˘ fie transferate pe ”buc˘¸i” de o anumit˘ dimensiune. null). Statement pstmt = con.prepareStatement(sql).executeUpdate().setInt(2.setInt(1. sql = "SELECT * from persoane WHERE cod >= ?".setObject(1. pstmt = con.setInt(2. pstmt. Cu ajutorul metodelor setBytes sau setString avem posibilitatea de a specifica date de orice dimensiuni ca valori pentru anumite articole din baza de date. Pentru a realiza a at a . pstmt. pstmt. Folosind metoda setNull putem s˘ atribuim unui parametru de intrare a valoare SQL NULL. Metoda setObject permite specificarea unor valori pentru parametrii de intrare.CHAR). LUCRUL CU BAZE DE DATE String sql = "UPDATE persoane SET nume=? WHERE cod=?". pstmt.CHAR). prin cons a stantelor declarate de aceasta. Fiec˘rui tip Java ˆ corespunde un tip generic SQL. Este responsabilitatea a ıi programatorului s˘ se asigure c˘ folose¸te metoda adecvat˘ de tip setXXX la a a s a stabilirea valorii unui parametru de intrare.setNull(1. Acela¸i lucru poate fi realizat cu metode de a s tipul setXXX dac˘ argumentul folosit are valoarea null. este definit˘ de clasa Types. trebuind ˆ a s˘ specific˘m ¸i tipul de date al coloanei ˆ ıns˘ a a s ın care vom scrie aceast˘ valoare.INTEGER). pstmt. ResultSet rs = pstmt.setObject(2. pstmt.executeQuery().setObject(2.

Trimiterea parametrilor de intrare se realizeaz˘ ˆ a ıntocmai ca la PreparedStatement. instantele ¸ a ¸ de acest tip oferind o modalitate de a apela o procedur˘ stocat˘ ˆ a a ıntr-o baz˘ a de date.setUnicodeStream (1. EFECTUAREA DE SECVENTE SQL ¸ 437 acest lucru API-ul JDBC pune la dispozitie metodele setBinaryStream. atribuind coloanei continut continutul a ¸ unui anumit fi¸ier: s File file = new File("date.prepareCall( "{call proceduraStocata(?. Dac˘ procedura are ¸i parametri de ie¸ire (valori a s s returnate). a Crearea unui obiect CallableStatement se realizeaz˘ prin metoda prea pareCall a clasei Connection: Connection con = DriverManager.executeUpdate().PreparedStatement pstmt = con.txt"). fileLength). java. CallableStatement cstmt = con. pstmt.sql.prepareCall( .getConnection(url). unui parametru de intrare. Obtinerea valorilor rezultate ˆ parametrii ¸ ¸ ın de ie¸ie se va face cu metode de tip getXXX. acest lucru fiind solicitat de unele tipuri de baze de date. fluxul de intrare va fi apelat repetat pentru a ¸ ¸ furniza datele ce vor fi scrise ˆ coloana continut a articolului specificat. fin.length(). Exema a plul de mai jos ilustreaz˘ acest lucru. 15. caractere ASCII. ¸ setAsciiStream ¸i setUnicodeStream care ata¸eaz˘ un flux de intrare pe s s a octeti.txt’"). ele vor fi atribuite parametrului. ?)}"). Pe ¸ m˘sur˘ ce sunt citite date de pe flux. pstmt. cu metode de tip setXXX.prepareStatement( "UPDATE fisiere SET continut = ? WHERE nume = ’date. respectiv UNICODE. ˆ ıntr-o manier˘ standar pentru toate SGBD-urile. ın Observati c˘ este necesar ˆ a s˘ ¸tim dinainte dimensiunea datelor ce vor fi ¸ a ın˘ a s scrise.3. La executia secventei.15. int fileLength = file.3 Interfata CallableStatement ¸ Interfata CallableStatement este derivat˘ din PreparedStatement. ace¸tia vor trebui ˆ s ınregistrati cu metoda registerOutParame¸ ter ˆ ınainte de executia procedurii. InputStream fin = new FileInputStream(file). s CallableStatement cstmt = con.3.

Pentru s a acest lucru vom folosi metode de tip getXXX. a Statement stmt = con. a a a a .438 CAPITOLUL 15. In a s s acest caz el trebuie s˘ primeasc˘ o valoare cu setXXX ¸i. Forma general˘ a unui ResultSet este tabelar˘. etc. Este posibil ca un parametru de intrare s˘ fie ¸i parametru de ie¸ire. num˘rul lor. cstmt.sql.registerOutParameter(1. java. De asemenea. fie numele acestuia. nume FROM persoane". In general.FLOAT). float medie = cstmt. LUCRUL CU BAZE DE DATE "{call calculMedie(?)}"). Coloanele sunt numerotate de la stˆnga a la dreapta. ˆ ıncepˆnd cu 1. tipurile de date specificate trebuind s˘ coincid˘. a a avˆnd un num˘r de coloane ¸i de linii. ResultSet rs = stmt.createStatement(). ce va contine toate liniile ce satisfac conditiile ¸ ¸ impuse de comanda SQL.3. String sql = "SELECT cod. Rezultatul interog˘rii de mai sus va fi obiectul rs cu urm˘toarea structur˘: a a a cod nume 100 Ionescu 200 Popescu Pentru a extrage informatiile din aceast˘ structur˘ va trebui s˘ parcurgem ¸ a a a tabelul linie cu linie ¸i din fiecare s˘ extragem valorile de pe coloane.executeQuery().3. a a 15. va fi a a s ˆ ınregistrat cu registerOutParameter. obiectul va contine ¸i meta-datele interog˘rii cum ar fi denumirele ¸ s a coloanelor selectate. De a a s ¸ ¸ a asemenea. de asemenea.getDouble(1).executeQuery(sql).Types. folosirea indexului coloanei ˆ loc de a ın numele s˘u va fi mai eficient˘. pentru maxim˘ portabilitate a a a se recomand˘ citirea coloanelor ˆ ordine de la stˆnga la dreapta ¸i fiecare a ın a s citire s˘ se fac˘ o singur˘ dat˘. functie de secventa executat˘.4 15. unde XXX este tipul de dat˘ al unei coloane iar argumentul primit indic˘ fie num˘rul de ordine din a a a cadrul tabelului.5 Obtinerea ¸i prelucrarea rezultatelor ¸ s Interfata ResultSet ¸ In urma executie unei interog˘ri SQL rezultatul va fi reprezentat printr-un ¸ a obiect de tip ResultSet. cstmt.

Dac˘ un ResultSet folose¸te un cursor modificabil ¸i care poate naviga a s s ˆ ambele sensuri.TYPE_SCROLL_INSENSITIVE. /* echivalent: int cod = r. a a a • updateXXX .getString(2).3.Deplaseaz˘ cursorul la o anumit˘ linie specificat˘ absolut. nume FROM persoane". while (rs.createStatement( ResultSet.15. .Actualizeaz˘ valoarea unei coloane din linia curent˘.out.println(cod + ".getInt(1). Initial acest cursor este pozitionat ˆ ın a ¸ ¸ ınaintea primei linii. " + nume). */ System.getInt("cod"). ResultSet rs = stmt. linie cu linie.executeQuery(sql). a a unde XXX este un tip de date.next()) { int cod = r. un tabel de tip ResultSet nu poate fi modificat iar cursorul asociat nu se deplaseaz˘ decˆt ˆ a a ınainte. nume FROM persoane". Este ˆ a posibil s˘ cre˘m ResultSet-uri care s˘ permit˘ modificarea ıns˘ a a a a sau deplasarea ˆ ambele sensuri. } Implicit. String sql = "SELECT cod. fiecare apel al metodei next determinˆnd trecerea la urm˘toarea a a linie. putem itera s prin rezultatul unei interog˘ri o singur˘ dat˘ ¸i numai de la prima la ultima a a as linie.CONCUR_UPDATABLE). Deoarece next returneaz˘ false cˆnd nu mai sunt linii de adus. EFECTUAREA DE SECVENTE SQL ¸ 439 Un obiect ResultSet folose¸te un cursor pentru a parcurge articolele s rezultate ˆ urma unei interog˘ri.getString("nume"). ResultSet. String nume = r. A¸adar.executeQuery(sql). String nume = r. ResultSet rs = stmt. atunci are la dispozitie o serie de metode ce se bazeaz˘ pe ın ¸ a acest suport: • absolute . uzual a a va fi folosit˘ o bucl˘ while-loop petru a itera prin articolele tabelului: a a String sql = "SELECT cod. Exemplul urm˘tor va folosi un cursor care ın a este modificabil ¸i nu va reflecta schimb˘rile produse de alti utilizatori dup˘ s a ¸ a crearea sa: Statement stmt = con.

revine la linia curent˘ din tabel. a a ın a Nu toate sistemele de gestiune a bazelor de date ofer˘ suport pentru a folosirea cursoarelor care pot fi modificate. nu s a s poate fi apelat˘ cˆnd cursorul este ˆ modul linie nou˘. numit˘ a a a linie nou˘. ıncˆ a a 15. avˆnd coloanele: cod. astfel ˆ at s˘ nu apar˘ anomalii. este responsabilitatea driver-ului bazei de ın date s˘ asigure rezolvarea problemelor legate de actualizarea concurent˘ a a a unui cursor.6 Exemplu simplu In continuare vom da un exemplul simplu de utilizare a claselor de baz˘ a mentionate anterior. Scriptul a s SQL de creare a bazei este: create table persoane(cod integer. Aplicatia va goli tabelul cu persoane. • insertRow . a a ın Linia curent˘ anterioar˘ a cursorului va fi memorat˘ pentru a se putea a a a reveni la ea. a s s Listing 15. a ¸ a ¸ ¸ • moveToCurrentRow .*. public class TestJdbc { public static void main ( String [] args ) { . LUCRUL CU BAZE DE DATE • updateRow . In cazul s ˆ care acest lucru este permis.deplaseaz˘ cursorul la o linie spceial˘.3.Transfer˘ actualiz˘rile f˘cute liniei ˆ baza de date. va efectua afi¸area lor ¸i calculul mediei salariilor. Pentru a determina dac˘ baza de a date permite acest lucru pot fi utilizate metodele supportsPositionedUpdate ¸i supportsPositionedDelete ale clasei DatabaseMetaData. a a a ın • moveToInsertRow . Programul va folosi o baz˘ de date MySql.¸terge linia curent˘ din tabel ¸i din baza de date.440 CAPITOLUL 15.insereaz˘ articolul din zona linie nou˘ ˆ baza de date. salariu double). utilizate˘ pentru a introduce noi articole ˆ baza de date. nume ¸i salariu. sql . ce contine ¸ a ¸ un tabel numit persoane. dup˘ care va ad˘uga aleator un ¸ a a num˘r de articole. a a ın cursorul trebuie s˘ fie pozitionat le linia nou˘ la executia acestei operatiuni. nume char(50).1: Exemplu simplu de utilzare JDBC import java . a • deleteRow .

cod ) . while ( rs . } try { Connection con = DriverManager . double salariu = 100 + Math . getInt ( " cod " ) + " . mysql .3. // salariul va fi intre 100 si 1000 pstmt . out . return . setString (2 . . } catch ( Cl as sNo tF oun dE x c e p t i o n e ) { System . i < n . " + rs .15. pstmt . getConnection ( url ) . Statement stmt = con . Driver " ) . // Calculam salariul mediu sql = " SELECT avg ( salariu ) FROM persoane " . out . pstmt . forName ( " com . // Golim tabelul persoane String sql = " DELETE FROM persoane " . executeQuery ( sql ) . rs = stmt . setInt (1 . " + rs . ? . createStatement () . executeQuery ( sql ) . nume . println ( rs . next () ) System . round ( Math . try { Class . executeUpdate () . stmt . getDouble ( " salariu " ) ) . salariu ) int n = 10. ?) " . } // Afisam persoanele ordonate dupa salariu sql = " SELECT * FROM persoane ORDER BY salariu " . getString ( " nume " ) + " . 441 // Adaugam un numar de persoane generate aleator // Tabelul persoane are coloanele ( cod . EFECTUAREA DE SECVENTE SQL ¸ String url = " jdbc : mysql :// localhost / test " . println ( " Eroare incarcare driver !\ n " + e ) . ResultSet rs = stmt . next () . PreparedStatement pstmt = con . pstmt . nume ) . i ++) { int cod = i . prepareStatement ( sql ) . salariu ) . sql = " INSERT INTO persoane VALUES (? . for ( int i =0. jdbc . random () * 900) . String nume = " Persoana " + i . setDouble (3 . executeUpdate ( sql ) . rs .

ale bazei de date.2: Folosirea interfetei DatabaseMetaData ¸ import java . } } } 15. close () . vom obtine un obiect de tip DatabaseMetaData ce ofer˘ metode pentru deter¸ a minarea tabelelor.1 Lucrul cu meta-date Interfata DatabaseMetaData ¸ Dup˘ realizarea unui conexiuni la o baz˘ de date. LUCRUL CU BAZE DE DATE System . null . out . } catch ( Cl as sNo t F o u n d E x c e p t i o n e ) { System .4 15.4. odbc . putem apela metoda geta a MetaData pentru a afla diverse informatii legate de baza respectiv˘. capabilit˘¸ilor conexiunii. ResultSet rs = dbmd . forName ( " sun . gramaticii at SQL suportate. Ca rezult al apelului metodei. etc.442 CAPITOLUL 15. out . } try { Connection con = DriverManager . . a¸a ¸ a s numitele meta-date (”date despre date”). procedurilor stocate. public class TestMetaData { public static void main ( String [] args ) { String url = " jdbc : odbc : test " . null . null ) . getDouble (1) ) .*. return . printStackTrace () . a ın Listing 15. Programul urm˘tor afi¸eaz˘ numele tuturor tabelelor dintr-o baz˘ de dat a s a a ˆ ınregistrat˘ ˆ ODBC. getConnection ( url ) . jdbc . println ( " Eroare incarcare driver !\ n " + e ) . } catch ( SQLException e ) { e . // Inchidem conexiunea con . println ( " Media : " + rs . JdbcOdbcDriver " ) . getTables ( null . try { Class . DatabaseMetaData dbmd = con . getMetaData () . sql .

tipul ¸i denumirile lor.2 Interfata ResultSetMetaData ¸ Meta-datele unui ResultSet reprezint˘ informatiile despre rezultatul continut a ¸ ¸ ˆ acel obiect cum ar fi num˘rul coloanelor. con . etc. // Aflam numarul de coloane int n = rsmd. ResultSetMetaData rsmd = rs. LUCRUL CU META-DATE while ( rs . next () ) System . i<=n. ¸ ResultSet rs = stmt. } catch ( SQLException e ) { e . i++) nume[i] = rsmd. care va returna un obiect de tip ResultSetMetaData ce poate fi apoi folosit pentru extragerea informatiilor dorite.4. Acesın a s tea sunt obtinute apelˆnd metoda getMetaData pentru ResultSet-ul re¸ a spectiv. out .15.getMetaData(). for(int i=1.getColumnCount(). println ( rs . getString ( " TABLE_NAME " ) ) . printStackTrace () . // Aflam numele coloanelor Sring nume[] = new String[n+1].4. } } } 443 15.getColumnName(i). .executeQuery("SELECT * FROM tabel"). close () .

444 CAPITOLUL 15. LUCRUL CU BAZE DE DATE .

corespunz˘tor clasei respective. Editarea de leg˘turi . momentul efectiv ˆ care se realizeaz˘ acest a ın a lucru depinzˆnd de implementarea ma¸inii virtuale.Capitolul 16 Lucrul dinamic cu clase 16. In urma acestui proces.lang. Initializarea . ¸ a 445 . Spre deosebire de alte limbaje de progra¸ ın a mare cum ar fi C sau C++. va fi instantiat un obiect de ın ¸ tip java.class) pe baza numelui complet al acestuia ¸i ˆ arcarea acess s ınc˘ teia ˆ memorie. a 2. un program Java compilat nu este descris de un fi¸ier executabil ci de o multime de fi¸iere cu extensia . aceste clase nu sunt ˆ arcate toate ˆ a ın˘ ın memorie la pornirea aplicatiei. Operatiunea de a ¸ ˆ arcare a unei clase este realizat˘ la un moment ce precede prima ınc˘ a utilizare efectiv˘ a sa.Const˘ ˆ executia blocurilor statice de initializare ¸i ¸ a ın ¸ ¸ s initializarea variabilelor de clas˘.Este procesul reg˘sirii reprezent˘rii binare a unei clase a a a (fi¸ierul . 3. aceasta fiind responsabil˘ cu interpretarea codului de a a octeti rezultat ˆ urma compil˘rii.Class. a s Ciclul de viat˘ al unei clase are a¸adar urm˘toarele etape: ¸a s a 1. ci sunt ˆ arcate pe parcursul executie acesteia ¸ ın˘ ¸ atunci cˆnd este nevoie de ele.class corespunz˘toare s ¸ s a fiec˘rei clase a programului. Inc˘rcarea .Specific˘ incorporarea noului tip de date ˆ JVM a a ın pentru a putea fi utlizat.1 Inc˘rcarea claselor ˆ memorie a ın Dup˘ cum ¸tim executia unei aplicatii Java este realizat˘ de c˘tre ma¸ina a s ¸ ¸ a a s virtual˘ Java (JVM). In plus.

r˘d˘cina acestuia a a fiind class loader-ul primordial. Fiecare instanta de tip ClassLoader va avea ¸ a¸adar un p˘rinte (evident.2 de Java. a Inc˘rcarea claselor unei aplicatii Java ˆ memorie este realizat˘ prin ina ¸ ın a termediul unor obiecte pe care le vom numi generic class loader. In momentul cˆnd este solicitat˘ ˆ arcarea unei clase. Desc˘rcarea . Class loader-e proprii . Aceasta este o clas˘ ¸ a abstract˘. sau a unor resurse ce sunt necesare function˘rii acesteia. ˆ arcarea unei clase poate a a ınc˘ determina ˆ arcarea unor altor clase care sigur vor fi folosite ˆ ınc˘ ımpreun˘ cu a prima. fiind responsabil cu ˆ arcarea claselor stana s ınc˘ dard din distributia Java. Dac˘ nici ea nu va reu¸i. la executia unui program Java vor fi create implicit a ¸ dou˘ obiecte de tip ClassLoader pentru ˆ arcarea ˆ memorei a claselor a ınc˘ ın proprii ale aplicatiei. mai putin r˘d˘cina). bootstrap) . a fost introdus un model de tip delegat. . pentru a minimiza ˆ arcarea aceleia¸i ın ¸ ınc˘ s clase de mai multe ori.446 CAPITOLUL 16.Acestea nu fac parte intrinsec˘ din JVM ¸i a s sunt instante ale clasei java.ClassLoader.Atunci cˆnd nu mai exist˘ nici o referint˘ de tipul clasei a a a ¸a respective. s ˆ multe situatii el este de preferat. Class loader-ul primordial (eng. LUCRUL DINAMIC CU CLASE 4. a ˆ care class loader-ele sunt dispuse ierarhic ˆ ın ıntr-un arbore. ¸ a Incepˆnd cu versiunea 1. Acestea sunt de dou˘ tipuri: a 1. va fi aruncat˘ o exceptie de tipul ınc˘ a s a ¸ ClassNotFoundException.Reprezint˘ o parte intea grant˘ a ma¸inii virtuale. tipul efectiv al obiectului fiind a¸adar derivat din aceasta. acesta fiind specificat la s a ¸ a a crearea sa. etc.lang. va ˆ s s ıncerca s˘ execute operatiunea de a ¸ ˆ arcare a clasei. ¸ 2. a s Dup˘ cum vom vedea. Astfel. De¸i acest comportament nu este obligatoriu. folosind class loader-e diferite. Exist˘ ˆ a posibilitarea de a crea noi tipuri derivate din ¸ a ıns˘ ClassLoader specializate pentru ˆ arcarea claselor conform unor specificatii ınc˘ ¸ anume care s˘ realizeze diverse optimiz˘ri. obiectul de tip Class creat va fi marcat pentru a fi eliminat din memorie de c˘tre garbage collector. Abia ˆ cazul ˆ ın ın care nici unul din ace¸tia nu a reu¸it. un classa a ınc˘ loader poate delega ˆ primul rˆnd operatiunea de ˆ arcare p˘rintelui s˘u ın a ¸ ınc˘ a a care va delega la rˆndul s˘u cererea mai departe pˆn˘ la class loader-ul a a a a primordial sau pˆn˘ unul din ace¸tia reu¸e¸te s˘ o ˆ a a s s s a ıncarce.

Inc˘rcarea dinamic˘ a unei clase ˆ memorie se refer˘ la faptul c˘ nu a a ın a a cunoastem tipul acesteia decˆt la executia preogramului. Tipul acestuia este ¸ java.Utilizat pentru ˆ arcarea claselor din direcınc˘ toarele extensiilor JRE.Acesta este responsabil cu ˆ arcarea claselor ınc˘ proprii aplicatiilor Java (cele din CLASSPATH). INCARCAREA CLASELOR ˆ MEMORIE IN 447 Implicit. Acesta este responsabil cu ˆ arcarea claselor din distributia Java standard (cele din ınc˘ ¸ pachetele java. cunoscute sub numele de: • Boostrap Class Loader .˘ 16. Acest lucru poate fi realizat prin mai multe modalit˘¸i.1.). fiecare obiect Class va retine class loader-ul care a ¸ fost folosit pentru ˆ arcare. Intrucˆt tipurile de date Java pot fi ˆ arcate folosind diverse instante a ınc˘ ¸ de tip ClassLoader.*. acesta putˆnd fi obtinut cu metoda getClassınc˘ a ¸ Loader. • Extension Class Loader . unul primordial ¸i dou˘ a s a proprii. • System Class Loader . specificˆnd numele s˘u complet prin intermediul ınc˘ a a unui ¸ir de caractere.lang. Java 2 JVM ofer˘ trei class loader-e.URLClassLoader.Class loader-ul primordial. moment ˆ care ¸ a ¸ ın putem solicita ˆ arcarea sa. javax. etc. s at cele mai comune metode fiind: .*.

forName("java. // echivalent cu ClassLoader loader = this.newInstance(). Dac˘ dorim s˘ instantiem un obiect dintr-o clas˘ ˆ arcat˘ dinamic putem a a ¸ a ınc˘ a folosi metoda newInstance. Folosirea interfetelor sau a claselor abstracte ˆ ¸ ımpreun˘ cu ˆ arcarea dia ınc˘ namic˘ a claselor ofer˘ un mecanism extrem de puternic de lucru ˆ Java. −1 ˆ caz contrar.getClassLoader().Button"). tot ce trebuie s˘ facem fiind s˘ scriem noi clase care aa a a extind Functie ¸i s˘ implement˘m metoda executa. a a ın ¸ a mai exist˘ ¸i alte posibilit˘¸i de a instantia astfel de obiecte. // Clasele standard pot fi si ele incarcate astfel Class t = Class. a a ın Vom detalia acest lucru prin intermediul unui exepmplu.Thread"). S˘ presupunem a c˘ dorim s˘ cre˘m o aplicatie care s˘ genereze aleator un vector de numere a a a ¸ a dup˘ care s˘ aplice o anumit˘ functie acestui vector. • Class.forName Aceast˘ metoda va ˆ arca respectiva clas˘ folosind class loader-ul a ınc˘ a obiectului curent (care o apeleaz˘): a Class c = Class. In felul acesta. Button b = (Button) c. Dup˘ cum vom vedea ˆ sectiunea urm˘toare. Aceasta va returna 0 s a a dac˘ metoda s-a executat corect. Numele functiei care a a a ¸ ¸ trebuie apelat˘ va fi introdus de la tastatur˘. iar implementarea ei va fi a a continut˘ ˆ ¸ a ıntr-o clas˘ a directorului curent. cu conditia s˘ existe constructorul f˘r˘ argu¸ a aa mente pentru clasa respectiv˘.lang.loadClass("ClasaNecunoscuta"). loader.getClass(). a ın .forName("NumeCompletClasa"). loader. as at ¸ Class c = Class.forName("java. Toate functiile vor extinde clasa a ¸ abstract˘ Functie.448 CAPITOLUL 16. LUCRUL DINAMIC CU CLASE • loadClass apelat˘ pentru un obiect de tip ClassLoader a ClassLoader loader = new MyClassLoader().loadClass("NumeCompletClasa"). aplicatia poate fi extins˘ cu noi functii a ¸ ¸ a ¸ f˘r˘ a schimba codul ei.awt.

readLine () . import java . executa () . err . print ( " \ nFunctie : " ) . while (! numeFunctie .*. // sau f . int v [] = new int [ n ]. err . try { // Incarcam clasa Class c = Class . v = v . err . // Cream un obiect de tip Functie Functie f = ( Functie ) c . io . println ( " Functia nu poate fi accesata ! " ) . .1. // Setam vectorul f . in ) ) . equals ( " gata " ) ) { System . } catch ( Cl as sNo tF oun d E x c e p t i o n e ) { System . println ( " \ nCod returnat : " + ret ) . forName ( numeFunctie ) . Random rand = new Random () . for ( int i =0. } catch ( Il le gal Ac ces s E x c e p t i o n e ) { System . util . String numeFunctie = " " . System . setVector ( v ) . } catch ( In st ant ia tio n E x c e p t i o n e ) { System . // Executam functia int ret = f . println ( " Functia nu poate fi instantiata ! "). newInstance () . println ( " Functie inexistenta ! " ) . i ++) v [ i ] = rand . out .*. out . // Citim numele unei functii BufferedReader stdin = new BufferedReader ( new InputStreamReader ( System . i < n .1: Exemplu de ˆ arcare dinamic˘ a claselor ınc˘ a import java . INCARCAREA CLASELOR ˆ MEMORIE IN Listing 16. nextInt (100) .˘ 16. public class TestFunctii { 449 public static void main ( String args []) throws IOException { // Generam un vector aleator int n = 10. numeFunctie = stdin .

length . for ( int i =1. print ( max ) . return 0. v = v .3: Un exemplu de functie ¸ import java . out . Arrays . for ( int i =0. } public abstract int executa () . int max = v [0]. public void setVector ( int [] v ) { this . . LUCRUL DINAMIC CU CLASE Listing 16. public class Sort extends Functie { public int executa () { if ( v == null ) return -1. i < v . i < v . return 0. } Listing 16.2: Clasa abstract˘ ce descrie functia a ¸ public abstract class Functie { public int v [] = null . i ++) if ( max < v [ i ]) max = v [ i ]. sort ( v ) . length . util . print ( v [ i ] + " " ) . System .450 } } } } CAPITOLUL 16. } } Listing 16. i ++) System .4: Alt exemplu de functie ¸ public class Max extends Functie { public int executa () { if ( v == null ) return -1.*. out .

aflat˘ ˆ pachetul demo ¸i dorim a a ın s s˘ o ˆ arc˘m dinamic ˆ memorie: a ınc˘ a ın // Obtinem class loaderul curent URLClassLoader urlLoader = (URLClassLoader) this. // Incarcam clasa urlLoader. iar cu addURL putem ad˘uga a o nou˘ adres˘ de c˘utare a claselor. Implicit. Crearea unui class a a ¸a ınc˘ loader propriu se face uzual prin extinderea clasei URLClassLoader.addURL(new File("c:\\clase"). In cazul ˆ care dorim s˘ avem posia a ın a bilitatea de a o reˆ arca. S˘ presupunem c˘ ˆ directorul s s a a ın c:\clase\demo exist˘ clasa cu numele Test. trebuie s˘ ınc˘ as a a folosim class-loadere proprii ¸i s˘ instantiem noi obiecte de tip ClassLoader. o variant˘ simplist˘ fiind prezentat˘ mai jos: a a a public class MyClassLoader extends URLClassLoader{ public MyClassLoader(URL[] urls){ super(urls). adresele URL pot specifica a a a ınt ¸i directoare ale sistemului de fi¸iere local.loadClass("demo.getClassLoader().toURL()). s a ¸ ori de cˆte ori dorim s˘ fort˘m reˆ arcarea claselor. la crearea class loader-ului aceast˘ a list˘ este completat˘ cu informatiile din variabila sistem CLASSPATH sau cu a a ¸ cele specificate prin optiunea -classpath la lansarea aplicatiei. Dup˘ ce o clas˘ a fost ˆ arcat˘ folosind un class loader. Folosind ¸ ¸ metoda getURLs putem afla aceste adrese.Test"). deoarece a fost modificat˘ ¸i recompilat˘. ea nu va mai a a ınc˘ a putea fi desc˘rcat˘ explicit din memorie.˘ 16.getClass(). INCARCAREA CLASELOR ˆ MEMORIE IN } } 451 Un obiect de tip URLClassLoader mentine o list˘ de adrese URL de unde ¸ a va ˆ ıncerca s˘ ˆ a ıncarce ˆ memorie clasa al c˘rei nume ˆ specific˘m ca arguın a ıl a ment al metodelor de mai sus. Bineˆ ¸eles. } } Inc˘rcarea claselor folosind clasa nou creat˘ se va face astfel: a a .1. // Adaugam directorul sub forma unui URL urlLoader.

// nu functioneaza ! // Cream alt class loader MyClassLoader myLoader = new MyClassLoader(urls). • Instantierea unor clase al c˘ror nume este ¸tiut abia la executie. // reincarca clasa 16. myLoader. ¸ a s ¸ • Setarea sau aflarea atributelor unui obiect. LUCRUL DINAMIC CU CLASE // La initializare URLClassLoader systemLoader = (URLClassLoader) this.loadClass("Clasa"). interfat˘ sau obiect ”reflect˘” la momentul a ¸a a executiei structura lor intern˘ se nume¸te reflectare (eng. s ¸ • Invocarea metodelor unui obiect al c˘ror nume este ¸tiut abia la executie. fiind ın ¸ cunoscut sub numele de Reflection API ¸i contine urm˘toarele clase: s ¸ a . acesta ¸ a s punˆnd la dispozitie metode pentru: a ¸ • Determinarea clasei unui obiect. myLoader.loadClass("Clasa"). a s ¸ • Crearea unor vectori a c˘ror dimensiune ¸i tip nu este ¸tiut decˆt la a s s a executie. .getClassLoader(). con¸ a structori.getURLs().2 Mecanismul reflect˘rii a Mecanismul prin care o clas˘. URL[] urls = systemLoader. superclasa.loadClass("Clasa"). chiar dac˘ numele acestora a este ¸tiut abia la executie. metode). • Aflarea unor informatii despre o clas˘ (modificatori.. ¸ Suportul pentru reflectare este inclus ˆ distributia standard Java. reflection).452 CAPITOLUL 16. // Dorim sa reincarcam clasa myLoader. // Cream class loaderul propriu MyClassLoader myLoader = new MyClassLoader(urls)..getClass().

class.Class • java.Se realizeaz˘ cu metoda getName: a Class clasa = obiect.class. MECANISMUL REFLECTARII • java. double. Class c = Class.2.lang.reflect ¸i anume: s – Array – Constructor – Field – Method – Modifier 453 16. etc.Object • Clasele din pachetul java. s ¸ a un obiect de acest tip putˆnd s˘ reprezinte atˆt o clas˘ cˆt ¸i o interfat˘.getName().lang.getClass(). String nume = clasa.getClass(). . Tipurile primitive sunt descrise ¸i ele de instante de tip Class avˆnd forma s ¸ a TipPrimitiv. a a a a a s ¸a diferentierea acestora f˘cˆndu-se prin intermediul metodei isInterface.class. diferentierea lor f˘cˆndu¸ a a se cu ajutorul metodei isPrimitive.class: int.2. Class c = java.lang.lang.Class.1 Examinarea claselor ¸i interfetelor s ¸ Examinarea claselor ¸i interfetelor se realizeaz˘ cu metode ale clasei java.˘ 16.awt. Aflarea numelui unei clase ..forName("NumeClasa"). ¸ a a Reflection API pune la dispozitie metode pentru obtinerea urm˘toarelor ¸ ¸ a informatii: ¸ Aflarea instantei Class corespunz˘tor unui anumit obiect sau tip de ¸ a date: Class c = obiect.Button.

class.out. if (Modifier.out.getName(). if (Modifier.getSuperclass(). System. String modif = "".Se realizeaz˘ cu metoda getSuperclass ce rea turneaz˘ o instant˘ de tip Class. // null Aflarea interfetelor implementate de o clas˘ sau extinse de o interfat˘ ¸ a ¸a . System.println(s). isAbstract ¸i isFinal: s Class clasa = obiect. .Se realizeaz˘ cu metoda getModifiers.length.getName()). for (int i = 0.awt.Window Class c = java.Frame. ce returneaz˘ un vector de tip a a Class[]. // java.println(modif + "class" + c. a aceasta returnˆnd un num˘r ˆ a a ıntreg ce codific˘ toti modificatorii clasei.Object.isAbstract(m)) modif += "abstract ".getClass(). Class c = java. Aflarea superclasei . if (Modifier.awt. System. public void interfete(Class c) { Class[] interf = c.out. Pena ¸ tru a determina u¸or prezenta unui anumit modificator se folosesc metodele s ¸ statice ale clasei Modifier isPublic. i++) { String nume = interf[i].awt.class.isPublic(m)) modif += "public ".454 CAPITOLUL 16. LUCRUL DINAMIC CU CLASE Aflarea modificatorilor unei clase . i < interf. Class s = c. Class s = c.getInterfaces(). int m = clasa.print(nume + " ").getModifiers().Se realizeaz˘ cu metoda getInterfaces. corespunz˘toare tipului de date al supera ¸a a clasei sau null pentru clasa Object.isFinal(m)) modif += "final ".getSuperclass().

class). getParameterTypes. ˆ timp ce a doua le returnez˘ doar s ın a pe cele declarate ˆ cadrul clasei. Serializable. getReturnType pentru a obtine toate informatiile legate ¸ ¸ . Collection. Cu ajutorul metodei getField este posibil˘ obtinerea unei referinte la o a ¸ ¸ variabil˘ mebr˘ cu un anumit nume specificat. Cu ajutorul metodei getConstructor este posibil˘ obtinerea unei referinte a ¸ ¸ la constructor cu o signatur˘ specificat˘.Se realizeaz˘ cu metodele getConstructors a sau getDeclaredConstructors.Set).˘ 16. ce returnez˘ un vector de tip Field[]. a Clasa Constructor pune la dispozitie metodele getName.Se realizeaz˘ cu una din metodele a getFields sau getDeclaredFields.util..util.2. getParameterTypes. interfete(java. getModifiers.HashSet.. // Va afisa interfetele implementate de HashSet: // Cloneable. clasa Field pune la dispozitie ın a ¸ metodele getName. inclusiv cele mo¸tenite. a a Aflarea constructorilor . a diferenta ˆ ¸ ıntre cele dou˘ constˆnd ˆ faptul c˘ prima returneaz˘ toate varia a ın a a abilele membre. ¸ getExceptionTypes. getExceptionTypes pentru a obtine toate informatiile legate ¸ ¸ de respectivul constructor. Set 455 interfete(java. Clasa Method a pune la dispozitie metodele getName. getType ¸i getModifiers pentru a obtine numele. ¸ getModifiers. tipul. ce returneaz˘ un vector de tip Constructor[]. a a Aflarea metodelor . La rˆndul ei. MECANISMUL REFLECTARII } } . // Va afisa interfetele extinse de Set: // Collection Aflarea variabilelor membre . s ¸ respectiv modificatorii unei variabile membru. ce returneaz˘ un vector de tip Method[].Se realizeaz˘ cu metodele getMethods sau a getDeclaredMethods.

2. In schimb. Dac˘ nu exist˘ un astfel de constructor sau nu este a a accesibil vor fi generate exceptii de tipul InstantiationException. Class c = Class. a 16. LUCRUL DINAMIC CU CLASE de respectiva metod˘. ce returnez˘ un vector de tip Class[].Se realizeaz˘ cu metoda getDeclaringClass.2 Manipularea obiectelor Pe lˆng˘ posibilitatea de a examina structura unei anumite clase la momentul a a executiei. folosind Reflection API avem posibilitatea de a lucra dinamic cu ¸ obiecte.Se realizeaz˘ cu metodele getClasses sau a getDeclaredClasses. // Daca stim tipul obiectului .newInstance(). re¸ spectiv IllegalAccessException.lang. a a a Aflarea claselor imbricate . bazˆndu-ne pe informatii pe care le obtinem abia la executie. a Cu ajutorul metodei getMethod este posibil˘ obtinerea unei referinte la a ¸ ¸ o metod˘ cu o signatur˘ specificat˘. Method. In cazul ˆ care ¸ ın numele clasei nu este cunoscut decˆt la momentul executiei nu mai putem a ¸ folosi aceast˘ metod˘ de instantiere. avem la dispozitie alte dou˘ a a ¸ ¸ a variante: • Metoda newInstance din clasa java. constructorul sau metoda a a ıi ¸ respectiv˘.forName("NumeClasa"). a Aceast˘ metod˘ o reg˘sim ¸i ˆ clasele Field. Object o = c. crearea obiectelor se realizeaz˘ cu operatorul new urmat de a ¸ a un apel la un constructor al clasei pe care o instantiem. Constructor.456 CAPITOLUL 16. pentru a a a s ın acestea returnˆnd clasa c˘rei ˆ apartine variabila. a Aflarea clasei de acoperire .Class Aceasta permite instantierea unui obiect folosind constructorul f˘r˘ ar¸ aa gumente al acestuia. a ¸ ¸ ¸ Crearea obiectelor Dup˘ cum stim.

class. apoi specificarea argumentelor la apelarea sa.class. int. cel pentru care se face apelul. Evident. Constructor ctor = clasa. Point p = (Point) c. // Instantiem Point p = (Point) ctor. // Obtinem constructorul dorit Class[] signatura = new Class[] {int. aceast˘ solutie presupune a ¸ ˆ primul rˆnd obtinerea unui obiect de tip Constructor cu o anumit˘ ın a ¸ a signatur˘. Class clasa = java. Invocarea metodelor Invocarea unei metode al c˘rei nume ˆ cunoa¸tem abia la momentul executiei a ıl s ¸ se realizeaz˘ cu metoda invoke a clasei Method. IllegalArgumentException ¸i s InvocationTargetException. Object[] arg = new Object[] {x. trebuie s˘ obtinem ˆ ai o referint˘ la metoda cu signatura corea ¸ ıntˆ ¸a spunz˘toare ¸i apoi s˘ specific˘m argumentele. MECANISMUL REFLECTARII Class c = java. Exceptii generate de metoda newInstance sunt: InstantiationException.˘ 16. S˘ presupunem c˘ dorim s˘ apel˘m metoda contains a a a a a . In plus. // Pregatim argumentele // Ele trebuie sa fie de tipul referinta corespunzator Integer x = new Integer(10). ¸ IllegalAccessException.2. Integer y = new Integer(20).Point.getConstructor(signatura). Metoda getConstructor poate provoca exceptii ¸ de tipul NoSuchMethodException. mai putem obtine a s a a ¸ valoarea returnat˘.awt.class. S˘ rescriem a a exemplul de mai sus. apelˆnd constructorul cu dou˘ argumente al clasei a a Point.Point. Ca ¸i ˆ cazul construca s ın torilor.awt.newInstance().newInstance(arg). 457 • Metoda newInstance din clasa Constructor Aceasta permite instantierea unui obiect folosind un anumit construc¸ tor.class}. y}.

// Obtinem metoda dorita Class[] signatura = new Class[] {Point. noi o vom apela pe cea care accept˘ un argument de tip Point.awt. 100). 20).Rectangle. y. . Object[] arg = new Object[] {p}.class}. Point obiect = new Point(0. Setarea ¸i aflarea variabilelor membre s Pentur setarea ¸i aflarea valorilor variabilelor membre sunt folosite metodele s set ¸i get ale clasei Field. respectiv parametri ın a de apelare ai metodei. x = clasa. 0. Metoda getMethod poate provoca exceptii s ¸ de tipul NoSuchMethodException.invoke(obiect. S˘ presupunem c˘ dorim s˘ set˘m variabila x a s a a a a unui obiect de tip Point ¸i s˘ obtinem valoarea variabilei y a aceluia¸i obiect: s a ¸ s Class clasa = java. // Apelam metoda metoda. Rectangle obiect = new Rectangle(0. 100.getField("x"). arg). atunci putem folosi vala a oarea null ˆ locul vectorilor ce reprezint˘ signatura.Point.458 CAPITOLUL 16.awt. Metoda contains are mai multe variante. Method metoda = clasa. y = clasa. Exceptiile generate de metoda invoke sunt: IllegalAccessException ¸ ¸i InvocationTargetException.class. signatura). 20).class. Dac˘ num˘rul argumentelor metodei este 0. LUCRUL DINAMIC CU CLASE a clasei Rectangle care determin˘ dac˘ un anumit punct se g˘se¸te ˆ intea a a s ın riorul drepunghiului.getMethod("contains".getField("y"). // Obtinem variabilele membre Field x. // Pregatim argumentele Point p = new Point(10. a Class clasa = java.

*. s˘ presupunem c˘ exist˘ deja un num˘r ˆ ¸ a a a a ınsemnat de clase care descriu diferite functii dar acestea nu extind clasa abstract˘ ¸ a Functie. import java . solutia anterioar˘ nu mai este viabil˘ ¸i trebuie ¸ a as s˘ folosim apelarea metodei executa ˆ a ıntr-un mod dinamic. i < n .2. lang . Random rand = new Random () . 459 Exceptiile generate de metodele get. Revenind la exemplul din sectiunea anterioar˘ cu apelarea dinamic˘ a ¸ a a unor functii pentru un vector. public class TestFunctii2 { public static void main ( String args []) throws IOException { // Generam un vector aleator int n = 10.5: Lucru dinamic cu metode ¸i variabile s import java . nextInt (100) . numeFunctie = stdin . while (! numeFunctie . for ( int i =0. // Citim numele unei functii BufferedReader stdin = new BufferedReader ( new InputStreamReader ( System .*. io .*. Din acest motiv. Listing 16. equals ( " gata " ) ) { System .get(obiect). Metoda getField poate provoca exceptii de s ¸ tipul NoSuchFieldException. .˘ 16. int v [] = new int [ n ]. readLine () . String numeFunctie = " " . print ( " \ nFunctie : " ) . import java . MECANISMUL REFLECTARII // Setam valoarea lui x x. reflect . // Obtinem valoarea lui y Integer val = y. in ) ) . util .set(obiect. new Integer(10)). set sunt: IllegalAccessException ¸ ¸i IllegalArgumentException. i ++) v [ i ] = rand . out .

newInstance () . forName ( numeFunctie ) .getComponentType()). invoke (f . System .getClass(). v ) . ¸ diferentierea f˘cˆndu-se prin intermediul metodei isArray.out. Aceasta contine o serie de metode statice ce permit: ¸ • Crearea de noi vectori: newInstance • Aflarea num˘rului de elemente: getLength a . null ) . // Cream un obiect de tip Functie Object f = c .println(c.2.Class. println ( " Eroare la apelarea functiei ! " ) . getMethod ( " executa " . } catch ( Exception e ) { System .Point Lucrul dinamic cu obiecte ce reprezint˘ vectori se realizeaz˘ prin intera a mediul clasei Array. out . Class c = vector.lang.awt. // Apelam metoda ’ executa ’ // Folosim null pentru ca nu avem argumente Method m = c . // Setam vectorul ( setam direct variabila v ) Field vector = c . LUCRUL DINAMIC CU CLASE try { // Incarcam clasa Class c = Class . set (f . Integer ret = ( Integer ) m . println ( " \ nCod returnat : " + ret ) . getField ( " v " ) . ce ˆ ıntoarce o referint˘ de tip Class. // Va afisa: class java. ¸ a a Tipul de date al elementelor din care este format vectorul va fi obtinut cu ¸ ajutorul metodei getComponentType. ¸a Point []vector = new Point[10]. null ) . err .3 Lucrul dinamic cu vectori Vectorii sunt reprezentati ca tip de date tot prin intermediul clasei java.460 CAPITOLUL 16. System. vector . } } } } 16.

new Integer(i)).print(Array. MECANISMUL REFLECTARII • Setarea / aflarea elementelor: set.2.getLength(a). get 461 Exemplul de mai jos creeaz˘ un vector ce contine numerele ˆ a ¸ ıntregi de la 0 la 9: Object a = Array.get(a. i.class. for (int i=0.newInstance(int. 10). .˘ 16.getLength(a). i < Array. i++) System. i++) Array.out.set(a. i) + " "). i < Array. for (int i=0.

Sign up to vote on this title
UsefulNot useful