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 ¸

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

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

10 CUPRINS .

Capitolul 1 Introducere ˆ Java ın 1.1 Limbajul de programare Java Inainte de a prezenta ˆ detaliu aspectele tehnice ale limbajului Java. impunˆndu-se prin calit˘¸i deosebite cum ar fi sima at plitate.1. ¸ • Simplitate . ¸ ¸ ¸a a • Robustete . fire de executie. robustete ¸i nu ˆ ultimul rˆnd portabilitate. s at • U¸urint˘ ˆ crearea de aplicatii complexe ce folosesc programarea ˆ s ¸a ın ¸ ın retea. administrarea automat˘ a memoriei ¸i elim¸ a s 11 . 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. ¸ 1.elimin˘ sursele frecvente de erori ce apar ˆ programare ¸ a ın prin renuntarea la pointeri.elimin˘ supraˆ arcarea operatorilor.1 Ce este Java ? Java este o tehnologie inovatoare lansat˘ de compania Sun Microsystems ˆ a ın 1995. mo¸tenirea multipl˘ a ınc˘ s a ¸i toate ”facilit˘¸ile” ce pot provoca scrierea unui cod confuz. indiferent de domeniu sau de complexitatea lor. baze de date. interfat˘ grafic˘. care a avut un impact remarcabil asupra ˆ ıntregii comunit˘¸i a dezat voltatorilor de software. etc. Denumit˘ initial OAK. ¸ 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. s˘ amın a intim caracteristicile sale principale.

Aceste tehnologii a au fost grupate ˆ a¸a numitele platforme de lucru. ¸ a a ¸ • Este modelat dup˘ C ¸i C++. etc. Linux. ce reprezint˘ seturi de ın s a libr˘rii scrise ˆ limbajul Java. furnizˆnd a mecanisme stricte de securitate a programelor concretizate prin: verificarea dinamic˘ a codului pentru detectarea secventelor periculoase. ¸ • Este compilat ¸i interpretat.este un limbaj de programare foarte sigur.1. etc.de¸i mai lent decˆt limbajele de programare care genereaz˘ ¸a s a a executabile native pentru o anumit˘ platform˘ de lucru. inclusiv grafic˘ 3D. Mac OS. lucru care aduce economii substantiale firmelor ¸ dezvoltatoare de aplicatii. etc.elimin˘ complet stilul de programare a procedural. trecerea de la C. ce ruleaz˘ ˆ fundal (”garbage collector”). precum ¸i diverse programe utilitare. a a s 1. a ın • Complet orientat pe obiecte . 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. .comportamentul unei aplicatii Java nu a ¸ depinde de arhitectura fizic˘ a ma¸inii pe care ruleaz˘.Java este un limbaj independent de platforma de lucru. compilatorul a a Java asigur˘ o performant˘ ridicat˘ a codului de octeti. folosite a ın s pentru dezvoltarea de aplicatii sau componente destinate unei anume cate¸ gorii de utilizatori. animatie. C++ la Java a s f˘cˆndu-se foarte u¸or. INTRODUCERE ˆ JAVA IN inarea pierderilor de memorie printr-o procedur˘ de colectare a obiectelor a care nu mai sunt referite. Solaris. ¸a • Neutralitate arhitectural˘ . aceasta fiind solutia eficient˘ pentru s ¸ a obtinerea portabilit˘¸ii. a s a • Portabililtate .12 CAPITOLUL 1. 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. • Securitate .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. ¸ at • Performant˘ . a ¸ impunerea unor reguli stricte pentru rularea proceselor la distant˘.

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

a Limbajul Java combin˘ solutiile amintite mai sus.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. 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. ¸ s ¸ Codul de octeti este diferit de codul ma¸in˘. 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. pe acesta trebuie s˘ fie instalat˘ o ma¸in˘ virtual˘ Java.println("Hello world!"). a a s a a Acest lucru este realizat automat de c˘tre distributia J2SDK. 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. Pentru ca un cod de octeti s˘ poat˘ fi executat pe un ¸ ¸ a a anumit calculator. a ¸ 1. programele Java fiind a ¸ atˆt interpretate cˆt ¸i compilate. } } . a ¸ Prin ma¸ina virtual˘ Java (JVM) vom ˆ ¸elege mediul de executie al s a ınt ¸ aplicatiilor Java. Avantajul este executia extrem de rapid˘. Scriererea codului surs˘ a class FirstApp { public static void main( String args[]) { System.out. 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. 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.2 Primul program Crearea oric˘rei aplicatii Java presupune efectuarea urm˘torilor pa¸i: a ¸ a s 1. INTRODUCERE ˆ JAVA IN ma¸in˘. dezavantajul fiind s a ¸ a lipsa portabilit˘¸ii.

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

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

se reprezint˘ pe 8 octeti (64 biti) ¸i se termin˘ cu caracterul a ¸ ¸ s a L (sau l). Dup˘ a a a cum am mai spus. .˘ 1. ˆ ¸ s ıncepˆnd cu o liter˘. identificatorii nu au voie s˘ fie identici cu cuvintele rezera vate.5. 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. null nu sunt cuvinte cheie. dar nu sunt folosite. baza 16 (ˆ ¸ ıncep cu caracterele 0x) ¸i baza 8 (ˆ s ıncep cu cifra 0) ¸i pot fi de dou˘ tipuri: s a – normali .3. Cuvintele marcate prin ∗ ın ¸ sunt rezervate. mai exist˘ ¸i cuvˆntul cheie enum. a as a 1.4 Literali Literalii pot fi de urm˘toarele tipuri: a • Intregi Sunt acceptate 3 baze de numeratie : baza 10. 1. true.3. false.3 Identificatori Sunt secvente nelimitate de litere ¸i cifre Unicode. ¸ dar nu pot fi nici ele folosite ca nume ˆ aplicatii. variabile sau metode.3.se reprezint˘ pe 4 octeti (32 biti) a ¸ ¸ – lungi . STRUCTURA LEXICALA A LIMBAJULUI JAVA 17 interfete.

0. a Atentie ¸ Spre deosebire de C++. s˘ fie ˆ notatie exponential˘ sau s˘ aib˘ sufixul a a a a ın ¸ ¸ a a a F sau f pentru valorile normale . 3f. respectiv fals.18 CAPITOLUL 1. respectiv false ¸ a a . ¸ Exemple: 1. 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˘. literalii ˆ ıntregi 1 ¸i 0 nu mai au semnificatia s ¸ de adev˘rat. 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 . etc.reprezentate pe 32 biti. 2e2.reprezentate pe 64 biti.valoarea logic˘ de fals. 4D. • Logici Sunt reprezentati de true . apostrof. respectiv D ¸ sau d pentru valorile duble . fie o secvent˘ a ¸a escape scris˘ ˆ a ıntre apostrofuri.valoarea logic˘ de adev˘r. a • Caracter Un literal de tip caracter este utilizat pentru a exprima caracterele codului Unicode. Reprezentarea se face fie folosind o liter˘. Secventele escape permit specificarea ¸ caracterelor care nu au reprezentare grafic˘ ¸i reprezentarea unor caras actere speciale precum backslash.

ca ˆ exemplul: "Ana " + " are " + " mere ". a s ¸a definit˘ ˆ pachetul java. ~ (not) ¸ • operatori de translatie: <<. -.6 Operatori Operatorii Java sunt. /. . ++x. ¸ a s a 1. != ¸ • operatori pe biti: &(and). -. ==.3. >>> (shift la dreapta f˘r˘ semn) ¸ a a . >. <=. ¸ Dac˘ ¸irul este prea lung el poate fi scris ca o concatenare de sub¸iruri as s de dimensiune mai mic˘.5 Separatori Un separator este un caracter care indic˘ sfˆr¸itul unei unit˘¸i lexicale ¸i a as at s ınceputul alteia.3.lang. !(not) • operatori relationali: <. . a • operatori logici: &&(and). *. ++.3. . ||(or). Instructiunile unui program se separ˘ cu punct ¸i virgul˘. orice ¸ir este de fapt o instant˘ a clasei String. concatenarea ¸irurilor realizˆndu-se cu opera s a atorul +. Dup˘ cum vom vedea. >>. 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. a ın 1. --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˘. %.˘ 1. Caracterele care formeaz˘ ¸irul pot fi caractere grafice as sau secvente escape. cei din C++: • atribuirea: = • operatori matematici: +. 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++. ^ (xor). <=. Sirul vid ın este "". n--. cu mici deosebiri. |(or).. In Java separatorii sunt urm˘torii: ( ) a [ ] .

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

4 1. 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. Java porne¸te de la premiza c˘ ”orice este un obiect”. struct ¸i union. clasele ¸i interfetele sunt tipuri referint˘. mai a ıns˘ ¸ a exist˘ ¸i a¸a numitele tipurile primitive de date. care sunt cele uzuale : as s • aritmetice –ˆ ıntregi: byte (1 octet). long (8) – reale: float (4 octeti). short (2). orice dependent˘ de o anumit˘ platform˘ specific˘ fiind ¸a a a a eliminat˘. In a ¸ principiu acest lucru este adev˘rat. TIPURI DE DATE SI VARIABILE ¸ 21 1. int (4). Valoarea unei variabile s ¸ ¸a de acest tip este. ın . In Java acest lucru a nu mai este valabil. Acestea sunt: pointer. ¸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). a Vectorii.4.1. pentru usurinta program˘rii. Pointerii au fost s eliminati din cauz˘ c˘ erau o surs˘ constant˘ de erori. ˆ a. 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. locul lor fiind luat de ¸ a a a a tipul referint˘.4.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˘. spre deosebire de tipurile primitive. a Exist˘ trei tipuri de date din limbajul C care nu sunt suportate de lima bajul Java. o referint˘ (adres˘ de ¸a a memorie) c˘tre valoarea sau multimea de valori reprezentat˘ de variabila a ¸ a respectiv˘.

atunci a ¸ primele litere ale celorlalti atomi se scriu cu majuscule. Evident. 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]. INTRODUCERE ˆ JAVA IN 1. ¸ Exemple: final double PI = 3. final int MINIM=0. urm˘toarele ¸ ın a criterii: • variabilele finale (constante) se scriu cu majuscule. variabila2[=valoare2]. • variabilele care nu sunt constante se scriu astfel: prima liter˘ mic˘ iar a a dac˘ numele variabilei este format din mai multi atomi lexicali. Conventia de numire a variabilelor ˆ Java include. c2=’a’. pentru a putea fi folosite variabilele trebuie declarate ¸i.. printre altele. s eventual. c3=’v’. • Initializarea variabilelor: Tip numeVariabila = valoare. MAXIM = 10. char c1=’j’.14. c4=’a’. int valoare = 100. 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”). long numarElemente = 12345678L. Variabile membre.22 CAPITOLUL 1. ... ¸ • Declararea variabilelor: Tip numeVariabila. In¸ ¸a diferent de tipul lor. declarate ˆ interiorul unei clase.. ¸ • Declararea constantelor: final Tip numeVariabila. In functie de locul ˆ care sunt declarate variabilele se ˆ ¸ ın ımpart ˆ urm˘toatele ın a categorii: a. initializate.2 Variabile Variabilele pot fi de tip primitiv sau referinte la obiecte (tip referint˘). String bauturaMeaPreferata = "apa".4.

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

switch-case ¸ • Instructiuni de salt: for. { int x=2. } else { . label: ¸ 1. continue.24 CAPITOLUL 1. } switch-case switch (variabila) { case valoare1: .. throw ¸ ¸ • Alte instructiuni: break.... INTRODUCERE ˆ JAVA IN int x=1. while.. do-while ¸ • Instructiuni pentru tratarea exceptiilor: try-catch-finally... return.1 if-else Instructiuni de decizie ¸ if (expresie-logica) { .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.5. break. //incorect } 1. } if (expresie-logica) { .. case valoare2: .

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

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

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

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

Dup˘ cum vom vedea. folosind un algoritm de tip Quicka Sort performant.util. a. // Sorteaza vectorul v // Acesta va deveni {1. // Varianta 1 for(int i=0. // Varianta 2 System. VECTORI 29 1.5 Sortarea vectorilor . fie cu ajutorul metodei System.1. ca ˆ exemın plele de mai jos. 2}.util. 3. 1.sort(v).sorteaz˘ ascendent un vector. 4}. 4} • binarySearch . 2. fie element cu element.6. a Clasa java. 3. 4.Arrays ofer˘ diverse metode foarte utile ˆ lucrul cu veca ın tori cum ar fi: • sort . 2. int v[]={3. int a[] = {1.6.length). programs a atorul trebuind s˘ se concentreze pe aspectele specifice problemei abordate.length.arraycopy. i++) b[i] = a[i].4 Copierea vectorilor Copierea elementelor unui vector a ˆ ıntr-un alt vector b se poate face. java. de complexitate O(n log(n)). 0. i<a.Arrays.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. // Nu are efectul dorit b = a. 0.6.c˘utarea binar˘ a unei anumite valori ˆ a a ıntr-un vector sortat. b.arraycopy(a. int b[] = new int[4]. . 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. 1.

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. reverse.6. s ¸ ın ¸ 1. un ¸ir de caractere poate fi reprezentat printr-un vector format s din elemente de tip char. 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.de altfel. 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.atribuie fiec˘rui element din vector o valoare specificat˘. cea mai folosit˘ modalitate de a lucra cu ¸iruri este prin intermediul a s clasei String.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 .30 CAPITOLUL 1. String s = new String(data). Observati prima variant˘ de declarare a ¸irului s din exemplul de mai sus ¸ a s . ’b’. ale c˘ror elemente au tipul Object. 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”. ¸ ¸ . un obiect de tip String sau un obiect de tip StringBuffer. a ¸ altfel va fi declarat de tip StringBuffer. cea mai folosit˘ . a a 1. String s = new String("abc"). delete. Astfel de obiecte descriu vectori eterogeni. ¸ s Uzual. Clasa StringBuffer a s va fi utilizat˘ predominant ˆ aplicatii dedicate proces˘rii textelor cum ar fi a ın ¸ a editoarele de texte.care prezint˘ o particularitate a clasei String a a fata de restul claselor Java referitoare la instantierea obiectelor sale. ’c’}. Exemple echivalente de declarare a unui ¸ir: s String s = "abc". cum ar fi: append. char data[] = {’a’.7 Siruri de caractere ¸ In Java. INTRODUCERE ˆ JAVA IN • equals .util. insert.

ˆ sensul c˘ ın a permite concatenarea ¸irurilor cu obiecte de orice tip care au o reprezentare s de tip ¸ir de caractere. Mai jos.length + " elemente").append("a"). append("b").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. cum ar fi Mac OS. In Java.˘ 1. cel de concatenare a ¸irurilor. FOLOSIREA ARGUMENTELOR DE LA LINIA DE COMANDA 31 Concatenarea ¸irurilor de caractere se face prin intermediul operatorului s + sau. ¸ Atentie ¸ Programele care folosesc argumente de la linia de comand˘ nu sunt 100% a pure Java.append(1). 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. deoarece unele sisteme de operare. Sirul s=1+2+"a"+1+2 ¸ ıns˘ ¸ ¸ va avea valoarea "3a12". nu au ˆ ın mod normal linie de comand˘.8.8 1. sunt cˆteva exemple: s a System. a . operatorul de concatenare + este extrem de flexibil. String s2 = "123". primul + fiind operatorul matematic de adunare iar al doilea +.out. folosind metoda append.print("Vectorul v are" + v. s 1. ˆ cazul ¸irurilor de tip StringBuffer.toString() Atentie ˆ a la ordinea de efectuare a operatiilor. String s3 = s1 + s2. 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().8. String x = "a" + 1 + "b" Pentru a l˘muri putin lucrurile. ın s String s1 = "abc" + "xyz".

txt". .8. A¸adar. argumentele trebuie separate prin spatii ın ¸ iar dac˘ unul dintre argumente contine spatii. Acesta este primit s de aplicatie ca parametru al metodei main. . 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: . a In cazul apelului java Sortare persoane.2 Primirea argumentelor In momentul lans˘rii unei aplicatii interpretorul parcurge linia de comand˘ cu a ¸ a care a fost lansat˘ aplicattia ¸i. Pentru a ordona fi¸ierul "persoane. argn] In cazul ˆ care sunt mai multe. Evident. formatul general pentru lansarea unei aplicatii care prime¸te argus ¸ s mente de la linia de comand˘ este: a java NumeAplicatie [arg0 arg1 . De exemplu. atunci el trebuie pus ˆ a ¸ ¸ ıntre ghilimele. INTRODUCERE ˆ JAVA IN Argumentele de la linia de comand˘ sunt introduse la lansarea unei aplicatii.32 CAPITOLUL 1. transmite programului a ¸ s ın ın a argumentele specificate sub forma unui vector de ¸iruri. ˆ cazul ˆ care exist˘. 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˘. aplicatia va fi lansat˘ ıl s ¸ a astfel: java Sortare persoane.txt vectorul args va contine un ¸ singur element pe prima s˘ pozitie: args[0]="persoane. o aplicatie poate s˘ nu primeasc˘ nici un argument sau ¸ a a poate s˘ ignore argumentele primite de la linia de comand˘. a ¸ fiind specificate dup˘ numele aplicatiei ¸i separate prin spatiu. 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˘. a a 1. 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".txt A¸adar.

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

S˘ consider˘m.out. Tratarea acestor exceptii este prezentat˘ ˆ ¸ a ın capitolul ”Exceptii”.3 Argumente numerice Argumentele de la linia de comand˘ sunt primite sub forma unui vector de a ¸iruri (obiecte de tip String).34 } } CAPITOLUL 1. } } 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.parseInt(args[1]).8. Double. In cazul ˆ care unele dintre acestea reprezint˘ s ın a valori numerice ele vor trebui convertite din ¸iruri ˆ numere. Acest lucru s ın se realizeaz˘ cu metode de tipul parseTipNumeric aflate ˆ clasa corespuna ın zatoare tipului ˆ care vrem s˘ facem conversia: Integer. int putere = Integer. Float.5" "2" //ridica 1.parseDouble(args[0]). 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.println("Rezultat=" + Math. System. putere)).pow(numar. ın a etc. de exemplu. ¸ . argumentele fiind trimise de la linia de comand˘ sub forma: a a java Power "1. c˘ aplicatia Power ridic˘ un numar real la o a a a ¸ a putere ˆ ıntreag˘.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.

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

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

lipseste instantierea 2. height.x = 10. 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. schimbarea st˘rii sale sau executarea unor actiuni. Alocarea memoriei se face doar la apelul operatorului new.variabila De exemplu clasa Rectangle are variabilele publice x. 0. //Eroare . Referirea valorii unei variabile se face prin obiect. //schimba originea Accesul la variabilele unui obiect se face ˆ conformitate cu drepturile de ın acces pe care le ofer˘ variabilele respective celorlalte clase. y.setSize(200.2 Folosirea obiectelor Odat˘ un obiect creat. (vezi ”Modificaa tori de acces pentru membrii unei clase”) Apelul unei metode se face prin obiect. 100. System.setLocation(10. 300). patrat.println(patrat. //schimba originea patrat.x = 10. respectiv prin apelarea metodelor sale.1. 200). Rectangle 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).metoda([parametri]). In schimb. patrat.origin = new Point(10. 200).2. //schimba originea patrat. width. pentru fiecare variabil˘ care descrie starea a . 100. origin. patrat. Rectangle patrat = new Rectangle(0. //afiseaza 100 patrat.out. el poate fi folosit ˆ urm˘toarele sensuri: aflarea unor a ın a informatii despre obiect.y = 20. Aflarea valorilor acestor variabile sau schimbarea lor se face prin constructii ¸ de genul: Rectangle patrat = new Rectangle(0. 0. ¸ a ¸ Aceste lucruri se realizeaza prin aflarea sau schimbarea valorilor variabilelor sale. //schimba dimensiunea Se observ˘ c˘ valorile variabilelor pot fi modificate indirect prin intera a mediul metodelor sale. 20).width). 20).1.

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

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

toate clasele din directorul curent sunt considerate a fi ˆ acela¸i ın s pachet). 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. – programare ˆn spririt orientat-obiect: O clasa ”perfect˘” nu treı a buie s˘ mai aib˘ subclase. ın . O clas˘ declarat˘ cu public poate fi folosit˘ din orice alt˘ a a a a clas˘.40 CAPITOLUL 2. Java permite doar mo¸tenirea simpl˘.2 Extinderea claselor Spre deosebire de alte limbaje de programare orientate-obiect. (vezi ”Clase ¸i metode abstracte”) s • final Declar˘ c˘ respectiva clas˘ nu poate avea subclase. de unde rezult˘ c˘ multimea tuturor claselor definite ˆ Java poate fi a a ¸ ın vazut˘ ca un arbore. a ın a s • abstract Declar˘ o clas˘ abstract˘ (¸ablon). r˘d˘cina acestuia fiind clasa Object. ceea ce ˆ s a ıneamn˘ c˘ o clas˘ poate avea un singur a a a p˘rinte (superclas˘). dar tipul exact al unui s obiect nu poate fi aflat cu exactitate decat ˆ momentul executiei. dac˘ este cazul. 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. indiferent de pachetul ˆ care se g˘se¸te. 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. ale c˘ror nume trebuie separate a ¸ a prin virgul˘. OBIECTE SI CLASE ¸ • public Implicit. a 2.2. O clas˘ abstract˘ nu poate fi a a a s a a instantiat˘. fiind foarte important˘ ˆ modul de a a a ın lucru cu obiecte si structuri de date ˆ Java. fiind folosit˘ doar pentru a crea un model comun pentru o ¸ a a serie de subclase. A¸adar. Evident. 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. o clas˘ poate avea oricˆti mo¸tenitori (suba a a a s clase). Object a a a s este singura clas˘ care nu are p˘rinte.

initializarea variabilelor de instant˘ ¸i de clas˘ s ¸ ¸a s a (cunoscute ˆ ımpreun˘ ca variabile membre). a • Declararea unor clase imbricate (interne). Continutul acestuia este format din: ¸ • Declararea ¸i.. s • Declararea ¸i implementarea metodelor de instanta ¸i de clas˘ (cunoss ¸ s a cute ˆ ımpreun˘ ca metode membre). Implementarea a a a ın metodelor unei clase trebuie s˘ se fac˘ obligatoriu ˆ corpul clasei. int metoda2() { // Implementare } } A::metoda1() { // Implementare } .2. eventual.. a • Declararea ¸i implementarea constructorilor.3 Corpul unei clase Corpul unei clase urmeaz˘ imediat dup˘ declararea clasei ¸i este cuprins ˆ a a s ıntre acolade.2. a a ın // C++ class A { void metoda1(). nu este permis˘ doar declararea metodei ˆ corpul a ın clasei. CREAREA CLASELOR Extinderea unei clase se realizeaz˘ folosind cuvˆntul cheie extends: a a class B extends A {.} // 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. urmˆnd ca implementare s˘ fie facut˘ ˆ afara ei.2. Spre deosebire de C++. 2.

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

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

d). double y1.out. double w1. derivat˘ din clasa Dreptunghi: a a a a a class Patrat extends Dreptunghi { Patrat(double x. Dreptunghi(double x1. h=h1. w=w1. // 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. // Apelam constructorul cu 2 argumente } } Dintr-o subclas˘ putem apela explicit constructorii superclasei cu expresia a super( argumente ). y. y=y1. h. w1. S˘ presupunem c˘ dorim s˘ cre˘m clasa Patrat. d. 0). double h1) { // Implementam doar constructorul cel mai general x=x1. // Apelam constructorul cu 4 argumente } Dreptunghi() { this(0. y. a ¸ . h1). double d) { super(x.println("Instantiere dreptunghi"). OBIECTE SI CLASE ¸ a repeta acelea¸i secvente de cod ˆ toti constructorii (cum ar fi afi¸area s ¸ ın ¸ s mesajului ”Instantiere dreptunghi”). clasa de mai sus poate fi rescris˘ astfel: a class Dreptunghi { double x. double h1) { this(0. double y. System. } Dreptunghi(double w1.44 CAPITOLUL 2. w. 0.

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

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

o variabil˘ se declar˘ astfel: a a [modificatori] Tip numeVariabila [ = valoareInitiala ]. public String s = "abcd". volatile Exemple de declaratii de variabile membre: ¸ class Exemplu { double x. Variabilele ın declarate ˆ cadrul unei metode sunt locale metodei respective. 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. private (vezi ”Modificatori de acces pentru membrii unei clase”) • unul din cuvintele rezervate: static.2. unde un modificator poate fi : • un modificator de acces : public. 10). protected. transient. } .2. fiind vizibile ˆ toate metodele respectivei clase. private Point p = new Point(10. final. final static long MAX = 100000L. ı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. protected static int n.

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

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

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

¸ • synchronized Este folosit ˆ cazul ˆ care se lucreaz˘ cu mai multe fire de executie iar ın ın a ¸ metoda respectiv˘ gestioneaz˘ resurse comune. } . 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. cum ar fi C.. decˆt unui singur fir de executie. (vezi ”Fire de executie”) a ¸ . fiind critic˘ pentru consistenta a a ın a ¸ st˘rii unui obiect. indiferent de facultatea la care sunt. C++ ¸i limbajul de asamblare.. 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.. studentilor unei universit˘¸i trebuie s˘ a ¸ at a li se calculeze media finala. 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˘.. float ponderi[]) { .. ın ¸ ¸ ˆ aceea¸i manier˘. Are ca efect construirea a a unui monitor care nu permite executarea metodei. float ponderi[]) { return 10. final float calcMedie(float note[]. acestea s pot fi refolosite din programele Java. } class StudentInformatica extends Student { float calcMedie(float note[].3. ˆ functie de notele obtinute la examene. ın s a class Student { . 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.00. la un moment dat.2..

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

2. // Corect } Patrat metoda2( ) { Poligon p = new Poligon().3.. IMPLEMENTAREA METODELOR return (int)1. // Corect 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. De exemplu.) return p. if (. if (. // Corect } double metoda() { return (float)1. atˆt tip primitiv cˆt ¸i tip referint˘. Tipul de date al unui argument poate fi orice tip valid al a limbajului Java.. Patrat t = new Patrat()..) return p.3. // Corect } 53 Dac˘ valoarea returnat˘ este o referint˘ la un obiect al unei clase....]) Exemplu: . . // Eroare else return t.2. Patrat t = new Patrat().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˘. // Corect } 2. Poligon metoda1( ) { Poligon p = new Poligon(). fie clasa Poligon ¸i subclasa s acesteia Patrat. a a s ¸a TipReturnat metoda([Tip1 arg1. Tip2 arg2.

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

x = x. astfel ˆ at s˘ le poat˘ modifica valorile.2.y = y. } } Argumentul param are tip referint˘ ¸i. param. valy ¸i valr ¸i nu referinte la ele (adresele lor s s ¸ de memorie). 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. y. valy = y.3. public void aflaParametri(Param param) { param.raza = raza. a a a // Varianta incorecta: class Cerc { private int x. public void aflaParametri(int valx. s˘ consider˘m clasa Cerc descris˘ anterior ˆ care dorim s˘ a a a ın a implement˘m o metod˘ care s˘ returneze parametrii cercului. y. } class Cerc { private int x. raza. In concluzie. IMPLEMENTAREA METODELOR 55 De exemplu. metoda ıncˆ a a nu realizeaz˘ nimic pentru c˘ nu poate schimba valorile variabilelor primite a a ca argumente. s s a . int valy. raza. raza. param. 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˘). int valr) { // Metoda nu are efectul dorit! valx = x. } } Aceast˘ metod˘ nu va realiza lucrul propus ˆ a a ıntrucˆt ea prime¸te doar a s valorile variabilelor valx. valr = raza. y.

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

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

2 Clase interne Spre deosebire de clasele obi¸nuite. urmat de simbolul ’$’ apoi de numele clasei imbricate. ¸ 2.. 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.. class ClasaDeAcoperire{ class ClasaInterna1 {} class ClasaInterna2 {} } ..3 Identificare claselor imbricate Dup˘ cum ¸tim orice clas˘ produce la compilare a¸a numitele ”unit˘¸i de coma s a s at pilare”. } static class ClasaImbricataStatica { . O clas˘ imbricat˘ nestatic˘ se nume¸te clasa intern˘.6.. cele mai folosite clase imbricate sunt cele interne. o clas˘ imbricat˘ poate fi declarat˘ static˘ s a a a a sau nu. class ClasaInterna { . A¸adar.class s a s ¸i care contin toate informatiile despre clasa respectiv˘. care sunt fi¸iere avˆnd numele clasei respective ¸i extensia .. ın • o ”clas˘ intern˘” reflect˘ relatia dintre instantele a dou˘ clase.. OBIECTE SI CLASE ¸ 2.6. Pentru clasele ims ¸ ¸ a bricate aceste unit˘¸i de compilare sunt denumite astfel: numele clasei de at acoperire. ¸ In general. } } 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. a a a s a class ClasaDeAcoperire{ .66 CAPITOLUL 2. ˆ 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.

s 2. De exa emplu. ¸ ın Number numar = new Number().4 Clase anonime Exist˘ posibilitatea definirii unor clase imbricate locale. s a Long ¸i Short. reale.vom folosi ˆ schimb subclasele sale. Double.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. utilizate a aa doar pentru instantierea unui obiect de un anumit tip.. 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˘. ˆ pachetul java. // Eroare Integer intreg = new Integer(10). clasa Number reprezint˘ un concept abstract ¸i nu vom s a s putea instantia obiecte de acest tip .class ClasaDeAcoperire$ClasaInterna2.7. Integer.. A¸adar. ClasaAcoperire.class ClasaDeAcoperire$ClasaInterna1. ın ¸ precum ¸i extensiv ˆ capitolul ”Interfata grafic˘ cu utilizatorul”. ce implementeaz˘ obiecte pentru descrierea numerelor de un s a anumit tip.. // Corect . Intr-un program nu avem ˆ a nevoie de nua ıns˘ mere generice ci de numere de un anumit tip: ˆ ıntregi.lang exist˘ clasa abstract˘ Number care modeleaz˘ ın a a a conceptul generic de ”num˘r”.6. unde n este num˘rul a de clase anonime definite ˆ clasa respectiv˘ de acoperire.$1. f˘r˘ nume. Clasa Number serve¸te ca superclas˘ pentru clasele concrete Byte. a Exemple de folosire a claselor anonime vor fi date ˆ capitolul ”Interfete”. s ın ¸ a Fi¸ierele rezultate ˆ urma compil˘rii claselor anonime vor avea numele s ın a de forma ClasaAcoperire..$n. ın a 2. Float.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. CLASE SI METODE ABSTRACTE ¸ Pentru exemplul de mai sus vor fi generate trei fi¸iere: s ClasaDeAcoperire.2. etc.

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

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

. Writer: superclasele abstracte ale fluxurilor de intrare/ie¸ire s pe caractere • InputStream.. AbstractMap: superclase abstracte pentru structuri de date de tip colectie ¸ . Dintre cele mai importante amintim: • Number: superclasa abstract˘ a tipurilor referint˘ numerice a ¸a • Reader. 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 . } } Legat de metodele abstracte.70 CAPITOLUL 2. 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˘. a a a a a a • O metod˘ abstract˘ nu poate ap˘rea decˆt ˆ a a a a ıntr-o clas˘ abstract˘... AbstractSet. Ima ın a plementarea claselor pentru obiecte grafice ar fi: class Circle extends GraphicObject { void draw() { // Obligatoriu implementarea . OutputStream: superclasele abstracte ale fluxurilor de intrare/ie¸ire pe octeti s ¸ • AbstractList. a a • Orice clas˘ care are o metod˘ abstract˘ trebuie declarat˘ ca fiind aba a a a stract˘.

a a ¸ . a s • returnarea clasei din care face parte un obiect.1 Clasa Object Orice clas˘ are o superclas˘ a a Dup˘ cum am v˘zut ˆ sectiunea dedicat˘ modalit˘¸ii de creare a unei clase. Label.8 2. Button. direct a sau indirect. 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˘. Declaratiile de mai jos sunt echivalente: a a ¸ class Exemplu {} class Exemplu extends Object {} 2. etc.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. etc.8. Cu alte cuvinte. numit˘ superclas˘. • notificarea altor obiecte c˘ o variabil˘ de conditie s-a schimbat. CLASA OBJECT 71 • Component : superclasa abstract˘ a componentelor folosite ˆ deza ın voltarea de aplicatii cu interfat˘ grafic˘ cu utilizatorul (GUI). 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˘. ¸ s Clasa Object este ¸i superclasa implicit˘ a claselor care nu specific˘ o s a a anumit˘ superclas˘. cum ar fi: • posibilitatea test˘rii egalit˘¸ii valorilor obiectelor. descendent al acestei clase. • etc.8.2.8. Fiind p˘rintele tuturor. orice obiect fiind. a at • specificarea unei reprezent˘ri ca ¸ir de caractere a unui obiect . 2. cum ar ¸ ¸a a fi Frame. Aceasta este clasa Object. ˆ Java s a ın orice clas˘ are o superclas˘ ¸i numai una. Evident. 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.

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

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

System . println ( c1 . de genul tipPrimitivValue: ın a Integer obi = new Integer(1). Boolean obb = new Boolean(true).5 a limbajului Java. boolean b = obb. out .booleanValue(). System . int i = obi. println ( c1 . aduna ( c2 ) ) . Conversia explicit˘ va fi facut˘ de c˘tre a a a compilator. 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. Complex c3 = ( Complex ) c1 . OBIECTE SI CLASE ¸ public class TestComplex { public static void main ( String c []) Complex c1 = new Complex (1 . println ( c1 .intValue(). } } { // 3. . Incepˆnd cu versiunea 1. respectiv auto-unboxing. equals ( c2 ) ) . 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. atribuirile explicite ˆ a ıntre tipuri primitve ¸i referint˘ sunt posibile.74 CAPITOLUL 2.9 Conversii automate ˆ ıntre tipuri Dup˘ cum v˘zut tipurile Java de date pot fi ˆ artie ˆ primitive ¸i referint˘. System .0 i // false // true 2. out . out .0 + 5. clone () .3) .2) . Complex c2 = new Complex (2 . equals ( c3 ) ) .

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

OBIECTE SI CLASE ¸ .76 CAPITOLUL 2.

¸ ¸ a • starea programului ˆ momentul producerii acelei exceptii.println("Aici nu se mai ajunge.out..Capitolul 3 Exceptii ¸ 3. ın ¸ public class Exemplu { public static void main(String args[]) { int v[] = new int[10]. } } La rularea programului va fi generat˘ o exceptie. //Exceptie ! System. ¸ 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.. v[10] = 0. ¸ 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˘."). 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 . cum ar fi accesarea unui element din afara t spatiului alocat unui vector.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.

s Atentie ¸ In Java tratarea erorilor nu mai este o optiune ci o constrˆngere..lang. 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 .” nu va fi afi¸at).. catch ¸i finally. 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. In ¸ a aproape toate situatile. o secvent˘ de cod care poate provoca exceptii trebuie ¸ ¸a ¸ s˘ specifice modalitatea de tratare a acestora. a 3. Dac˘ sistemul nu gase¸te nici un a a a s analizor pentru o anumit˘ exceptie. 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”).ArrayIndexOutOfBoundsException :10 at Exceptii. EXCEPTII ¸ "Exception in thread "main" java.main (Exceptii.2 ”Prinderea” ¸i tratarea exceptiilor s ¸ Tratarea exceptiilor se realizeaz˘ prin intermediul blocurilor de instructiuni ¸ a ¸ try. 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. ˆ 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˘.java:4)" Crearea unui obiect de tip exceptie se nume¸te aruncarea unei exceptii ¸ s ¸ (”throwing an exception”).78 CAPITOLUL 3. C˘utarea se face recursiv. s ¸ Cu alte cuvinte. la aparitia unei erori este ”aruncat˘” o exceptie iar cineva ¸ a ¸ trebuie s˘ o ”prind˘” pentru a o trata.

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˘. while ( (c=f.out.println("\\nInchidem fisierul " + fis). f = new FileReader(fis).print((char)c).close(). Folosind mecanismul exceptiilor metoda ¸ citeste ˆsi poate trata singur˘ erorile care pot surveni pe parcursul executiei ı¸ a ¸ sale. ”PRINDEREA” SI TRATAREA EXCEPTIILOR ¸ ¸ } catch (TipExceptie2 variabila) { // Tratarea exceptiilor de tipul 2 } . 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. } Aceast˘ secvent˘ de cod va furniza erori la compilare deoarece ˆ Java a ¸a ın tratarea erorilor este obligatorie.println("Deschidem fisierul " + fis). .2.3.out. Tratarea exceptiilor este realizat˘ complet chiar de c˘tre metoda a ¸ a a citeste. f. . . 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.out. // Citim si afisam fisierul caracter cu caracter int c.read()) != -1) System. // Inchidem fisierul System. // Deschidem fisierul System.

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

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

2: Citirea unui fisier import java . { . io . while ( ( c = f . } . } Atentie ¸ O metod˘ care nu trateaz˘ o anumit˘ exceptie trebuie obligatoriu s˘ o a a a ¸ a ”arunce”. EXCEPTII ¸ 3. f = new FileReader ( fis ) . urmˆnd ca acestea s˘ implementeze tratarea lor sau.82 CAPITOLUL 3. int c . s˘ a a a a a ”arunce” mai departe exceptiile respective. la rˆndul lor. TipExceptie2. 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.*...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˘. read () ) != -1) System . IOException { FileReader f = null . print (( char ) c ) . f .. ¸ Acest lucru se realizeaz˘ prin specificarea ˆ declaratia metodei a clauzei a ın ¸ throws: [modificatori] TipReturnat metoda([argumente]) throws TipExceptie1.. close () . . out . public class CitireFisier { public static void citesteFisier ( String fis ) throws FileNotFoundException .

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

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

a 3. a ¸ a ¸ (vezi ”Crearea propriilor exceptii”) ¸ 3.4. throw e. } 85 Aceast˘ instructiune este folosit˘ mai ales la aruncarea exceptiilor proprii. sunt de a ¸ a genul: ”Ce se ˆ ampl˘ dac˘: . } Problemele care pot ap˘rea la aceasta functie.˘ 3. 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˘. aparent simpl˘. determina dimensiunea fisierului.out.4 Avantajele trat˘rii exceptiilor a ¸ Prin modalitatea sa de tratare a exceptiilor. ?” ıntˆ a a • fi¸ierul nu poate fi deschis s • nu se poate determina dimensiunea fi¸ierului s .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”. 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. citeste fisierul in memorie.4. aloca memorie. inchide fisierul. a a ¸ a • Gruparea erorilor dup˘ tipul lor..println("A aparut o exceptie). AVANTAJELE TRATARII EXCEPTIILOR ¸ catch(Exception e) { System. a a • Propagarea unei erori pˆn˘ la un analizor de exceptii corespunz˘tor..

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

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

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

ˆ a. ¸ Pronderea unei exceptii se poate face fie la nivelul clasei specifice pen¸ tru acea exceptie. De exemplu. ¸ s Radacin˘ acestei ierarhii este clasa Throwable (vezi ”Ierarhia claselor ce dea scriu exceptii”).. .. fie la nivelul uneia din superclasele sale. ¸ etc. La rˆndul ei.. cum ar fi FileNotFoundException. AVANTAJELE TRATARII EXCEPTIILOR ¸ int metoda2() throws TipExceptie { metoda3(). ˆ functie de ¸ ın ¸ necesit˘¸ile programului..˘ 3. EOFException.4. /* 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. Acestea sunt grupate ˆ functie de similarit˘¸ile ¸ ın ¸ at lor ˆ ıntr-o ierarhie de clase. clasa IOException se ˆ a ıncadreaz˘ ˆ a ıntr-o categorie mai larg˘ de a exceptii ¸i anume clasa Exception. cu cˆt clasa folosit˘ este mai generic˘ cu atˆt at ıns˘ a a a a tratarea exceptiilor programul ˆsi pierde din flexibilitate.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. } int metoda3() throws TipExceptie { citesteFisier(). } 89 3.4.dat").dat’ } // sau . ¸ ı¸ try { FileReader f = new FileReader("input. 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. .

90 CAPITOLUL 3. obiecte de tip Error. 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. care s sunt la rˆndul lor superclase pentru o serie ˆ a ıntreag˘ de tipuri de exceptii.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. 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. . a ¸ Erorile. 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.

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

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

respec¸ a tiv de scoatere a elementului din vˆrful stivei. Dac˘ presupunem c˘ stiva a a a poate memora maxim 100 de elemente. ambele operatii pot provoca exceptii. int n =0. } } class Stiva { int elemente [] = new int [100]. ˆ 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. CREAREA PROPRIILOR EXCEPTII ¸ public class ExceptieProprie extends Exception { public ExceptieProprie(String mesaj) { super(mesaj). } public int scoate () throws ExceptieStiva { if ( n ==0) throw new ExceptieStiva ( " Stiva este goala ! " ) . // numarul de elemente din stiva public void adauga ( int x ) throws ExceptieStiva { if ( n ==100) throw new ExceptieStiva ( " Stiva este plina ! " ) .7. } } 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. a ¸ . // Apeleaza constructorul superclasei Exception } } 93 S˘ consider˘m urm˘torul exemplu.-]. elemente [ n ++] = x .3: Exceptii proprii class ExceptieStiva extends Exception { public ExceptieStiva ( String mesaj ) { super ( mesaj ) . return elemente [n . ¸ ¸ Pentru a personaliza aceste exceptii vom crea o clas˘ specific˘ denumit˘ ¸ a a a ExceptieStiva: Listing 3.3.

ıns˘ . 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). chiar f˘r˘ nici un cod ˆ ele. EXCEPTII ¸ In general. Exceptiile proprii sunt descrise uzual ı¸ ın ¸ de clase foarte simple.94 CAPITOLUL 3. 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. 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. ˆ a aceasta dezvoltare nu ¸ ıns˘ ˆsi are rostul ˆ majoritatea cazurilor.

1. a s a ¸ 95 . a a ¸ a ¸ a Informatia se poate g˘si oriunde: ˆ ¸ a ıntr-un fi¸ier pe disc.Capitolul 4 Intr˘ri ¸i ie¸iri a s s 4. etc. obiecte. memorie. un progam Java ¸ trebuie s˘ deschid˘ un canal de comunicatie (flux) de la sursa informatiilor a a ¸ ¸ (fi¸ier. etc) ¸i s˘ citeasc˘ secvential informatiile respective. ˆ retea. s s a a ¸ ¸ Similar. imagini. } inchide canal comunicatie. 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. ¸ ¸ Indiferent de tipul informatiilor. ın s sunete.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˘.1 4. Pentru a aduce informatii dintr-un mediu extern. respectiv consum˘ informatii. 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. socket. 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. ˆ memorie s ın ¸ ın sau ˆ alt program ¸i poate fi de orice tip: date primitive.

dar pe fluxuri diferite.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 ¸ .*. a a s a Un proces care descrie o destinatie extern˘ pentru date se nume¸te proces ¸ a s consumator. a Un proces care descrie o surs˘ extern˘ de date se nume¸te proces produc˘tor.1. de la produc˘tor la consumator. 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. ¸ ¸ Fluxurile sunt unidirectionale. orice proces putˆnd fi atˆt proa a a a ducator cˆt ¸i consumator ˆ acela¸i timp. Deci. INTRARI SI IESIRI ¸ ¸ Definitii: ¸ Un flux este un canal de comunicatie unidirectional ˆ ¸ ¸ ıntre dou˘ procese. Clasele ¸i intefetele standard pentru lucrul cu fluxuri se g˘sesc ˆ pachetul s ¸ a ın java. orice program care necesit˘ operatii de intrare sau ie¸ire trea ¸ s buie s˘ contin˘ instructiunea de import a pachetului java. ¸ a Fiecare flux are un singur proces produc˘tor ¸i un singur proces consumator. a s Intre dou˘ procese pot exista oricˆte fluxuri. Un flux care cite¸te date se nume¸te flux de intrare.io.io: a ¸ a ¸ import java.96 ˘ CAPITOLUL 4. s s Un flux care scrie date se nume¸te flux de ie¸ire.io. s s Observatii: ¸ Fluxurile sunt canale de comunicatie seriale pe 8 sau 16 biti.

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

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

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

a . FileReader nu putea citi decˆt caracter s a cu caracter. folosind codificarea stans ıi s dard a caracterelor sau o codificare specificat˘ de program. Clasele ce descriu aceste fluxuri pot fi ˆ ımpartite ˆ functie de tipul de ın ¸ procesare pe care ˆ efectueaza astfel: ıl • ”Bufferizare” BufferedReader. Un flux InputStreamReader cite¸te octeti dintr-un flux ¸ s ¸ InputStream ¸i ˆ converte¸te la caractere. BufferedReader a poate prelua date de la un flux FileReader ¸i s˘ ofere informatia dintr-un s a ¸ fi¸ier linie cu linie. a • Conversie octeti-caractere ¸ InputStreamReader.100 ˘ CAPITOLUL 4. reducˆnd astfel num˘rul de acces˘ri la dispozitivul ce ¸ a a a reprezint˘ sursa/destinatia original˘ a datelor. BufferedOutputStream Sunt folosite pentru a introduce un buffer ˆ procesul de citire/scriere ın a informatiilor. INTRARI SI IESIRI ¸ ¸ date (pipe). 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. Similar.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. Fiind primitiv. a s • Filtrare FilterReader. a a mai util˘ dintr-un anumit punct de vedere. BufferedWriter BufferedInputStream. FilterOutputStream Sunt clase abstracte ce definesc o interfat˘ comun˘ pentru fluxuri care ¸a a filtreaz˘ automat datele citite sau scrise (vezi ”Fluxuri pentru filtrare”). De exemplu. FilterWriter FilterInputStream. ¸ a ¸ 4.2. Un flux de procesare nu poate fi folosit decˆt ˆ a ımpreun˘ cu un a flux primitiv. 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”).

s • Serializare ObjectInputStream. ı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”). FOLOSIREA FLUXURILOR 101 • Concatenare SequenceInputStream Concateneaz˘ mai multe fluxuri de intrare ˆ a ıntr-unul singur (vezi ”Concatenarea fi¸ierelor”).4. 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. • Conversie tipuri de date DataInputStream. 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. prin instructiunea a s ¸ new ¸i invocarea unui constructor corespunz˘tor al clasei respective: s a Exemple: .2.3 Crearea unui flux Orice flux este un obiect al clasei ce implementeaz˘ fluxul respectiv. • 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.2. ObjectOutputStream Sunt folosite pentru serializarea obiectelor (vezi ”Serializarea obiectelor”).

//crearea unui flux de iesire pe caractere FileWriter out = new FileWriter("fisier. Din acest motiv.102 ˘ CAPITOLUL 4. A¸adar. 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. //echivalent cu FileReader fr = new FileReader("fisier. A¸adar.dat"). //echivalent cu FileWriter fo = new FileWriter("fisier. BufferedWriter out = new BufferedWriter(fo). INTRARI SI IESIRI ¸ ¸ //crearea unui flux de intrare pe caractere FileReader in = new FileReader("fisier.txt"). 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).dat").txt"))). //crearea unui flux de iesire pe octeti FileOutputStrem out = new FileOutputStream("fisier. //crearea unui flux de iesire printr-un buffer BufferedWriter out = new BufferedWriter( new FileWriter("fisier. //crearea unui flux de intrare pe octeti FileInputStream in = new FileInputStream("fisier. crearea unui flux pentru procesarea datelor are formatul general: s .txt").txt").txt")).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.

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. fluxurile pot fi compuse ˆ succesiuni oricˆt de lungi: ın a DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream("fisier. FileOutputStream .octeti Constructorii acestor clase accept˘ ca argument un obiect care s˘ specifice a a un anume fi¸ier. In general. FileWriter .4 Fluxuri pentru lucrul cu fi¸iere s Fluxurile pentru lucrul cu fi¸iere sunt cele mai usor de ˆ s ınteles. FOLOSIREA FLUXURILOR 103 FluxProcesare numeFlux = new FluxProcesare(fluxPrimitiv). 4. Dup˘ cum am v˘zut deja. Acesta poate fi un ¸ir de caractere. clasele care implementeaz˘ aceste fluxuri sunt a a a urm˘toarele: a FileReader. 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.caractere FileInputStream. boolean throws IOException append) .2.2.4.dat"))). on obiect de tip File s s sau un obiect de tip FileDesciptor (vezi ”Clasa File”). ˆ ıntrucˆt a operatia lor de baz˘ este citirea.

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

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

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

print (( char ) c ) . f2 ) . s Exemplul cel mai elocvent de folosirea a acestei clase este concatenarea a dou˘ sau mai multor fi¸iere: a s Listing 4. out .4. while (( c = s . exit ( -1) . Rezultatul concatenarii este afisat pe ecran . a a Constructorii acestei clase sunt: SequenceInputStream(Enumeration e) SequenceInputStream(InputStream s1. InputStream s2) Primul construieste un flux secvential dintr-o multime de fluxuri de in¸ trare. dup˘ care procesul se ın a repet˘ pˆna la terminarea tuturor fluxurilor de intrare. FileInputStream f2 = new FileInputStream ( args [1]) . 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. out . public class Concatenare { public static void main ( String args []) { if ( args . int c . Fiecare obiect ˆ enumerarea primit˘ ca parametru trebuie s˘ fie de ın a a tipul InputStream. SequenceInputStream s = new S eq u e nc e I np u tS t r ea m ( f1 .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. length <= 1) { System . read () ) != -1) System . Cel de-al doilea construie¸te un flux de intrare care combin˘ doar dou˘ fluxuri s a a s1 ¸i s2. . io . } try { FileInputStream f1 = new FileInputStream ( args [0]) .2: Concatenarea a dou˘ fi¸iere a s /* Concatenarea a doua fisiere ale caror nume sunt primite de la linia de comanda . System .2. FOLOSIREA FLUXURILOR 107 4. println ( " Argumente insuficiente ! " ) . */ import java . primul flux citit fiind s1.*. 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.2.

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

sunt date ˆ tabelul de a ın mai jos: .2.2. De exemplu. a A¸adar. Cele mai folosite ¸ ın metode. ci introduc o noua modalitate de manipulare a lor. fluxurile de filtrare nu elimin˘ date citite sau scrise de un anumit s a flux. Din acest motiv. s s Clasele care ofer˘ un astfel de suport implementeaz˘ interfetele DataInput. 4. Prin urmare. urmˆnd ca citirea/scrierea s˘ se a a fac˘ prin intermediu acelui buffer.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. altele decˆt cele comune tuturor fluxurilor. clasa BufferedInputStream pune la dispozitie metoda readLine pentru citirea unei linii din fluxul de intrare. FOLOSIREA FLUXURILOR Observati c˘ toate aceste clase descriu fluxuri de octeti. ¸ 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˘. ele mai fiind numite ¸i fluxuri de procesare. clasele de filtrare BufferedInputStream ¸i BufferedOutputStream s colecteaz˘ datele unui flux ˆ a ıntr-un buffer. fluxurile de filtrare vor contine s ¸ anumite metode specializate pentru citirea/scrierea datelor. vor furniza metode pentru ¸ citirea ¸i scrierea datelor la nivel de tip primitiv ¸i nu la nivel de octet. a a ¸ respectiv DataOutput. ¸ 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). ci de date primitive. altele decˆt cele a comune tuturor fluxurilor.4. Acestea definesc metodele pe care trebuie s˘ le pun˘ la a a dispozitie ˆ vederea citireii/scrierii datelor de tip primitiv. A¸a cum am v˘zut la citirea/scrierea cu zon˘ a a s a a tampon.

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

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

clas˘ concret˘ pentru scrierea datelor.4.4.out.).printf (format.2 Citirea datelor de la tastatur˘ a Uzual. } Fluxurile de ie¸ire pot fi folosite a¸adar f˘r˘ probleme deoarece tipul lor s s aa este PrintStream.format (format.println(argument).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.out..1 Afisarea informatiilor pe ecran ¸ Am v˘zut deja numeroase exemple de utilizare a fluxului standard de ie¸ire.println(linie). este acela¸i cu fluxul standard ın ¸ ¸ s de ie¸ire. System. 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. s catch(Exception e) { System.out. In schimb.out este de tip InputStream. argumente. a s el fiind folosit la afi¸area oric˘ror rezultate pe ecran (ˆ modul consola): s a ın System.112 ˘ CAPITOLUL 4.out. String linie = stdin. Fluxul standard pentru afi¸area erorilor se folose¸te similar ¸i apare uzual s s s ˆ secventele de tratare a exceptiilor. System.err.in)). care este o clas˘ a abstract˘. Exemplul tipic este: a a a BufferedReader stdin = new BufferedReader( new InputStreamReader(System.)..print("Introduceti o linie:").. fluxul a a standard de intrare System.out. Implicit. argumente. System. System.readLine() System. INTRARI SI IESIRI ¸ ¸ 4.print (argument). as ¸ a as a a . a a a 4.println("Exceptie:" + e).. 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˘.

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

Putem redirecta afisarea c˘tre un fi¸ier pe care s˘-l citim dup˘ a s a a executia programului. redirectˆnd intrarea standard c˘tre acel fi¸ier. Pentru a nu le scrie de la a s tastatur˘ de fiecare dat˘ ˆ timpul test˘rii programului.4: Exemplu de folosire a redirect˘rii: a import java . 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. PrintStream err = new PrintStream ( new FileOutputStream ( " erori . io .setOut(fis). setErr ( err ) . 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.txt"))). in ) ) . System. setOut ( out ) . a Listing 4. System . txt " ) ) . ele pot fi puse ˆ a a ın a ıntrun fi¸ier. txt " ) ) . System . System. BufferedReader br = new BufferedReader ( new InputStream Reader ( System .txt"))). setIn ( in ) . txt " ) ) . System . Redirectarea intr˘rii poate fi folositoare pentru un program ˆ mod cona ın sol˘ care prime¸te mai multe valori de intrare. 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 . PrintStream out = new PrintStream ( new FileOutputStream ( " rezultate . In momentul cˆnd s a a s a testarea programului a luat sfˆrsit redirectarea poate fi eliminat˘. 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.*.114 ˘ CAPITOLUL 4. .setErr(fis). datele fiind a a cerute din nou de la tastatur˘.

pe rˆnd.4. printStackTrace () . } catch ( IOException e ) { /* Daca apar exceptii . txt si vor fi scrise in fisierul rezultate .. tab. Implicit. punct ¸i virgula.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”.4.4. readLine () ) != null ) { /* Liniile vor fi citite din fisierul intrare . ele vor fi scrise in fisierul erori . println ( " Eroare intrare / iesire ! " ) . e . while (( s = br . se vor citi. } // Aruncam fortat o exceptie throw new IOException ( " Test " ) . println ( s ) . ¸ Constructorii clasei sunt: . atomii lexicali ai fluxului respectiv. } } } 115 4. out . etc. txt */ System . txt */ System . FLUXURI STANDARD DE INTRARE SI IESIRE ¸ ¸ String s . ˆ a pot fi s ¸ ¸ a s ıns˘ schimbati prin diverse metode ale clasei. virgul˘. 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. ace¸ti separas tori sunt cei obi¸nuti: spatiu. Rezultatul va consta ˆ faptul c˘ ˆ loc s˘ se citeasc˘ ın ın a ın a a octeti sau caractere.

5: Citirea unor atomi lexicali dintr-un fisier /* Citirea unei secvente de numere si siruri dintr .atom ce marcheaz˘ sfˆr¸itul unei linii a as • TT NUMBER . // Se citeste primul atom lexical .atom de tip num˘r a • TT WORD.un fisier specificat si afisarea tipului si valorii lor */ import java .tipul ultimului atom citit din flux • nval.valoarea unui atom numeric • sval . txt " ) ) .116 ˘ CAPITOLUL 4. public class CitireAtomi { public static void main ( String args []) throws IOException { BufferedReader br = new BufferedReader ( new FileReader ( " fisier . 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.atom de tip cuvˆnt a • ttype. StreamTokenizer st = new StreamTokenizer ( br ) .*. care returnez˘ a tipul atomului lexical citit ¸i scrie ˆ variabilele nval sau sval valoarea cores ın spunzato˘re atomului. io . nextToken () . int tip = st . 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 .valoarea unui atom de tip cuvˆnt a Citirea atomilor din flux se face cu metoda nextToken().atom ce marcheaz˘ sfˆar¸itul fluxului a a s • TT EOL .

5 Clasa RandomAccesFile (fi¸iere cu acces dis rect) Dup˘ cum am v˘zut. 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.5. desi sunt foarte utile ¸i pentru dispozitive ˆ care informatia poate ¸ s ın ¸ fi accesat˘ direct. fluxurile sunt procese secventiale de intrare/ie¸ire. sval ) . out . a s a In cazul ˆ care tipul atomilor nu ne intereseaz˘. TT_NUMBER : System . println ( " Numar : " + st . a aa a a • se g˘se¸te ˆ pachetul java.4. TT_EOF ) { switch ( tip ) { case StreamTokenizer .io. 4. } tip = st . a a ¸ s Acestea sunt adecvate pentru lucrul cu medii secventiale de memorare a ¸ datelor. a s ın . care realizeaz˘ s a a ˆ artirea unui ¸ir de caractere ˆ atomi lexicali. ¸ ¸ s • este o clas˘ de sine st˘t˘toare. a Clasa RandomAccesFile are urm˘toarele caracteristici: a • permite accesul nesecvential (direct) la continutul unui fi¸ier. ın a pˆna se ajunge la sfˆrsitul fluxului (TT EOF). break . // Trecem la urmatorul atom } } } 117 A¸adar. subclas˘ direct˘ a clasei Object. println ( " Cuvant : " + st . out . nextToken () . CLASA RANDOMACCESFILE (FISIERE CU ACCES DIRECT) ¸ while ( tip != StreamTokenizer . TT_WORD : System . 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. este mai simplu s˘ ın a a citim fluxul linie cu linie ¸i s˘ folosim clasa StringTokenizer. sau metoda split a clasei ımp˘ ¸ s ın String. case StreamTokenizer . nval ) . ˆ care se citesc atomii unul cˆte unul cu metoda nextToken.

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

listarea fi¸ierelor s s dintr-un director. crearea unui director. 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. 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. . sau este directorul curent . 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. io . s a s File f = new File("fisier. Numele directorului este primit ca argument de la linia de comanda .4.6. 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˘. ˆ aceast˘ clas˘ vom g˘si metode pentru testarea existentei. Pentru fiecare din ele vor fi afisate diverse informatii . CLASA FILE 119 4. 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. ın a a a ¸ s redenumirea unui fi¸ier sau 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. ¸tergerea. etc.*. Astfel. fie multimea fi¸ierelor dintr-un director. */ import java .6: Listarea continutului unui director ¸ /* Programul listeaza fisierele si subdirectoarele unui director . 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.txt"). pentru fiecare din ele afi¸eaz˘ diverse s s a informatii: ¸ Listing 4.

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

¸ a 121 . O interfat˘ Java define¸te un set de metode dar nu specific˘ nici o imple¸a s a mentare pentru ele. Interfetele permit.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.1. s Definitie ¸ O interfat˘ este o colectie de metode f˘r˘ implementare ¸i declaratii de ¸a ¸ aa s ¸ constante. supunˆndu-se a a ¸ a a¸adar unui anumit comportament. o interfat˘ poate fi privita ca un ¸a s ¸a protocol de comunicare ˆ ıntre obiecte. A¸adar. 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.1 5. definirea unor noi tipuri de date.Capitolul 5 Interfete ¸ 5. O clas˘ care implementeaz˘ o interfat˘ trebuie obligatoa a ¸a riu s˘ specifice implement˘ri pentru toate metodele interfetei. al˘turi de clase.

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

FOLOSIREA INTERFETELOR ¸ 123 • metode f˘r˘ implementare: acestea pot fi sau nu declarate cu moda a ificatorul public. a 5.. // Incorect. Interfata2. nici un alt modificator nu poate ap˘rea ˆ declaratia unei metode a unei interfete. . ˆ a acest lucru nu ın ¸ s ın ¸ ıns˘ mai este valabil. • In variantele mai vechi de Java era permis ¸i modificatorul abstract s ˆ declaratia interfetei ¸i ˆ declaratiile metodelor. protected void metoda2(). • Variabilele unei interfete sunt implicit constante chiar dac˘ nu sunt ¸ a declarate cu modificatorii static ¸i final..2.5.2. modificator nepermis Atentie ¸ • Variabilele unei interfete sunt implicit publice chiar dac˘ nu sunt declarate ¸ a cu modificatorul public. . deoarece atˆt interfata cˆt ¸i metodele sale nu pot fi a ¸ a s altfel decˆt abstracte. s • Metodele unei interfete sunt implicit publice chiar dac˘ nu sunt declarate ¸ a cu modificatorul public.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. care este implicit. // Echivalent cu: public void metoda(). a ın ¸ ¸ interface Exemplu { void metoda().

vor trebui s˘ contin˘ metodele: a a ¸ a • push .124 CAPITOLUL 5.returneaz˘ continutul stivei sub forma unui ¸ir de caractere. odat˘ creata ¸i folosit˘ la implementarea unor clase. ˆ 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˘. dac˘ acesta a ¸a a este o instant˘ a unei clase ce implementeaz˘ interfata X. INTERFETE ¸ O clas˘ poate implementa oricˆte interfete sau poate s˘ nu implementeze a a ¸ a nici una. a ¸a O interfat˘ nu este o clas˘.adaug˘ un nou element in stıv˘ a a • pop . atunci treın a a a ¸a buie obligatoriu s˘ specifice cod pentru toate metodele interfetei. o clas˘ poate avea ¸i alte metode ¸i variabile a a s s membre ˆ afar˘ de cele definite ˆ interfat˘. o interfat˘ nu a s a ¸a mai trebuie modificat˘. In cazul ˆ care o clas˘ implementeaz˘ o anumit˘ interfat˘. Evident.3 Exemplu: implementarea unei stive S˘ consider˘m urm˘torul exemplu. Dorim s˘ implement˘m un nou tip de a a a a a date numit Stack. a ¸ s . ¸ a s a a 5.testeaz˘ dac˘ stiva este vid˘ a a a • toString .elimin˘ elementul din vˆrful stivei a a • peek . ¸a a ¸ Implementarea unei interfete poate s˘ fie ¸i o clas˘ abstract˘. indiferent de implementarea lor. 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˘. unde X este o interfat˘. Din acest a ¸ motiv.returneaz˘ varful stivei a • empty . 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˘. care s˘ modeleze notiunea de stiv˘ de obiecte. Din acest motiv. ın a ın ¸a Atentie ¸ Modificarea unei interfete implic˘ modificarea tuturor claselor care im¸ a plementeaz˘ acea interfat˘.2.

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

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

top ) . this . // legatura la urmatorul nod Node ( Object item . } public String toString () { String s = " " .2. // Referinta la varful stivei public void push ( Object item ) { Node node = new Node ( item . // informatia din nod Node link . item . while ( node != null ) { . } public void pop () throws StackException { if ( empty () ) throw new StackException ( " Stiva este vida ! " ) . item = item . } public Object peek () throws StackException { if ( empty () ) throw new StackException ( " Stiva este vida ! " ) . } public boolean empty () { return ( top == null ) . Node link ) { this .4: Implementarea stivei folosind o list˘ a // Implementarea stivei folosind o lista inlantuita . link . } } private Node top = null . link = link . return top . top = top . public class StackImpl2 implements Stack { class Node { // Clasa interna ce reprezinta un nod al listei Object item . ce trebuie obligatoriu ¸ s ¸ tratate. Node node = top . S˘ vedem acum modalitatea de implementare a stivei folosind o list˘ a a ˆ antuit˘: ınl˘ ¸ a Listing 5.5. top = node . 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.

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

INTERFETE SI CLASE ABSTRACTE ¸ ¸ 129 afiseaza accept˘ ca argument orice obiect al unei clase ce implementeaz˘ a a Stack. • implementarea unei interfete specific˘ doar necesitatea implement˘rii ¸ a a unor anumie metode. a .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). ˆ a ˆ general este ’Nu’.3. diferenta const˘ ˆ ¸ a ın: • extinderea unei clase abstracte forteaz˘ o relatie ˆ ¸ a ¸ ıntre clase. 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˘. Observatie ¸ In pachetul java. aceasta va fi folosit˘ ˆ aplicatiile ce au nevoie de acest s a ın ¸ tip de date. 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. 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˘.util exist˘ clasa Stack care modeleaz˘ notiune de stiv˘ a a ¸ a de obiecte ¸i. La nivel conceptual. evident. Un a s a exemplu sugestiv este dat de clasele ce descriu colectii. Exemplu oferit de noi nu are leg˘tur˘ cu aceast˘ clas˘ ¸i are rol a a a as pur demonstrativ. Fara folosirea interfetelor nu am putea forta clasa respectiv˘ s˘ ¸ ¸ a a respecte diverse tipuri de protocoale. deoarece ˆ Java nu exista decˆt mo¸tenire a a a ın a s simpla. 5. A¸adar. ¸ ı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˘. Ca sa particulariz˘m.

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

void metoda(). pot ap˘rea situatii de ambiguitate.x). //corect System. //ambiguitate . In cazul in care acest lucru se ˆ ampl˘.println(I2. MOSTENIRE MULTIPLA PRIN INTERFETE ¸ ¸ } interface Mortal { void omoara().out. //corect System.4. interface I1 { int x=1. } //corect //incorect class C implements I1. atunci cˆnd exist˘ constante a ¸ a a sau metode cu acelea¸i nume ˆ mai multe interfete. void metoda(). deoarece scrierea unui cod care poate fi confuz este un stil prost de programare. } class Dracula implements public void ameninta() public void distruge() public void omoara()() public void beaSange() } 131 MonstruPericulos. } interface Vampir extends void beaSange(). } interface I2 { int x=2. ˆ a acest lucru trebuie s ın ¸ ıns˘ ˆ ıntotdeauna evitat.out. I2 { public void metoda() { System.˘ 5.println(I1.println(x). //int metoda(). 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.out. Mortal { Vampir { {} {} {} {} Evident.x). cum ar fi situatia cˆnd au aceea¸i list˘ de argumente dar ¸ a s a tipuri returnate incompatibile.

1 Crearea grupurilor de constante Deoarece orice variabil˘ a unei interfete este implicit declarat˘ cu public. a a ¸ • O clas˘ trebuie obligatoriu s˘ trateze metodele din interfetele pe care a a ¸ la implementeaz˘. interfetele reprezint˘ o metod˘ convenabil˘ de creare a unor ¸ a a a grupuri de constante care s˘ fie folosite global ˆ a ıntr-o aplicatie: ¸ . Interfetele a ¸ sunt utile pentru: • definirea unor similaritati ˆ ıntre clase independente f˘r˘ a forta artificial aa ¸ o legatur˘ ˆ a ıntre ele. 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˘. • transmiterea metodelor ca parametri.5. a a • definirea unor grupuri de constante. a a a • O clas˘ poate implementa oricˆte interfete. indiferent de ierarhia de clase din care face parte. o interfat˘ define¸te un protocol ce poate fi implementat a a ¸a s de orice clas˘. • asigur˘ c˘ toate clasele care implementeaz˘ o interfat˘ pun la dipozitie a a a ¸a ¸ metodele specificate ˆ interfat˘ . a ¸ a static si final.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˘.5 Utilitatea interfetelor ¸ Dup˘ cum am v˘zut.132 } } CAPITOLUL 5. 5. a • Ierarhia interfetelor este independent˘ de ierarhia claselor care le im¸ a plementeaz˘. a 5.

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

executa(v).explorare(new AfisareEn()).134 CAPITOLUL 5.println("Nodul curent este: " + v). } } } //Definim doua functii class AfisareRo implements Functie { public void executa(Nod v) { System. a s 5.. 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). ¸ A¸adar.explorare(new AfisareRo()).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. ¸i alte tehnici de programare.println("Current node is: " + v). } } class AfisareEn implements Functie { public void executa(Nod v) { System. G.out.out. prin intermediul s ın ¸a s˘u. } } public class TestCallBack { public static void main(String args[]) { Graf G = new Graf(). cum ar fi metoda list a clasei File. G. ˆ ın ¸ a ıntrucˆt face a parte din API-ul standard Java ¸i vor fi puse ˆ evident˘. a a s . //.. } } Al doilea xemplu va fi prezentat ˆ sectiunea urm˘toare. INTERFETE ¸ if (explorarea a ajuns in nodul v) { f.

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

Filtru ( String extensie ) { this . i ++) System . vor fi listate toate . */ import java . for ( int i = 0.136 CAPITOLUL 5. } } } class Filtru implements FilenameFilter { String extensie . String [] list . a Listing 5. 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. println ( list [ i ]) . " ) .*. if ( args . . INTERFETE ¸ Instantele claselor pentru filtrare sunt primite ca argumente de metode ¸ de listare a continutului unui director. Acesta este un exemplu tipic de a a a transmitere a unei functii (functia de filtrare accept) ca argument al unei ¸ ¸ metode.6: Listarea fi¸ierelor cu o anumit˘ extensie s a /* Listarea fisierelor din directorul curent care au anumita extensie primita ca argument . Daca nu se primeste nici un argument . extensie = extensie . printStackTrace () . list () . length > 0) list = director . } catch ( Exception e ) { e . else list = director . class Listare { public static void main ( String [] args ) { try { File director = new File ( " . length . io . list ( new Filtru ( args [0]) ) . out . 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. ea fiind substia ¸ a tuit˘ cu orice clas˘ care o implementeaz˘. i < list .

putem folosi clas˘ intern˘ anonim˘. i < list . } else list = director . } catch ( Exception e ) { e . if ( args . list () . out . } . } } 137 5. */ import java . list = director . list ( new FilenameFilter () { // Clasa interna anonima public boolean accept ( File dir . io . " + extensie ) ) . String nume ) { return ( nume . Listing 5.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 ++) System . } }) .6. String [] list . for ( int i = 0. println ( list [ i ]) . " + extensie ) ) . " ) . class Listare { public static void main ( String [] args ) { try { File director = new File ( " .6.5. endsWith ( " .*. endsWith ( " .7: Folosirea unei clase anonime /* Listarea fisierelor din directorul curent folosind o clasa anonima pentru filtru . String nume ) { return ( nume . length > 0) { final String extensie = args [0]. 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. INTERFATA FILENAMEFILTER ¸ } public boolean accept ( File dir . aceast˘ situatie fiind un exemplu a a a a ¸ tipic de folosire a acestora. printStackTrace () . length .

5. nu exist˘ nici o problem˘ ˆ a determina ordinea fireasc˘ a a ın a a elementelor.sort(v). nume = nume . // Sorteaza vectorul v // Acesta va deveni {1.Arrays. 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. cod = cod . 4} In cazul ˆ care elementele din vector sunt de tip primitiv. java. String nume .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. this . public Persoana ( int cod . 2}.util. 3. 1. 4.util. 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 }).138 } } CAPITOLUL 5. ˆ care dorim a a a ın s˘ sort˘m un vector format din instante ale clasei Persoana. 2. INTERFETE ¸ A¸adar. definit˘ mai jos: a a ¸ a Listing 5.Arrays. int v[]={3. ca in exemın plul de mai sus.8: Clasa Persoana (f˘r˘ suport pentru comparare) aa class Persoana { int cod . } public String toString () { return cod + " \ t " + nume . } } . String nume ) { this .

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

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

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. p [2] = new Persoana (2 . sort (p . 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. " Georgescu " ) . 5. Interfata java. false. p [1] = new Persoana (1 . Aceasta este oferit˘ tot de metoda sort din clasa java. } } 141 Observati folosirea operatorului instanceof. new Comparator () { public int compare ( Object o1 . Arrays . pur ¸i s simplu. vom transmite ın ın a a un argument de tip Comparator care s˘ specifice modalitatea de comparare a a elementelor. Object o2 ) { Persoana p1 = ( Persoana ) o1 .util. nume . COMPARAREA OBIECTELOR return ( cod . " Popescu " ) .11: Sortarea unui vector folosind un comparator import java .7. " Ionescu " ) . Object o2).*.p . care verific˘ dac˘ un obiect ¸ a a este instant˘ a unei anumite clase. . Persoana p2 = ( Persoana ) o2 . avem nevoie de o alt˘ a a a a solutie. util . a a Listing 5. nume ) ) . cod ) . Metoda equals va returna. a ¸ S˘ presupunem c˘ dorim s˘ sort˘m persoanele ordonate dup˘ numele lor.5. pe lˆng˘ vectorul ce trebuie sortat. p [0] = new Persoana (3 . ¸ a dar ˆ varianta ˆ care. " Vasilescu " ) .util.7. a a a a a Pentru definirea comparatorului vom folosi o clas˘ anonim˘. class Sortare { public static void main ( String args []) { Persoana p [] = new Persoana [4]. return ( p1 . p [3] = new Persoana (4 . compareTo ( p2 .Arrays. care impune ¸ ¸ o ordine total˘ asupra elementelor unei colectii.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.Comparator contine metoda compare.

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

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.8. 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. Mai multe exemple de folosire a adaptorilor vor fi date ˆ capitolul ”Interfata ın ¸ grafic˘ cu utilizatorul”. supradefinind doar metoda care ne intereseaz˘: a a functie(new XAdapter() { public void metoda_1() { // Singura metoda care ne intereseaza . ADAPTORI }).. public void metoda_n() {} } In situatia cˆnd avem nevoie de un obiect de tip X vom folosi clasa ¸ a abstract˘..5.. aa ¸ public abstract class XAdapter implements X { public void metoda_1() {} public void metoda_2() {} .. } }). a .

144 CAPITOLUL 5. INTERFETE ¸ .

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

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

awt. tf1 = new java. In aceste situatii.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. sau ¸ ın ¸ a a ˆ ıntreg pachetul din care face parte.6.awt. 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. ¸ 6.Button .awt. tf1 = new TextField("Placut"). Din acest moment. care trebuie s˘ apar˘ la ˆ a a ınceputul fi¸ierelor surs˘.numele scurt al clasei . = new Button("Cancel").1.Button("OK"). = new java. Button java. Acest lucru se realizeaz˘ prin instructiunea a ¸ import. PACHETE 147 Specificarea numelui complet al clasei se face prin prefixarea numelui scurt al clasei cu numele pachetului din care face parte: numePachet.pachetul din care face parte .awt.TextField = new java.1.Button b2 java. ˆ s a ınainte de declararea vreunei clase sau interfete. a a De exemplu.awt java. .awt.TextField.Button b1 java. //Pentru exemplul nostru: import java. import java.Button("Cancel").awt.TextField("Tot neplacut"). tf2 = new TextField("Foarte placut").awt. tf2 = new java.awt.numeClasa.awt. 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").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.NumeClasa.awt. vom importa ˆ aplicatia noastr˘ clasa respectiv˘.Button.TextField("Neplacut").TextField java.awt.

TextField. In aceast˘ situatie ar fi mai simplu s˘ folosim importul la cerere din ˆ a ¸ a ıntregul pachet ¸i nu al fiec˘rei clase ˆ parte.Rectangle. java. Point p = new Point(0.Line.Polygon. ar trebui s˘ s a avem cˆte o instructiune de import pentru fiecare dintre ele: a ¸ import import import import import import java. Dac˘ ˆ exemplul nostru a a a ın am avea nevoie ¸i de clasele Line.Point.C*. O expresie de genul import java.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.Button.awt. Point. java.awt.1. Din acest moment.awt.awt. java.*. 0). ın a import numePachet.awt.awt. Se nume¸te import la cerere deoarece ˆ arcarea s ınc˘ claselor se face dinamic. s a ın 6. 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.148 CAPITOLUL 6. urmat de simbolul *.awt. Rectangle. //Pentru exemplul nostru: import java. 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"). . va produce a o eroare de compilare. 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. Polygon.awt. java. java.*. ˆ momentul apel˘rii lor.

.. 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. pentru orice fi¸ier surs˘.List a = new java.List b = new ArrayList().6. PACHETE 149 In cazul ˆ care sunt importate dou˘ sau mai multe pachete care contin ın a ¸ clase (interfete) cu acela¸i nume.util. //corect java. • pachetul curent • pachetul implicit (f˘r˘ nume) aa 6. a import java.5.1.util.awt. // Contine clasa List import java. ˆ caz contrar fiind semnalat˘ o ambiguitate de ın a c˘tre compilator. Astfel. urm˘toarele s a a pachete: • pachetul java. .*. // Contine interfata List .lang import java. //Declaratie ambigua java.awt.CONSTANTA. ˆ loc s˘ ne referim la constantele clasei cu expresii de tipul ın a NumeClasa.NumeClasa. //corect Sunt considerate importate automat.. List x.lang.awt.*. introdus˘ ˆ a a ıncepˆnd cu versiunea 1. // Poate sau nu sa apara // Mai bine nu. putem folosi doar numele constantei. atunci referirea la ele trebuie f˘cut˘ doar ¸ s a a folosind numele complet.5 Importul static Aceast˘ facilitate.List().*.1.*..

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

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

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. functie. 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. grup.2 6. algebr˘.java. Intr-un fi¸ier surs˘ s a pot exista oricˆte clase sau interfete care nu sunt publice. s˘ a a a presupunem c˘ dorim s˘ cre˘m clase care s˘ descrie urm˘toarele notiuni: a a a a a poligon. Pentru a simplifica lucrurile.152 CAPITOLUL 6. sfer˘.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. S˘ presupunem c˘ dorim crearea unor compoa a nente care s˘ reprezinte diverse notiuni matematice din domenii diferite. s ¸ Vom clarifica modalitatea de organizare a fi¸ierelor surs˘ ale unei aplicatii s a printr-un exemplu concret. a ¸ cum ar fi geometrie. 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 .java. sau compilatorul s a ¸ s va furniza o eroare.2. ın a s ¸ s Cu alte cuvinte. ORGANIZAREA CLASELOR 6. ci doar recomandat. ˆ ıntr-un fi¸ier surs˘ nu pot exista s a dou˘ clase sau interfete publice. Din acest motiv. 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 . Pentru clasele care nu sunt publice a ¸ acest lucru nu este obligatoriu. Dac˘ numele pachetelor sunt formate din mai multe unit˘¸i lexicale a at separate prin punct. analiz˘. cerc. 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 . un director va contine surse pentru clase ¸i interfete ¸ s ¸ din acela¸i pachet iar numele directorului va fi chiar numele pachetus lui. poliedru. etc.

.java /algebra Grup. .java package geometrie.java package geometrie. ˆ a.java package geometrie.plan. . } // Poliedru.java /spatiu Poliedru. .java Cerc.spatiu.java /analiza Functie. 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 Sfera. } . . s ın s Ierarhia fi¸ierelor sursa ar fi: s /matematica /surse /geometrie /plan Poligon. public class Poliedru { . avˆnd a ıns˘ a ˆ vedere posibila extindere a aplicatiei cu noi reprezent˘ri de notiuni matemın ¸ a ¸ atice.plan. public class Poligon { . . } // Cerc.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. public class Cerc { .java Matematica.6. ORGANIZAREA FISIERELOR ¸ 153 ˆ acela¸i director ˆ ın s ımpreuna cu un program care s˘ le foloseasca.2. aceast˘ abordare ar fi ineficient˘.

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

In lipsa ¸ a a a a lui. de exemplu a s surse/geometrie/plan.class 155 Crearea acestei structuri ierarhice este facut˘ automat de c˘tre compilator.java ¸i .class Matematica.class Sfera.6. 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.class /algebra Grup. ORGANIZAREA FISIERELOR ¸ Poliedru.java -d clase sau javac -classpath surse surse/Matematica. Pentru aceasta. atˆt a la compilare cˆt ¸i la interpretare trebuie specificat˘ lista de directoare r˘d˘cin˘ a s a a a a .2. a a In directorul aplicatiei (matematica) cre˘m subdirectorul clase ¸i d˘m coa s a manda: javac -sourcepath surse surse/Matematica.java -d clase Optiunea -d specific˘ directorul r˘d˘cin˘ al ierarhiei de clase.class.2. dar numai acestea. vor fi compilate ˆ cascad˘ a a ¸ ın a toate clasele referite de aceasta.class /analiza Functie.java -d clase 6. a Deoarece compil˘m clasa principal˘ a plicatiei. ıntˆ a a a a ceea ce ˆ ınseamna c˘ trebuie s˘ gaseasc˘ fi¸erul surs˘ care o contine. In cazul ˆ care dorim s˘ ın a compil˘m explicit toate fi¸ierele java dintr-un anumit director.class. a a a s a ¸ Similar. ¸ Ins˘ aceast˘ organizare nu este suficient˘ deoarece specific˘ numai partea a a a a final˘ din calea c˘tre fi¸ierele .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˘. de exemplu a a s s /matematica/clase/geometrie/plan/Poligon. putem folosi expresia: javac surse/geometrie/plan/*. fiecare unitate de compilare va fi plasat˘ ˆ acela¸i director cu fi¸ierul s˘u a ın s s a surs˘.

*.spatiu.plan.. ın ın . Aceast˘ list˘ se nume¸te cale de cautare ın a s ¸ a a s (classpath). a a S˘ consider˘m clasa principal˘ a aplicatiei Matematica. s a a a ¸ Implicit.spatiu.Sfera(). ORGANIZAREA CLASELOR ˆ care se g˘sesc fi¸ierele aplicatiei. 6.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 .Grup.java: a a a ¸ import geometrie. geometrie. calea de c˘utare este format˘ doar din directorul curent. } } 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. 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. //. 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. 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. astfel ˆ at compiın a ıncˆ latorul ¸i interpretorul s˘ poat˘ construi calea complet˘ spre clasele aplicatiei. public class Matematica { public static void main(String args[]) { Poligon a = new Poligon().2. import algebra.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.Functie.. import analiza.Sfera = new geometrie.156 CAPITOLUL 6.

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

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

jar geometrie analiza algebra Matematica.jar manifest.class In urma acestei comenzi vom obtine arhiva mate.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. Aceasta ˆ ınseamna c˘ ˆ fiserul Manifest. Din directorul clase vom ın a lansa comanda: jar cvf mate. ˆ care clasa principal˘ era Matematica.txt geometrie analiza algebra Matematica. a .jar.jar”. a s ˆ care vom scrie: ın Main-Class: Matematica • adaug˘m aceast˘ informatie la fi¸ierul manifest al arhivei mate.3.jar a a ın ¸ a a vom obtine urm˘toarea eroare: ”Failed to load Main-Class manifest from ¸ a mate.txt. ˆ care dorim s˘ arhiv˘m clasele aplicatiei descrise mai a ın a a ¸ sus. Acest a a ¸ lucru ˆ vom face ˆ doi pa¸i: ıl ın s • se creeaz˘ un fi¸ier cu un nume oarecare. ARHIVE JAR 159 6.class Pe sistemele Win32. 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˘). platforma Java 2 va asocia extensiile . de exemplu manifest.txt Ambele operatii puteau fi executate ˆ ¸ ıntr-un singur pas: jar cvfm mate.6. S˘ consider˘m a ¸ a a urm˘torul exemplu.java. Dac˘ vom ˆ a ıncerca s˘ lans˘m ˆ executie aceast˘ arhiv˘ prin comanda java -jar mate.3.mf ce se gase¸te ˆ dia ın s ın rectorul META-INF trebuie s˘ ˆ a ınregistr˘m clasa principal˘ a aplicatiei.jar manifest.jar: a a ¸ s jar uvfm mate.jar cu interpretorul Java.

ORGANIZAREA CLASELOR .160 CAPITOLUL 6.

a a ¸ ¸ Aceste clase reprezint˘ tipuri de date reutilizabile. ˆ Java colectiile sunt tratate ˆ a ın ¸ ıntr-o manier˘ a unitar˘. reprezentˆnd ¸ a ¸ a elementul de functionalitate reutilizabil˘. a • Algoritmi: metode care efectueaz˘ diverse operatii utile cum ar fi a ¸ c˘utarea sau sortarea. ¸ a Utilizarea colectiilor ofer˘ avantaje evidente ˆ procesul de dezvoltare a ¸ a ın unei aplicatii. definite pentru obiecte ce implementeaz˘ interfetele a a ¸ ce descriu colectii. ceea ce ˆ ¸ ınseamn˘ a c˘ multimile reprezentate sunt eterogene. a • Implement˘ri: implement˘ri concrete ale interfetelor ce descriu colectii. a s ¸ a Tipul de date al elementelor dintr-o colectie este Object. a ¸ a Incepˆnd cu versiunea 1.1 Introducere O colectie este un obiect care grupeaz˘ mai multe elemente ˆ ¸ a ıntr-o singur˘ a unitate. Cele mai importante sunt: ¸ 161 . multimi matematice.2.Capitolul 7 Colectii ¸ 7. Ace¸ti algoritmi se numesc ¸i polimorfici deoarece ¸ s s pot fi folositi pe implement˘ri diferite ale unei colectii. liste ˆ antuite. etc. 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. tabele de ınl˘ ¸ ¸ dispersie. stive. Prin intermediul colectiilor vom avea acces la diferite tipuri de ¸ date cum ar fi vectori. putˆnd include obiecte de orice tip. 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.

boolean isEmpty(). Astfel. . scopul lor ¸ a ¸ fiind de a permite utilizarea structurilor de date independent de modul lor de implementare.162 CAPITOLUL 7. // Operatii la nivel de element boolean contains(Object element). descriind un a ¸ grup de obiecte numite ¸i elementele sale. Collection modeleaz˘ o colectie la nivelul cel mai general. boolean add(Object element). alte implement˘ri nu. boolean remove(Object element). Platforma Java nu ofer˘ nici o ima plementare direct˘ a acestei interfete. Iterator iterator(). 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.2 Interfete ce descriu colectii ¸ ¸ Interfetele reprezint˘ nucleul mecanismului de lucru cu colectii. altele nu. ¸ public interface Collection { // Metode cu caracter general int size(). Unele implement˘ri ale acestei s a interfete permit existenta elementelor duplicate. 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. ¸ 7. cum ar fi Set sau List. 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. void clear().

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

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

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

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

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

*. cronometrˆnd timpul necesar s a ¸ a realiz˘rii acestora: a Listing 7. COLECTII ¸ • au definit˘ metoda toString. add ( new Integer ( i ) ) .1: Comparare ArrayList .4 Folosirea eficient˘ a colectiilor a ¸ Dup˘ cum am vazut. ¸ • permit crearea de iteratori pentru parcurgere. fiecare interfat˘ ce descrie o colectie are mai multe a ¸a ¸ implement˘ri. System . i ++) lst . nu sunt sincronizate (vezi ”Fire a de executie). for ( int i =0. } . prin realizarea unor compromisuri ˆ ın ¸ ¸ ıntre spatiul ¸ necesar pentru memorarea datelor.168 CAPITOLUL 7. a ¸ ın a S˘ consider˘m un exemplu ce creeaza o list˘ folosind ArrayList. long t2 = System . respectiv a a a LinkedList ¸i execut˘ diverse operatii pe ea. ¸ 7.LinkedList import java . curre ntTimeM illis () . 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. util . out . rapiditatea reg˘sirii acestora ¸i timpul a s necesar actualiz˘rii colectiei ˆ cazul unor modific˘ri. println ( " Add : " + ( t2 . De exemplu. care returneaz˘ o reprezentare ca ¸ir de a a s caractere a colectiei respective.t1 ) ) . public class TestEficienta { final static int N = 100000. i < N . prima fiind ˆ general mult mai folosit˘. public static void testAdd ( List lst ) { long t1 = System . • 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. curre ntTimeM illis () . interfata List este implementat˘ de clasele a ¸ a ArrayList ¸i LinkedList.

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

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

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

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

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

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

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

176 CAPITOLUL 7. COLECTII ¸ .

Capitolul 8 Serializarea obiectelor 8.obiectul poate exista ¸i ˆ s ıntre apelurile programelor care ˆ ıl folosesc. de citire a unui obiect serializat pentru a-i reface starea original˘. Acest s a 177 . serializarea permite salvarea ˆ ıntr-o manier˘ unitar˘ a a a tuturor informatiilor unui obiect pe un mediu de stocare extern programului. prin serializare a s se ˆ ıntelege procesul de scriere/citire a obiectelor. • Permite persistenta obiectelor. 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. apoi. se nume¸te deserializare. Cu alte cuvinte. Tipurile primitive pot fi de asemenea serializate. ¸ Procesul invers. Intr-un cadru mai larg. la relansarea programului. obiectul va fi citit de pe disc ¸i starea lui refacut˘. Acest lucru se realizeaz˘ prin serializarea obiectului ¸i scrierea a s lui pe disc ˆ ınainte de terminarea unui program. ceea ce ˆ ¸ ınseamna c˘ durata de viata a a ¸ unui obiect nu este determinat˘ de executia unui program ˆ care acesta a ¸ ın este definit .

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

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

pentru restaurare.3 Clasa ObjectOutputStream Scrierea obiectelor pe un flux de ie¸ire este un proces extrem de simplu.1. 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.readUTF(). fluxPrimitiv. signatura clasei ¸i valorile tuturor cˆmpurile serializabile ale obiecs a tului. pe lˆng˘ metodele dedicate serializ˘rii obiectelor. 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.writeObject(referintaObiect). Acestea sunt fluxuri de procesare. SERIALIZAREA OBIECTELOR String s = in. 8. sau de pe care va fi restaurat un obiect serializat. .flush(). out. respectiv DataOutput. out. Metodele pentru serializarea obiectelor sunt: • writeObject. fis.1. pentru scriere ¸i s • readObject. s a Clasele ObjectInputStream ¸i ObjectOutputStream implementeaz˘ interfetele s a ¸ ObjectInput. respectiv ObjectOutput care extind DataInput. vor a a a a a exista ¸i metode pentru scrierea/citirea datelor primitive ¸i a ¸irurilor de s s s caractere. ceea ce ˆ ınseamn˘ c˘. Mecanismul implicit de serializare a unui obiect va salva numele clasei obiectului.180 CAPITOLUL 8.close().close(). 8.2 Serializarea obiectelor Serializarea obiectelor se realizeaz˘ prin intermediul fluxurilor definite de a clasele ObjectOutputStream (pentru salvare) ¸i ObjectInputStream s (pentru restaurare). s secventa uzual˘ fiind cea de mai jos: ¸ a ObjectOutputStream out = new ObjectOutputStream(fluxPrimitiv).

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

Clasa ObjectInputStream implementeaz˘ interfata DataInput deci. Trebuie observat c˘ metoda readObject are tipul returnat Object. altfel vor ap˘rea evident exceptii ˆ procesul de desea ¸ ın rializare. double d = in. Citirea informatiilor scrise ˆ exemplul de mai sus se va face astfel: ¸ ın FileInputStream fis = new FileInputStream("test.readObject().readObject().readObject(). fis. Date data = (Date)in. // gresit Date date = (Date)in. boolean b = in.readDouble(). // 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.close(). . String mesaj = (String)in.ser"). ceea a ce ˆ ınseamn˘ c˘ trebuie realizat˘ explicit conversia la tipul corespunzator a a a obiectului citit: Date date = in.readObject().readBoolean(). pe a ¸ lˆng˘ metoda de citire a obiectelor.readObject().readInt().182 CAPITOLUL 8. fluxPrimitiv. 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. ObjectInputStream in = new ObjectInputStream(fis).close().readUTF(). int i = in. String s = in.

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

184 CAPITOLUL 8. // DA // NU // DA // DA public String toString () { return x + " . // Ignorata la serializare Modificatorul static anuleaz˘ efectul modificatorului transient. } } . io . a a static transient int N. static int t =4. a a 8. De exemplu.2. nu particip˘ iar cele marcate cu ’Exceptie’ vor provoca a exceptii de tipul NotSerializableException. transient int y =2. declararea unei s a variabile membre temporare ar trebui facut˘ astfel: a transient private double temp. " + z + " . a a a cele marcate ’NU’. 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˘.1: Modificatorii static ¸i transient s import java . public class Test1 implements Serializable { int x =1. " + y + " . Chiar declarate a a private ˆ cadrul clasei aceste cˆmpuri particip˘ la serializare. // Participa la serializare In exemplele urm˘toare cˆmpurile marcate ’DA’ particip˘ la serializare. Cu a alte cuvinte. ¸ Listing 8. SERIALIZAREA OBIECTELOR In procesul serializ˘rii. transient static int z =3. 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.*.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. variabilele de clas˘ particip˘ obligatoriu la serializare. cum ar fi paa a a ¸ ¸ role. " + t . sau variabile temporare pe care nu are rost s˘ le salv˘m. Acestea sunt cazuri comune atunci ın cˆnd respectivele cˆmpuri reprezint˘ informatii confidentiale.

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

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

2. PERSONALIZAREA SERIALIZARII OBIECTELOR System . dup˘ cum ıns˘ a am spus. In majoritatea cazurilor mecanismul standard este suficient ˆ a.ObjectInputStream stream) throws IOException. 2 8. 0. modifcˆnd starea obiectelor citite astfel ˆ at ele s˘ corespund˘ s a ıncˆ a a . out . println ( " Obiect neserializabil : " + e ) .io. } test ( new Test3 () ) .˘ 8. De asemenea. 4 neserializabil: java. 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.ObjectOutputStream stream) throws IOException private void readObject(java.3. fiind creat pentru cazul general. 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. 3. ad˘ugˆnd ¸i alte informatii necesare a a a s ¸ pentru serializarea unor obiecte. 2 restaurat obiectul: 0. 4 restaurat obiectul: 1.3 Personalizarea serializ˘rii obiectelor a Dezavantajul mecanismului implicit de serializare este c˘ algoritmul pe care a se beazeaz˘. In aceste situatii. 3. o clas˘ poate avea nevoie de mai mult control asupra serializ˘rii. este posibil a s˘ extindem comportamentul implicit. eventual.NotSerializableException: A salvat obiectul: 1. citind informatiile salvate a ın ¸ ¸i.io. ClassNotFoundException Metoda writeObject controleaz˘ ce date sunt salvate iar readObject a controleaz˘ modul ˆ care sunt restaurate obiectele. putem s˘ ˆ ¸ a ınlocuim algoritmul implicit cu unul propriu. particularizat pentru o clas˘ anume. } } 187 Rezultatul acestui program va fi : A fost A fost Obiect A fost A fost salvat obiectul: 1.io.

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

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

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

adaugare () . Dup˘ introducerea unui a a num˘r suficient de mare de angajati ˆ fi¸ier. In aceast˘ situatie trebuie s˘ comua ¸ a nic˘m explicit c˘ cele dou˘ clase sunt compatibile. a a este generat pornind de la diverse informatii ale clasei. salvare () . 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. // Adaugam noi angajati app . Acest num˘r. ¸ 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 plus. } } Problema care se pune acum este urm˘toarea. a ın ad˘ugˆnd pur ¸i simplu cˆmpul: a a s a .3. In cazul ˆ a s a a ın care acestea nu sunt egale. PERSONALIZAREA SERIALIZARII OBIECTELOR 191 // Incarcam angajatii din fisier app .˘ 8. cum ar fi variabilele ¸ sale membre. Acest lucru se realizeaz˘ a a a a prin setarea manual˘ a variabilei serialVersionUID ˆ cadrul clasei dorite. care reprezint˘ un fel de a ¸ a ”amprent˘” a clasei obiectului. citire () . cum ar a fi ad˘ugarea unui nou cˆmp. va determina modificarea num˘rului s˘u de a a a a versiune. Pentru fiecare obiect serializat este calculat automat un num˘r reprezentat pe 64 de biti. clasa Angajat este modifia ¸ ın s cat˘ prin ad˘ugarea unei noi variabil˘ membre care s˘ retina adresa. va fi generat˘ o exceptie de tipul a ¸ InvalidClassException ¸i deserializarea nu va fi f˘cut˘. num˘rul de versiune salvat ˆ forma serializat˘ a ın a va fi reg˘sit ¸i comparat cu noua semn˘tur˘ a clasei obiectului. producˆnd o exceptie de tipul InvalidClassException. La restaurarea unui obiect. denumit serialVersionUID. La a a a a ¸ executia aplicatiei noastre. (dar nu numai) ¸i este salvat ˆ procesul de serializare ˆ s ın ımpreun˘ a cu celelalte date. procedura de citire a angajatilor din fi¸ier nu ¸ ¸ ¸ s va mai functiona. // Salvam angajatii inapoi fisier app . dat poate fi sup˘r˘toare atunci cˆnd modific˘rile aduse clasei nu stric˘ aa a a a compatibilitatea cu vechea versiune. 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. orice modificare semnificativ˘ a clasei.

this . Vom rescrie noua clas˘ Angajat astfel ˆ at s˘ fie compatibil˘ cu cea a ıncˆ a a veche astfel: Listing 8. nume = nume . a a ci s˘-l foloseasc˘ pe cel specificat de noi. this . public Angajat ( String nume . class Angajat implements Serializable { static final long serialVersionUID = 56 534 93 248 680 665 29 7 L . Prezenta variabilei serialVersionUID printre membrii unei clase va in¸ forma algoritmul de serialzare c˘ nu mai calculeze num˘rul de serie al clasei. } public String toString () { return nume + " ( " + salariu + " ) " . Rezultatul va fi: s a a a Angajat: static final long serialVersionUID = 5653493248680665297L. adresa .192 CAPITOLUL 8. La noua ın ın .*. SERIALIZAREA OBIECTELOR static final long serialVersionUID = /* numar_serial_clasa */. A¸adar. adresa = " Iasi " .7: Variant˘ compatibil˘ a clasei Angajat a a import java . parola = parola . io . salariu = salariu . private String parola . } } Aplicatia noastr˘ va functiona acum. int salariu . public int salariu . this . ˆ a rubrica adres˘ nu va fi initializat˘ ¸ a ¸ ıns˘ a ¸ a ˆ nici un fel (va fi null). 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˘. deoarece ea nu exista ˆ formatul original. 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. String parola ) { this . public String nume .

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

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

*. cod = cod . readUTF () . readInt () . } public void writeExternal ( ObjectOutput s ) throws IOException { s .10: Serializare proprie import java . io .9: Serializare implicit˘ a import java . String nume .*. writeUTF ( nume ) . String nume . class Persoana implements Externalizable { int cod .˘ 8. class Persoana implements Serializable { int cod . IOException { nume = s . this . int cod ) { this . int cod ) { this . io .3. public Persoana ( String nume . } } Listing 8. 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. s . cod = s . } } . cod = cod . } public void readExternal ( ObjectInput s ) throws ClassNotFoundException . this . writeInt ( cod ) . nume = nume . public Persoana ( String nume . nume = nume .

close(). ¸ a O metod˘ clone care s˘ realizeze o copie efectiv˘ a unui obiect.toByteArray(). s a ¸ O secventa de forma: ¸ TipReferinta o1 = new TipReferinta().196 CAPITOLUL 8.writeObject(this).4 Clonarea obiectelor Se ¸tie c˘ nu putem copia valoarea unui obiect prin instructiunea de atribuire. In cazul ˆ care exist˘ cˆmpuri a ın a a referinta la alte obiecte. TipReferinta o2 = (TipReferinta) o1. out. ObjectOutputStream out = new ObjectOutputStream(baos).readObject(). TipReferinta o2 = o1. Object ret = in. SERIALIZAREA OBIECTELOR 8. ˆ 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(). Aceasta creeaz˘ un nou obiect ¸i initializeaz˘ toate a ın a s ¸ a variabilele sale membre cu valorile obiectului clonat. in. ByteArrayInputStream bais = new ByteArrayInputStream(buffer). s a a O posibilitate de a face o copie a unui obiect este folosirea metodei clone definit˘ ˆ clasa Object. ObjectInputStream in = new ObjectInputStream(bais). obiectele referite nu vor mai fi clonate la rˆndul lor. byte[] buffer = baos. TipReferinta o1 = new TipReferinta(). out. return ret. } catch (Exception e) { . Deficienta acestei metode este c˘ nu realizeaz˘ duplicarea ˆ ¸ a a ıntregii retele ¸ de obiecte corespunz˘toare obiectului clonat.close().clone(). 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.

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

SERIALIZAREA OBIECTELOR .198 CAPITOLUL 8.

Acest lucru se datoreaz˘. Netscape ¸i IBM. a • Swing .1 Introducere Interfata grafic˘ cu utilizatorul (GUI).Capitolul 9 Interfata grafic˘ cu utilizatorul ¸ a 9. In momentul actual. ın a s Swing se bazeaz˘ pe modelul AWT. exist˘ dou˘ modalit˘¸i de a crea o aplicatie cu a a at ¸ interfata grafic˘ ¸i anume: ¸˘ as • AWT (Abstract Windowing Toolkit) .parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) creat ˆ urma colabor˘rii dintre Sun. Aceasta este o particularizare a interfetei cu utilizatorul (UI).este API-ul initial pus la dispozitie ¸ ¸ ˆ ıncepˆnd cu primele versiuni de Java. ¸ De la aparitia limbajului Java. 199 . extinzˆnd functionalitatea acestuia a a ¸ ¸i ad˘ugˆnd sau ˆ s a a ınlocuind componente pentru dezvoltarea aplicatiilor ¸ GUI. Limbajul Java pune la dispozitie numeroase clase pentru implementarea ¸ diverselor functionalitati UI. ˆ 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. 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. pe de alt˘ parte nevoii de a integra ¸ a mecanismele GUI cu tehnologii ap˘rute ¸i dezvoltate ulterior. cum ar fi Java a s Beans. prin a ¸ care vom ˆ ıntelege conceptul generic de interactiune dintre program ¸i utiliza¸ s tori. pe de o parte dificult˘¸ii legate de a at implementarea notiunii de portabilitate.

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. care poate fi o fereastr˘ ıntˆ s s a . a Crearea obiectelor grafice nu realizeaz˘ automat ¸i afi¸area lor pe ecran. dup˘ care vom face trecerea la Swing. Toate componentele AWT sunt definte de clase proprii ce se gasesc ˆ pachetul java. s 9. etc). butoanele. – Crearea ¸i a¸ezarea componentelor pe suprafata de afi¸are la pozitiile s s ¸ s ¸ corespunz˘toare.200 ˘ CAPITOLUL 9. deoarece va fi simplificat procesul de ˆ ¸elegere a ınt dezvolt˘rii unei aplicatii GUI. listele. clasa Component ın fiind superclasa abstract˘ a tuturor acestor clase. aceasta punˆnd la dispozitie o palet˘ mult mai larg˘ de facilit˘¸i. este de preferat ca aplicatiile Java s˘ fie create folosind tehnologia s ¸ a Swing. bare de defilare. cu exceptia meniurilor care ¸ descind din clasa MenuComponent.awt. ¸ s ¸ a a¸a cum au fost ele definite.awt. INTERFATA GRAFICA CU UTILIZATORUL ¸ A¸adar. liste. Exemple de componente sunt feres strele. etc. ıns˘ ¸ a ¸ reutilizate ˆ Swing. a s s Mai ˆ ai ele trebuie a¸ezate pe o suprafata de afi¸are. a ¸ a In principiu. A¸adar. ın In acest capitol vom prezenta clasele de baz˘ ¸i mecanismul de tratare a as evenimentelor din AWT. ¸ a ¸ – ”Ascultarea” evenimentelor generate de obiecte ˆ momentul ın interactiunii cu utilizatorul ¸i executarea actiunilor corespunz˘toare.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. a Obiectele grafice sunt derivate din Component. 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. controale pentru editarea textelor. a • Functionalitate ¸ – Definirea unor actiuni care trebuie s˘ se execute ˆ momentul cˆnd ¸ a ın a utilizatorul interactioneaz˘ cu obiectele grafice ale aplicatiei.

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 " ) ;

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

Button ( " Est " ) . estul ¸i vestul doar pe vertical˘. EAST ) . BorderLayout . 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˘. add ( new f . a a s a ˆ timp ce centrul se redimensioneaz˘ atˆt pe orizontal˘ cˆt ¸i pe vertical˘. BorderLayout . Celulele tabelului au dimensiuni egale a a iar o component˘ poate ocupa doar o singur˘ celul˘. show () .3. add ( new f .˘ 9. } } Button ( " Nord " ) . add ( new f . GESTIONAREA POZITIONARII ¸ Listing 9.3. SOUTH ) . ı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.*. componentele fiind plasate ˆ celulele tabelului de la stˆnga la ın a dreapta. Button ( " Vest " ) .4 Gestionarul GridLayout Gestionarul GridLayout organizeaz˘ containerul ca un tabel cu rˆnduri ¸i a a s coloane. Button ( " Centru " ) . BorderLayout . dar pot fi modificate ın . NORTH ) . WEST ) . BorderLayout . // Apelul de mai jos poate sa lipseasca f . add ( new f . Num˘rul de linii ¸i a a a a s coloane vor fi specificate ˆ constructorul gestionarului. a 9. ˆ ıncepˆnd cu primul rˆnd. f . awt . pack () .4: Gestionarul BorderLayout import java . CENTER ) . Button ( " Sud " ) . add ( new f . public class TestBorderLayout { public static void main ( String args []) { Frame f = new Frame ( " Border Layout " ) . f . BorderLayout . setLayout ( new BorderLayout () ) .

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

sau s˘ se poat˘ parcurge secvential pachetul. CENTER ) . public class TestCardLayout extends Frame implements ActionListener { Panel tab . 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.6: Gestionarul CardLayout import java .*.*. butoane . O clas˘ Swing care implementeaz˘ un mecansim similar este JTabbedPane. tab . NORTH ) . 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). TextField tf = new TextField ( " Text Field " ) . add ( tab . BorderLayout . a a Listing 9. pack () . tab . show () . setLayout ( new CardLayout () ) .3. La un moment dat. add ( butoane . add ( card1 ) . butoane . numai o singur˘ coma a ponent˘ este vizibil˘ (”cea de deasupra”). Panel butoane = new Panel () . event . tf ) . add ( card2 ) . a a Clasa dispune de metode prin care s˘ poat˘ fi afi¸at˘ o anumit˘ coma a s a a ponent˘ din pachet. tab = new Panel () . Button btn = new Button ( " Button " ) . add ( " Card 2 " . celelalte fiind ascunse. import java . btn ) . tab . add ( " Card 1 " . Button card1 = new Button ( " Card 1 " ) . . ordinea a a a ¸ componentelor fiind intern˘ gestionarului. Button card2 = new Button ( " Card 2 " ) .˘ 9. awt . awt . BorderLayout . public TestCardLayout () { super ( " Test CardLayout " ) .

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

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

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

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

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

add ( lista . control . BorderLayout . orice obiect poate ”consuma” evenimentele generate de o anumit˘ component˘ grafic˘. add ( 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. control . consumator a a de evenimente). add ( new Button ( " Salvare " ) ) . pack () . f . add ( intro . f . } } 9. s Interceptarea evenimentelor generate de componentele unui program se realizeaz˘ prin intermediul unor clase de tip listener (ascult˘tor. f . Componentele care genereaz˘ anumite evenimente se mai a numesc ¸i surse de evenimente. a a a A¸adar. TRATAREA EVENIMENTELOR 219 Panel control = new Panel () . In Java.4. BorderLayout . . ˆ ınchiderea sau redimensionarea unei ferestre. 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.9. modia ficarea textului ˆ ıntr-un control de editare. add ( new Button ( " Iesire " ) ) . f . NORTH ) . etc. f . show () . Exemple de evenimente sunt: ap˘sarea unui buton. SOUTH ) . BorderLayout . CENTER ) .

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

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

} } public class TestEvent1 { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test Event " ) . INTERFATA GRAFICA CU UTILIZATORUL ¸ class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ) . Button b2 = new Button ( " Cancel " ) . Button b1 = new Button ( " OK " ) . addActionListener ( listener ) . b1 . // instanta a clasei Ascultator . definita mai jos } } class Ascultator implements ActionListener { private Fereastra f . // Ambele butoane sunt ascultate de obiectul listener . setTitle ( " Ati apasat " + e . public Ascultator ( Fereastra f ) { this . getActionCommand () ) . Mai simplu ar fi fost s˘ folosim chiar clasa Fereastra pentru a a a trata evenimentele produse de componentele sale. f = f . addActionListener ( listener ) . add ( b1 ) . 100) . 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˘. Vom modifica putin ¸i ¸ s . setSize (200 .222 ˘ CAPITOLUL 9. setLayout ( new FlowLayout () ) . b2 . Ascultator listener = new Ascultator ( this ) . add ( b2 ) . } } Nu este obligatoriu s˘ definim clase speciale pentru ascultarea evenia mentelor. show () . f . } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e ) { f .

10: Tratarea evenimentelor ˆ ferestr˘ ın a import java . setTitle ( " Ati apasat OK de " + n + " ori " ) . awt .9.metoda getSource. event . } } } 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 . class Fereastra extends Frame implements ActionListener { Button ok = new Button ( " OK " ) . this . exit .*. 100) .*. setLayout ( new FlowLayout () ) . addActionListener ( this ) . f . awt . // Terminam aplicatia if ( e . exit (0) . add ( exit ) . setSize (200 . getSource () == exit ) System . Listing 9.4. ok . import java . add ( ok ) . addActionListener ( this ) . // Ambele butoane sunt ascultate in clasa Fereastra // deci ascultatorul este instanta curenta : this } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e ) { if ( e . Button exit = new Button ( " Exit " ) . getSource () == ok ) { n ++. show () . public Fereastra ( String titlu ) { super ( titlu ) . } } . int n =0.

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

metodele puse la dispozitie ¸i care trebuie implementate de ¸a s c˘tre clasa ascult˘tor. pentru ¸ a a fiecare interfat˘. a a . de exemplu. TRATAREA EVENIMENTELOR 225 Urm˘torul tabel prezint˘ componentele AWT ¸i tipurile de evenimente a a s generate.9. eveni¸ a mentele generate de o superclas˘. ˆ situatia cˆnd tratarea acestora nu ne intereseaz˘ ¸i dorim s˘ ¸ ın ¸ a a s a trat˘m doar evenimente de tip click. Tabelul de mai jos prezint˘. Evident. 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. se vor reg˘si ¸i pentru a a s toate subclasele sale. prezentate sub forma interfetelor corespunz˘toare. exist˘ dou˘ interfete ¸ a s a a a a a ¸ asociate MouseListener ¸i MouseMotionListener. cum ar fi Component. a Orice clas˘ care trateaz˘ evenimente trebuie s˘ implementeze obligatoriu a a a metodele interfetelor corespunz˘toare. 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.4.

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. ˆ cadrul uneia din a ın metodele de mai sus. Toate tipurile de evenimente mo¸tenesc ¸ ın ¸a s metoda getSource care returneaz˘ obiectul responsabil cu generarea evenia mentului. ın a ¸ a . care este sursa evenimentului pe care ˆ trat˘m penıl a tru a putea reactiona ˆ consecint˘.226 ˘ CAPITOLUL 9. In cazul ˆ care dorim s˘ diferentiem doar tipul componentei surs˘. este necesar s˘ putem afla.

TRATAREA EVENIMENTELOR putem folosi operatorul instanceof. } } 227 Pe lˆng˘ getSource.getSource()..9. returneaz˘ eticheta butonului care a fost ap˘sat. mai ales atunci cˆnd nu ne intereseaz˘ a a a decˆt o singura metod˘ a interfetei. chiar a ¸a dac˘ nu specific˘ nici un cod pentru unele dintre ele.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.4. if (btn == ok) { // A fost apasat butonul ’ok’ } . public void actionPerformed(ActionEvent e) { Object sursa = e. Sunt ˆ a situatii cˆnd a a ıns˘ ¸ a acest lucru poate deveni sup˘rator.. Astfel de a a particularit˘¸i vor fi prezentate mai detaliat ˆ sectiunile dedicate fiecˆrei at ın ¸ a componente ˆ parte. ın 9. 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 . implicit.4. obiectele ce descriu evenimente pot pune la dispozitie a a ¸ ¸i alte metode specifice care permit aflarea de informatii legate de evenimens ¸ tul generat. ActionEvent contine metoda getActionCommand ¸ care. Aceasta ˆ ¸ a ınseamn˘ c˘ trebuie a a s˘ implementeze obligatoriu toate metodele definite de acea interfat˘. if (sursa instanceof Button) { // A fost apasat un buton Button btn = (Button) sursa. if (tf == nume) { // A fost editata componenta ’nume’ } .. De exemplu. } if (sursa instanceof TextField) { // S-a apasat Enter dupa editarea textului TextField tf = (TextField) sursa..

INTERFATA GRAFICA CU UTILIZATORUL ¸ marcat cu ’x’ din coltul dreapta sus ¸i nici cu combinatia de taste Alt+F4. ˆ care specific˘m ce trebuie f˘cut atunci cˆnd a ın a a a utilizatorul doreste s˘ ˆ a ınchid˘ fereastra. 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 . awt . } 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 " ) .*. event . ˆ cazul cˆnd ın a este vorba de fereastra principal˘ a aplicatiei. sau System.11: Implementarea interfetei WindowListener ¸ import java . Singura metod˘ care ne interea seaz˘ este windowClosing.exit pentru terminarea programului. class Fereastra extends Frame implements WindowListener { public Fereastra ( String titlu ) { super ( titlu ) . awt . Listing 9.228 ˘ CAPITOLUL 9. Pentru a evita scrierea inutil˘ a a a . show () .*. addWindowList ener ( this ) . exit (0) . this . f . } } Observati c˘ trebuie s˘ implement˘m toate metodele interfetei. chiar dac˘ ¸ a a a ¸ a nu scriem nici un cod pentru unele dintre ele. ¸ 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. import java .

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

} } 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. va crea o metod˘ a clasei respective. s a a a Vom vedea ˆ a c˘ acest dezavantaj poate fi eliminat prin folosirea unei clase ıns˘ a anonime.se oberv˘ c˘ o interfat˘ XXXListener are un adaptor de tipul XXXAdapter. 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. pur ¸i simplu. iar ¸ a a a a a ın clasele anonime sunt clase interne folosite pentru instantierea unui singur ¸ obiect de un anumit tip. ı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. ¸ 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 ¸ . 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.230 ˘ CAPITOLUL 9.

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

face vizibil˘ fereastra.face fereastra invizibil˘ f˘r˘ a o distruge ˆ a. Acestea sunt descrise de clase derivate din Window. o fereastr˘ nou creat˘ nu este a a a vizibil˘. a ¸ Metodele mai importante ale clasei Window. s O aplicatie Java cu intefat˘ grafic˘ va fi format˘ din una sau mai multe ¸ ¸a a a ferestre. 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. Implicit. } } public class TestAdapters { public static void main ( String args []) { Fereastra f = new Fereastra ( " Test adaptori " ) . show () .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. f . una dintre ele fiind numit˘ fereastra principal˘. INTERFATA GRAFICA CU UTILIZATORUL ¸ this . a • hide . pentru a redeveni a aa ıns˘ vizibila se poate apela metoda show. getKeyChar () + " " ) .232 ˘ CAPITOLUL 9. . setText ( " Ati tastat : " + e . addKeyListener ( new KeyAdapter () { public void keyTyped ( KeyEvent e ) { // Afisam caracterul tastat label .5. } }) .5 Folosirea ferestrelor Dup˘ cum am v˘zut suprafetele de afi¸are ale componentelor sunt extensii a a ¸ s ale clasei Container. sunt date de mai jos: • show . } } 9. a a 9. care sunt de altfel mo¸tenite s de toate subclasele sale. O categorie aparte a acestor containere o reprezint˘ a ferestrele. cele mai utilizate fiind Frame ¸i Dialog.

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

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. addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { dispose () . Structura general˘ a unei ferestre este descris˘ de clasa Fereastra din a a exemplul de mai jos: Listing 9. import java .*. mai uzual. // inchidem fereastra // sau terminam aplicatia System . awt .show(). // Tratam evenimentul de inchidere a ferestrei this . } }) . ˆ momentul ˆ care fereastra este creat˘ dar nici o compoın ın a nent˘ grafic˘ nu este ad˘ugat˘. class Fereastra extends Frame implements ActionListener { // Constructorul public Fereastra ( String titlu ) { super ( titlu ) . 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.234 ˘ CAPITOLUL 9. a Se observ˘ de asemenea c˘ butonul de ˆ a a ınchidere a ferestrei nu este functional. ¸ Tratarea evenimentelor ferestrei se face prin implementarea interfetei WindowListener ¸ sau. ¸ Din acest motiv.*. event . } } Gestionarul de pozitionare implicit al clasei Frame este BorderLayout. awt .14: Structura general˘ a unei ferestre a import java . INTERFATA GRAFICA CU UTILIZATORUL ¸ } public class TestFrame { public static void main(String args[]) { Fereastra f = new Fereastra("Titlul ferestrei"). exit (0) . prin folosirea unui adaptor de tip WindowAdapter. . f. maximizare sa s ¸i ˆ s ınchidere.

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

String titlu. Cˆnd fer¸a aa a eastra p˘rinte este distrus˘ sunt distruse ¸i ferestrele sale de dialog. subclas˘ direct˘ a clasei Window. String titlu. ferestrele de dialog nu au o existent˘ de sine st˘t˘toare.236 ˘ CAPITOLUL 9. de selectare a unei optiuni. boolean modala) Dialog(Frame parinte. boolean modala) Dialog(Dialog parinte) Dialog(Dialog parinte. etc. mesaje de avertizare. a Ferestrele de dialog pot fi de dou˘ tipuri: a • modale: care blocheaz˘ accesul la fereastra parinte ˆ momentul dea ın schiderii lor. 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 exemplu. INTERFATA GRAFICA CU UTILIZATORUL ¸ • setResizable . de alegere a unui fi¸ier. 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.5.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. Acestea se numesc ferestre ¸ de dialog sau casete de dialog ¸i sunt implementate prin intermediul clasei s Dialog. s Implicit. numit˘ ¸i fereastra p˘rinte. Cu alte a a as a cuvinte. String titlu) Dialog(Dialog parinte. s ¸ • nemodale: care nu blocheaz˘ fluxul de intrare c˘tre fereastra p˘rinte a a a .stabile¸te dac˘ fereastra poate fi redimenionat˘ de utis a a lizator. dialogul de c˘utare a unui cuvˆnt ˆ a a ıntr-un fi¸ier. o fereastr˘ de dialog este nemodal˘ ¸i invizibil˘. Constructorii clasei Dialog a s s sunt: Dialog(Frame parinte) Dialog(Frame parinte. cum ar fi ferestrele de introducere a unor date. boolean modala) . String titlu) Dialog(Frame parinte. ˆ a exist˘ cona as a ıns˘ a structori care s˘ specifice ¸i ace¸ti parametri. 9. etc.

”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 .*.9. awt . awt . a S˘ cre˘m. Fereastra principal˘ a aplicatiei va fi p˘rintele casetei s a a de dialog. event . import java . • 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. iar fereastra de dialog s˘ ofere metode publice prin care a datele introduse s˘ fie preluate din exterior. FOLOSIREA FERESTRELOR 237 Parametrul ”p˘rinte” reprezint˘ referinta la fereastra p˘rinte. Deschiderea ferestrei de dialog se va face la ap˘sarea unui buton al a ferestrei principale numit ”Schimba titlul”. Cele dou˘ ferestre vor ar˘ta ca a a ˆ imaginile de mai jos: ın Fereastra principal˘ a Fereastra de dialog Listing 9.15: Folosirea unei ferestre de dialog import java .*.valoarea a a a implicit˘). a Crearea unei ferestre de dialog este relativ simpla ¸i se realizeaz˘ prin s a derivarea clasei Dialog. 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. pentru ca aceasta din urm˘ s˘ poat˘ folosi datele introduse (sau a a a a optiunea specificata) ˆ caseta de dialog. va primi ¸irul de caractere introdus ¸i ˆ va modifica titlul ca fiind s s ısi acesta. Comunicarea dintre fereastra de dialog ¸i fereastra s sa p˘rinte.5. de exemplu. o fereastr˘ de dialog modal˘ pentru introducerea a a a a unui ¸ir de caractere. // Fereastra principala class FerPrinc extends Frame implements ActionListener { .

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

FOLOSIREA FERESTRELOR cancel = new Button ( " Cancel " ) . panel .4 Clasa FileDialog Pachetul java. getText () . a ¸ Constructorii clasei sunt: FileDialog(Frame parinte) . dar forma ˆ care vor fi afi¸ate este specific˘ platformei pe care ın s a ruleaz˘ aplicatia. SOUTH ) . cancel .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. Instantele acestei clase au un s a ¸ comportament comun dialogurilor de acest tip de pe majoritatea platformelor de lucru. text .5. else raspuns = null . panel . BorderLayout . add ( cancel ) . add ( panel . f . derivat˘ din Dialog. } } 239 9.9. show () . pack () . addActionListener ( this ) . } public void actionPerformed ( ActionEvent e ) { Object sursa = e . if ( sursa == ok || sursa == text ) raspuns = text . show () . } } // Clasa principala public class TestDialog { public static void main ( String args []) { FerPrinc f = new FerPrinc ( " Fereastra principala " ) . addActionListener ( this ) . add ( ok ) . dispose () . getSource () .5. ok . addActionListener ( this ) .

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

show () . getFile () ) . System . f . java " ) . Button b = new Button ( " Alege fisier " ) . out . add (b .5. FOLOSIREA FERESTRELOR public void windowClosing ( WindowEvent e ) { System . b . setDirectory ( " . } 241 public void actionPerformed ( ActionEvent e ) { FileDialog fd = new FileDialog ( this . String numeFis ) { return ( numeFis . LOAD ) . // Specificam filtrul fd .9. java " ) ) . // Stabilim numele implicit fd . CENTER ) . BorderLayout . addActionListener ( this ) . } }) . println ( " Fisierul ales este : " + fd . ¸ ¸a a . // Afisam fereastra de dialog ( modala ) fd . endsWith ( " . } } public class TestFileDialog { public static void main ( String args []) { FerPrinc f = new FerPrinc ( " Fereastra principala " ) . " ) . } }) . show () . exit (0) . // Stabilim directorul curent fd . pack () . " Alegeti un fisier " . setFile ( " TestFileDialog . } } 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˘. setFilenameFilter ( new FilenameFilter () { public boolean accept ( File dir . FileDialog .

comutatoare sau alte ¸ meniuri (submeniuri).242 ˘ CAPITOLUL 9. La rˆndul lor. La rˆndul a lor. 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. acestea pot contine obiecte de tip MenuItem. INTERFATA GRAFICA CU UTILIZATORUL ¸ 9. O fereastr˘ poate avea un singur meniu fix. CheckBoxMenuItem. 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. Meniul Edit contine la rˆndul lui alt meniu (submeniu) s ¸ a Options. articolul Undo ¸i dou˘ comutatoare Bold ¸i Italic. Un obiect de tip MenuBar contine obiecte ¸ ¸ de tip Menu. 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. ¸ a a aceste meniuri contin articole ce pot fi selectate. 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. In modelul AWT obiectele care reprezint˘ bare de meniuri sunt reprezena tate ca instante al clasei MenuBar. Prin abuz de s a s limbaj. care sunt de fapt meniurile derulante propriu-zise. vom referi uneori bara de meniuri a unei ferestre ca fiind meniul ferestrei. ¸ dar ¸i alte obiecte de tip Menu (submeniuri). s . a componentele unui meniu reprezint˘ instante ale unor clase derivate din sua ¸ perclasa abstract˘ MenuComponent.6 Folosirea meniurilor Spre deosebire de celelalte obiecte grafice care deriv˘ din clasa Component. Aceast˘ exceptie este facut˘ deoarece a a ¸ a unele platforme grafice limiteaz˘ capabilit˘¸ile unui meniu.

pentru a lega bara de meniuri la a a o anumit˘ fereastra trebuie apelat˘ metoda setMenuBar din clasa Frame. Cel mai adesea. dintre care amintim getName. getFont. .6. 9. a a // Crearea barei de meniuri MenuBar mb = new MenuBar(). cu sintaxa ¸i semnificatiile uzuale. adaptˆnd conceptul de bar˘ de meniuri la platforma a a curent˘ de lucru. setName. FOLOSIREA MENIURILOR 243 Pentru a putea contine un meniu. MenuComponent contine metode cu carac¸ ter general. o component˘ trebuie s˘ implementeze ¸ a a interfata MenuContainer. fiind similar˘ celeilalte a superclase abstracte Component. meniurile sunt ata¸ate fere¸ s strelor. setFont. mai precis obiectelor de tip Frame. Ata¸area unei bare de meniuri la o fereastr˘ se face prin s a metoda addMenuBar a clasei Frame. Dup˘ cum am mai spus. acestea implementˆnd interfat˘ a ¸a MenuContainer. s ¸ Clasa MenuBar permite crearea barelor de meniuri asociate unei ferestre cadru de tip Frame.9.6.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.

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

add ( fisier ) . 100) . editare .6.*. fisier . MenuBar mb = new MenuBar () . addSeparator () . addSeparator () . add ( new MenuItem ( " Copy " ) ) . add ( editare ) . add ( optiuni ) . add ( new MenuItem ( " Undo " ) ) . Menu fisier = new Menu ( " File " ) . show () .9. add ( new MenuItem ( " Cut " ) ) . optiuni . fisier . mb . add ( new CheckboxMenuItem ( " Bold " ) ) . f . awt .*. add ( new MenuItem ( " Exit " ) ) . 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. setMenuBar ( mb ) . fisier . public class TestMenu { public static void main ( String args []) { Frame f = new Frame ( " Test Menu " ) . } } . import java . Menu optiuni = new Menu ( " Options " ) . awt . add ( new CheckboxMenuItem ( " Italic " ) ) . setSize (200 .17: Crearea unui meniu import java . f . add ( new MenuItem ( " Close " ) ) . event . add ( new MenuItem ( " Open " ) ) . editare . optiuni . Menu editare = new Menu ( " Edit " ) . fisier . editare . editare . f . optiuni . mb . add ( new MenuItem ( " Paste " ) ) . editare .

a a ın a ˆ ıntocmai ca pe orice component˘. A¸adar. 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. 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. ambele cu ¸ s a ıi a ¸ acela¸i nume. tratarea evenimentelor generate de obiecte de tip MenuItem este s identic˘ cu tratarea butoanelor.*. a a s Obiectele de tip CheckboxMenuItem tip se g˘sesc ˆ a ıntr-o categorie comun˘ a cu List. 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. tratarea evenimentului corespunz˘tor ap˘sarii butonului. CheckBox. Fiec˘rui meniu ˆ putem asocia un obiect receptor a ıi diferit.*. A¸adar. event . toate implementˆnd interfata ItemSelectable a ¸ ¸i deci tratarea lor va fi f˘cut˘ la fel.18: Tratarea evenimentelor unui meniu import java . ceea ce face posibil ca unui buton de pe a suprafata de afi¸are s˘ ˆ corespund˘ o optiune dintr-un meniu.6. Choice.SELECTED ın a ¸i ItemEvent. CheckboxMenuItem check = new CheckboxMenuItem ( " Check me " ) . import java . s Listing 9. a respectiv addItemListener. awt . . MenuBar mb = new MenuBar () . awt . INTERFATA GRAFICA CU UTILIZATORUL ¸ 9. ceea ce u¸ureaz˘ munca ˆ cazul ˆ care ierarhia de meniuri este coms a ın ın plex˘. public class TestMenuEvent extends Frame implements ActionListener .DESELECTED. Menu test = new Menu ( " Test " ) .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. fie ItemEvent a pentru comutatoarele CheckboxMenuItem. respec¸ s tiv itemStatChanged. ItemListener { public TestMenuEvent ( String titlu ) { super ( titlu ) . Tipul de operatie selectare / deselectare s a a este codificat ˆ evenimentul generat de cˆmpurile statice ItemEvent.246 ˘ CAPITOLUL 9. folosind metodele addActionListener. sau s a a alegerii optiunii.

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

popup. De obicei. Argumentul ”origine” reprezint˘ componenta fat˘ de a ¸a originile c˘reia se va calcula pozitia de afi¸are a meniului popup. Aceasta este isPopupTrigger ¸i este s definit˘ ˆ clasa MouseEvent.. vom crea un meniu de contex pe care ˆ vom activa ıl la ap˘sarea butonului drept al mouse-ului pe suprafata ferestrei principale.add(new MenuItem("New")). trebuie s˘ le definim pe toate ¸i.remove(popup1). a ¸ s reprezint˘ instanta ferestrei ˆ care se va afi¸a meniul. . Metodele de ad˘ugare a articolelor unui meniu de context sunt a a mo¸tenite ˆ s ıntocmai de la meniurile fixe. 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.add(new MenuItem("Edit")). 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. pentru a avea s a acces rapid la meniu. popup. In cazul cˆnd avem mai multe meniuri popup pe care vrem s˘ a a le folosim ˆ ıntr-o fereastr˘. Pozitionarea ¸i afi¸area meniului este ˆ a a ın ¸ s s ıns˘ responsabilitatea programatorului. 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.add(popup1).add(popup2). fereastra. popup. int x. vom ”rupe” leg˘tura ˆ a ıntre fereastr˘ ¸i meniu prin as instructiunea remove: ¸ fereastra. popup. PopupMenu popup = new PopupMenu("Options"). . int y) ¸i este de obicei rezultatul ap˘sarii unui buton al mouse-ului. a a a ıl Dup˘ ˆ a ınchiderea acestuia. fereastra. a ¸ Tratarea evenimentelor generate de un meniu popup se realizeaz˘ identic ca a pentru meniurile fixe.addSeparator()..add(new MenuItem("Exit")).248 ˘ CAPITOLUL 9. la un moment a a s dat.show(Component origine. In exemplul de mai jos. vom ad˘uga ferestrei meniul corespunz˘tor dup˘ care ˆ vom face vizibil. Deoarece interactiunea a ¸ ın s ¸ cu mouse-ul este dependent˘ de platforma de lucru. Afi¸area meniului de context se face prin metoda show: s popup.

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

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

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

120) . BOLD . 70) . pack () . } }) . this . Button b1 = new Button ( " OK " ) . class Fereastra extends Frame implements ActionListener { public Fereastra ( String titlu ) { super ( titlu ) . setBounds (30 .*. INTERFATA GRAFICA CU UTILIZATORUL ¸ f . add ( centru . 14) ) . b1 . awt . setFont ( new Font ( " Arial " . import java . addWindowList ener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { System .21: Folosirea clasei Button import java . exit (0) . b1 .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 . 50 . Textul etichetei este format dintr-o ¸ s singur˘ linie. setLayout ( null ) . a Listing 9. } } 9. event . CENTER ) .*. f . show () . Font .7. awt .252 ˘ CAPITOLUL 9. 30 . BorderLayout . . setSize (200 .

println ( e ) . System . getActionCommand () . b2 . Este folosit pentru a prelua o anumit˘ optiune de a ın a a ¸ la utilizator.7. orange ) . blue ) . . addActionListener ( this ) . 70 . FOLOSIREA COMPONENTELOR AWT b1 . b2 . add ( b1 ) . } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e ) { String command = e .9. f . Button b2 = new Button ( " Cancel " ) . setBounds (100 . else if ( command . equals ( " OK " ) ) setTitle ( " Confirmare ! " ) . } } 253 9. if ( command . b1 . setForeground ( Color . 50) . b2 . addActionListener ( this ) . Actiunea a ın a a a a ¸ utilizatorului asupra unui comutator ˆ trece pe acesta ˆ starea complemenıl ın tar˘ celei ˆ care se g˘sea.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). add ( b2 ) . equals ( " Cancel " ) ) setTitle ( " Anulare ! " ) . setBackground ( Color . } } public class TestButton { public static void main ( String args []) { Fereastra f = new Fereastra ( " Button " ) . out .7. show () . 30 .

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

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

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

} } 257 9.7. getLabel () ) . show () . setSize (200 .5 Clasa Choice Un obiect de tip Choice define¸te o list˘ de optiuni din care utilizatorul s a ¸ poate selecta una singur˘. addItemListener ( this ) . a a ¸ . La un moment dat. getS e lec ted Che ck box () . f . add ( cbx3 ) .7. setText ( cbx . din ˆ a ıntreaga list˘ doar o sina gur˘ optiune este vizibil˘. } } public class TestCheckboxGroup { public static void main ( String args []) { Fereastra f = new Fereastra ( " CheckboxGroup " ) . if ( cbx != null ) label2 . cbx2 . pentru ca utilizatorul s˘ a a poat˘ selecta o anumit˘ optiune. cbx3 . cea selectat˘ ˆ momentul curent. addItemListener ( this ) . 200) .9. 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. cbx1 . } // Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e ) { Checkbox cbx = cbg . FOLOSIREA COMPONENTELOR AWT add ( cbx2 ) .

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

Toate ıncˆ a a a ¸ elementele listei sunt vizibile ˆ limita dimensiunilor grafice ale componentei. this .*.9. awt . event . ın Listing 9. addWindowListener ( new WindowAdapter () { .7. awt .7. } } 259 9. public Fereastra ( String titlu ) { super ( titlu ) . private List culori .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.*. import java . FOLOSIREA COMPONENTELOR AWT } } } public class TestChoice { public static void main ( String args []) { Fereastra f = new Fereastra ( " Choice " ) . f . show () .25: Folosirea clasei List import java . class Fereastra extends Frame implements ItemListener { private Label label .

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

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

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

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

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

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

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

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

268 ˘ CAPITOLUL 9. INTERFATA GRAFICA CU UTILIZATORUL ¸ .

maximizare. 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.Deseneaz˘ o component˘. 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) . Este o metod˘ a a a supradefinit˘ de fiecare component˘ ˆ parte pentru a furniza reprezentarea a a ın sa grafic˘ specific˘. redimensionare a suprafetei de ¸ ¸ afi¸are.Actualizeaz˘ starea grafic˘ a unei coma a ponente. s a • la operatii de minimizare. s • ca r˘spuns al unei solicit˘ri explicite a programului. s 269 . Aceast˘ a a desenare include componentele standard folosite ˆ aplicatie precum ¸i cele ın ¸ s definite de c˘tre programator.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˘. Actiunea acestei metode se realizeaz˘ ˆ trei pa¸i: ¸ a ın s 1. s a • void update(Graphics g) . 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. ¸terge componenta prin supradesenarea ei cu culoarea fundalului.Capitolul 10 Desenarea 10.

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

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

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

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

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

s – originii coordonatelor suprafetei de desenare.2. enumer˘m aceste a propriet˘¸i ¸i metodele asociate lor din clasa Graphics. 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. Desenarea figurilor geometrice se realizeaz˘ cu urm˘toarele metode: a a . 20). ın care permit desenarea de figuri geometrice ¸i texte. 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.2 Primitive grafice Prin primitive grafice ne vom referi ˆ continuare la metodele clasei Graphics. Textul va fi desenat s s ¸ a cu fontul ¸i culoarea curente ale contextului grafic. CONTEXTUL GRAFIC DE DESENARE – culorii ¸i fontului curente cu care se face desenarea.10. ¸ ın – modului de desenare. ¸ – suprafetei ˆ care sunt vizibile componentelor desenate. In continuare. etc. 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. y=20. s // Desenam la coordonatele x=10. 10. 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. 275 10. font.2.2.1 Propriet˘¸ile contextului grafic at La orice tip de desenare parametrii legati de culoare. drawString("Hello".

a Cei mai importanti parametri ce caracterizeaz˘ un font sunt: ¸ a • Numele fontului: Helvetica Bold. Arial. fie din Graphics. etc. cum ar a a a fi Label. a a at Prima dintre acestea este s˘ folosim o component˘ orientat˘-text. pentru a scrie un text pe ecran avem dou˘ posibilit˘¸i. Arial Bold Italic. • Dimensiunea fontului: ˆ altimea sa. . etc. 10. Indiferent de modalitatea aleas˘. adic˘ ”umplut” cu culoarea curent˘ a contextului de desenare. putem a specifica prin intermediul fonturilor cum s˘ arate textul respectiv. a a ˆ timp ce metodele care ˆ ın ıncep cu ”draw” vor desena doar conturul figurii respective. acest lucru a realizˆndu-se prin metoda setFont fie din clasa Component. cum ar fi drawString. • Familia din care face parte fontul: Helvetica. ın˘ ¸ • Stilul fontului: ˆ ıngro¸at (bold). 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.276 Figur˘ geometric˘ a a Linie CAPITOLUL 10.3 Folosirea fonturilor Dup˘ cum vazut. iar a doua s˘ apel˘m la metodele clasei Graphics de desenare a a a textelor. ˆ s ınclinat (italic).

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

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

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. s ın ¸ s ınalt ın Pentru aceasta este folosit˘ clasa FontMetrics.3. at at • Distanta ˆ ¸ ıntre linii (”leading”): distanta optim˘ ˆ ¸ a ıntre dou˘ linii de text a scrise cu acela¸i font. • Ascendentul: distanta ˆ ¸ ıntre linia de baz˘ ¸i linia de ascendent˘. as ¸a • Descendentul: distanta ˆ ¸ ıntre linia de baz˘ ¸i linia de descendent˘. cu alte cuvinte despre dimensiunile ˆ pixeli ale caracın terelor sale. trebuie s˘ calcul˘m pozitiile s a a ¸ lor de afi¸are ˆ functie de lungimea ¸i ˆ ¸imea ˆ pixeli a celorlalte texte.10. 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. 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. Utilitatea principal˘ a acestei clase const˘ ˆ faptul c˘ permite a a ın a pozitionarea precis˘ a textelor pe o suprafat˘ de desenare. FOLOSIREA FONTURILOR 279 10. a¸ ¸ a Figura de mai jos prezint˘ o imagine reprezentativ˘ asupra metricii unui a a font: . A¸adar. indiferent de fontul ¸ a ¸a folosit de acestea. In momentul ˆ care avem de afi¸at a a ın s mai multe ¸iruri consecutiv. sau unele sub altele.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. un obiect de tip FontMetrics ˆ s ıncapsuleaz˘ informatii despre a ¸ metrica unui font. as ¸a • L˘¸imea: l˘¸imea unui anumit caracter din font.3. s • In˘ltimea: distanta dintre liniile de baz˘ (leading+ascent+descent).

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

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

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

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

0. setColor ( Color . 0). import java . 8-15 verde. class Culoare extends Canvas { public Color color = new Color (0 . black ) . DESENAREA // Exemple de folosire a constructorilor: Color alb = new Color(255.5: Folosirea clasei Color import java . 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. Dimension canvasSize = new Dimension (150 . 0. 0 . 255). . 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. public void paint ( Graphics g ) { g .*. 255) . 0 . awt . Color negru = new Color(0. Color rosuTransparent = new Color(255.*. 128). 0.284 CAPITOLUL 10. 50) . ¸ ¸ a Aplicatia va ar˘ta astfel: ¸ a Listing 10. event . 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˘. Color rosu = new Color(255. 0. 0). 255. awt .

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

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

FOLOSIREA IMAGINILOR 287 In AWT este posibil˘ folosirea imaginilor create extern ˆ format gif sau a ın jpeg. String fisier) getImage(String fisier) Pentru a obtine un obiect de tip Toolkit se va folosi metoda getDefaultToolkit.ro/~acf/poza.getImage( new URL("http://www. a 10.5. 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. 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. Image image1 = toolkit. ¸ ca ˆ exemplul de mai jos: ın Toolkit toolkit = Toolkit. . Afi¸area propriu-zis˘ ˆ s a ıntr-un context grafic.infoiasi.1 Afi¸area imaginilor s Afi¸area unei imagini presupune realizarea urm˘toarilor doi pa¸i: s a s 1. Metodele pentru ˆ arcarea unei imagini dintr-un fi¸ier se g˘sesc ınc˘ s a ˆ clasele Applet ¸i Toolkit.getDefaultToolkit().10.getImage("poza.5.gif"). 2. Image image2 = toolkit. fie aflat la o anumit˘ adres˘ Web s a a a (URL). 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˘.gif")). Orice imagine va fi reprezentat˘ ca o instant˘ a clasei Image.

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

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. int w. int x. dup˘ care red˘ imediat conınc˘ s a a trolul apelantului.10. f˘r˘ interventia programatorului. Aceste informatii pot fi aflate prin intermediul constantelor ¸ definite de interfat˘: ¸a . Intregul f lags furnizeaz˘ informatii despre starea ¸ a ¸ transferului. ¸ a a a ce va fi apelat˘ periodic de firul de executie (creat automat) care se ocup˘ a ¸ a cu ˆ arcarea imaginii. Formatul acestei metode este: ınc˘ boolean imageUpdate (Image img. Acest mecanism este realizat prin intermediul interfetei s a ¸ ImageObserver. 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˘. a Interfata ImageObserver are o singur˘ metod˘ numit˘ imageUpdate. 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. implementat˘ de clasa Component ¸i deci de toate compoa s nentele. 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˘.5. int y. ¸ a 10. 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.5. 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.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. pˆn˘ la ın ın ¸ a a afi¸area sa complet˘. Ca urmare. FOLOSIREA IMAGINILOR 289 Metoda drawImage returneaz˘ true dac˘ imaginea a fost afi¸at˘ ˆ ˆ a a s a ın ıntregime ¸i false ˆ caz contrar. In sectiunea urm˘toare vom detalia acest aspect. int flags. 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˘.

int flags. 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. } De asemenea. int y. se observ˘ c˘ metodele clasei Image pentru determinarea a a dimensiunilor unei imagini au ca argument un obiect de tip ImageObserver. int w. int h) { // Desenam imaginea numai daca toti bitii sunt disponibili if (( flags & ALLBITS) != 0) repaint(). Aceasta va fi apelat˘ apelat˘ asincron s a a de fiecare dat˘ cˆnd sunt disponibili noi pixeli. DESENAREA Inc˘rcarea imaginii a fost ˆ a ıntrerupt˘. a a public boolean imageUpdate(Image img. . atunci argumentul observer a al metodelor referitoare la imagini va fi this.290 ABORT CAPITOLUL 10. int x. // Daca sunt toti bitii nu mai sunt necesare noi update-uri return ( (flags & (ALLBITS | ABORT)) == 0). 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˘.

.drawImage(img.. /* Realizam desenul folosind gmem gmem. Graphics gmem = img. h).4 Salvarea desenelor ˆ format JPEG ın Pachetul com..setColor(.codec. FOLOSIREA IMAGINILOR 291 10.3 Mecanismul de ”double-buffering” Tehnica de double-buffering implic˘ realizarea unui desen ˆ memorie ¸i apoi a ın s transferul s˘u pe ecran. .dispose().sun. } } 10.5.5.fillOval(. 0.. ¸ 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).).).. */ // Transferam desenul din memorie pe ecran // desenand de fapt imaginea creata g. 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.jpeg din distributia standard Java ofer˘ ¸ a suport pentru salvarea unei imagini aflate ˆ memorie ˆ ın ıntr-un fi¸ier ˆ fors ın . this).. } public void paint(Graphics g) { // Desenam in memorie pe un obiect de tip Image // w si h sunt dimensiunile desenului Image img = createImage(w. 0. O situatie frecvent˘ ˆ care se apeleaz˘ la double-buffering este ¸ a ın a crearea de animatii.image. gmem.10.5.getGraphics(). gmem.

// Folosim setarile de codare jpeg implicite encoder.*.awt.5.jpeg. } } } 10. DESENAREA mat JPEG.setQuality(quality.encode(img). false).9f.printStackTrace(). String filename) { try { FileOutputStream out = new FileOutputStream(filename). O clas˘ responsabil˘ cu realizarea acestei operatiuni ar putea fi a a ¸ definit˘ astfel: a import import import import com.io. JPEGEncodeParam jep = encoder. encoder.awt.setJPEGEncodeParam(jep).sun.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. java.codec.image.image.292 CAPITOLUL 10. JPEGImageEncoder encoder = JPEGCodec. out.BufferedImage. //intre 0 si 1 public static void write(BufferedImage img.getDefaultJPEGEncodeParam(img). jep.*. java. } catch( Exception e ) { e.close().image. Pentru aceasta va trebui s˘ definim un ın a .awt. class JPEGWriter { static float quality = 0. java. a s aflata ˆ pachetul java.*.createJPEGEncoder(out).

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

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

awt . class Plansa extends Canvas implements Printable { Dimension d = new Dimension (400 . paint ( g ) . 200 . public Dimension getPreferredSize () { return d . g . } } class Fereastra extends Frame implements ActionListener { private Plansa plansa = new Plansa () . event . 200 . PAGE_EXISTS . Tip˘rirea efectiv˘: print. 200 . 100) . drawString ( " Hello " . g . drawOval (200 . s a Listing 10. } public int print ( Graphics g .*.*. } public void paint ( Graphics g ) { g . return Printable . 200) . PageFormat pf . private Button print = new Button ( " Print " ) . java . drawString ( " Numai la imprimanta " . 100) . java .6.*. 300) . ˆ a s a a ınsotite de un text) ¸i vom tip˘ri obiectul respectiv. java . addWindowListener ( new WindowAdapter () { public void windowClosing ( WindowEvent e ) { .6: Tip˘rirea unei componente a import import import import java . print . 400) .*. NO_SUCH_PAGE . awt . g . 100 . 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. 100 . io . drawRect (200 . awt . int pi ) throws PrinterException { if ( pi >= 1) return Printable . public Fereastra ( String titlu ) { super ( titlu ) . 200 . TIPARIREA 4.

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

linie as ¸ cu linie. deoarece necesit˘ tratare special˘ ˆ functie de a a a ın ¸ sistemul de operare folosit. imp . imp .6. io . iar ˆ Unix prin ”/dev/lp”.*. pe acest flux. 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. Listing 10.*. imp . imprimanta poate fi referit˘ prin ”lpt1”. class TestPrintText { public static void main ( String args []) throws Exception { // pentru Windows PrintWriter imp = new PrintWriter ( new FileWriter ( " lpt1 " ) ) . println ( " ABCDE " ) . close () .7: Tip˘rirea textelor a import java . println ( " Test imprimanta " ) . // pentru UNIX // PrintWriter imp = new PrintWriter ( new FileWriter ("/ dev / lp ") ) . Observati c˘ aceast˘ a ın ¸ a a abordare nu este portabil˘. import java . } } . In sistemul de operare Windows. awt .˘ 10.

DESENAREA .298 CAPITOLUL 10.

Java. acestea putˆnd fi s a interschimbate de c˘tre utilizator chiar la momentul executiei . ecrane Braille.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. Motif sau altele oferite de diver¸i dezvoltatori. 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. a ¸ • Accessibility API Permite dezvoltarea de aplicatii care s˘ comunice cu dispozitive uti¸ a lizate de c˘tre persoane cu diverse tipuri de handicap. Acela¸i program poate utiliza diın ¸ ¸ a s verse moduri Look-and-Feel. etc. • Look-and-Feel Permite schimbarea ˆ a¸i¸˘rii ¸i a modului de interactiune cu aplicatia ınf˘t sa s ¸ ¸ ˆ functie de preferintele fiec˘ruia. s • Java 2D API Folosind Java 2D pot fi create aplicatii care utilizeaz˘ grafic˘ la un ¸ a a 299 .1. dispozitive de recunoa¸tere a vocii.1 11. cum ar fi cele standard Windows. Mac.Capitolul 11 Swing 11. cum ar fi cititoare a de ecran.

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

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

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

JSlider JTabbedPane SingleSelectionModel ListModel JList ListSelectionModel JList JTable TableModel JTable TableColumnModel JTree TreeModel JTree TreeSelectionModel Document JEditorPane.11. ˆ 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. JRadioButton. a 311 • Controlul . JCheckBox. 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˘. ˆ general. ˆ care datele componentelor (modelul) sunt separate de ın reprezentarea lor vizual˘. JPasswordField Fiecare component˘ are un model initial implicit. JMenuItem. JTextField.modul de reprezentare vizual˘ a datelor. Metodele care acceseaz˘ a a . ˆ a are posibilitatea a ¸ ıns˘ de a-l ˆ ınlocui cu unul nou atunci cˆnd este cazul.transformarea actiunilor utilizatorului asupra componen¸ telor vizuale ˆ evenimente care s˘ actualizeze automat modelul acesın a tora (datele). FOLOSIREA MODELELOR • Prezentarea . JCheckBoxMenuItem. 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. dar a s exist˘ ¸i componente care au asociate mai multe modele: as Model ButtonModel Component˘ a JButton. JTextArea. JRadioButtomMenuItem JComboBox ComboBoxModel BoundedRangeModel JProgressBar. JTextPane.5. Dup˘ cum se observ˘ din tabelul de mai a a jos. JToggleButton. componente cu reprezent˘ri diferite pot avea acela¸i tip de model. JMenu. 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. Pentru a realiza separarea modelului de prezentare. A¸adar. Din motive practice. JScrollBarm.

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

11. } public Object getElementAt ( int index ) { return data1 [ index ]. show () . } } } public class TestModel { public static void main ( String args []) { new Fereastra ( " Test Model " ) . } } class Model2 extends Abst ractLis tModel { public int getSize () { return data2 . tipModel = 1. FOLOSIREA MODELELOR 313 pack () . setModel ( model1 ) . } else { lst . } public Object getElementAt ( int index ) { return data2 [ index ].5. setModel ( model2 ) . length . } public void actionPerformed ( ActionEvent e ) { if ( tipModel == 1) { lst . } } 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 . length . tipModel = 2. } } // Clasele corespunzatoare celor doua modele class Model1 extends Abst ractLis tModel { public int getSize () { return data1 .

f˘r˘ ¸ a a a aa a include ˆ eveniment detalii legate de schimbarea survenit˘. BoundedRangeModel model = slider. SWING acesteia. Obiectele ın a de tip listener vor trebui s˘ apeleze metode specifice componentelor pena tru a afla ce anume s-a schimbat.getModel(). folosirea modelelor aduce flexibilitate sporit˘ programului ¸i este recomandat˘ utilizarea lor. modelele care suport˘ aceast˘ abordare fiind BoundedRangeModel. // Trebuie sa interogam sursa asupra schimbarii .getSource().getValue().314 CAPITOLUL 11. 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).Modelele trimit un eveniment prin care sunt informati ascult˘torii c˘ a survenit o anumit˘ schimbare a datelor.5. aceast˘ ın a notificare este realizat˘ ˆ dou˘ moduri: a ın a 1. Acest lucru se realizeaz˘ prin intefata a ¸ ChangeListener iar evenimentele sunt de tip ChangeEvent. JSlider slider = new JSlider(). In multe situatii ˆ a. singura informatie continut˘ ˆ eveniment fiind componenta surs˘. Informativ (lightweight) .addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { // Sursa este de tip BoundedRangeModel BoundedRangeModel m = (BoundedRangeModel)e. model. mai ¸ ıns˘ ales pentru clase cum ar fi JTable sau JTree. ¸ ¸ a ın a Inregistrarea ¸i eliminarea obiectelor de tip listener se realizeaz˘ cu metodele s a addChangeListener. Un exemplu este metoda getValue a clasei JSlider care este de fapt un apel de genul getModel(). In Swing. a s a 11.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. ButtonModel ¸i a a s SingleSelectionModel. respectiv removeChangeListener.

getValue()). unele clase permit ˆ ınregistrarea ascult˘torilor direct pentru componenta a ˆ sine.5. Pentru u¸urinta program˘rii.out. pentru a nu lucra direct cu instanta modelus ¸ a ¸ lui. JList list = new JList(culori).11. 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". 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. "galben".addListSelectionListener( . System. s Secventa de cod de mai sus poate fi rescris˘ astfel: ¸ a JSlider slider = new JSlider().getSelectionModel(). } }). 2.Modele pun la dispozitie interfete special¸ ¸ izate ¸i tipuri de evenimente specifice ce includ toate informatiile legate de s ¸ schimbarea datelor. slider. } }).println("Valoare noua: " + s.println("Schimbare model: " + m. sModel. "albastru"). FOLOSIREA MODELELOR 315 System.out.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { // Sursa este de tip JSlider JSlider s = (JSlider)e. Consistent(statefull) .getValue()). ListSelectionModel sModel = list.getSource().

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

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

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

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

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

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

setBackground(isSelected ? Color. getSelectedIndices. setSelectedIndices.white). ¸i pentru obtinerea s ¸ celor selectate la un moment dat getSelectedIndex.. int index.322 .. Clasa JComboBox Clasa JComboBox este similar˘ cu JList. } } CAPITOLUL 11. Object value. Interfata ın ¸ s ¸ ListCellRenderer contine o singur˘ metod˘ getListCellRendererCom¸ a a ponent ce returneaz˘ un obiect de tip Component. return this. O facilitate extrem de important˘ pe care o au listele este posibilitatea de a a stabili un renderer pentru fiecare articol ˆ parte.red : Color.white : Color. } } Setarea unui anumit renderer pentru o list˘ se realizeaz˘ cu metoda setCella a Renderer. boolean isSelected. 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. acesta fiind ¸i singurul permanent vizibil. etc.. clasa ofer˘ metode pentru selectarea unor elemente din cadrul a programului setSelectedIndex.toString()). SWING Evident. Implicit toate elementele ın listei sunt afi¸ate ˆ acela¸i fel.black). Lista s . 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. } public Component getListCellRendererComponent( JList list. setForeground(isSelected ? Color. a class MyCellRenderer extends JLabel implements ListCellRenderer { public MyCellRenderer() { setOpaque(true). boolean cellHasFocus) { setText(value.

existˆnd o serie de clase predefinite ce implea menteaz˘ aceast˘ interfat˘ cum ar fi SpinnerListModel. JSpiner se bazeaz˘ exclusiv pe folosirea unui model. Acesta este un a obiect de tip SpinnerModel. 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. ce face parte integrant˘ din component˘.6.11. O diferent˘ notabil˘ const˘ ˆ modul de selectare a unui articol. 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. respectiv ActionEvent generate la selectarea a efectiv˘ a unui articol. lista elementelor nefiind ˆ a vizibil˘. Coma ponenta contine dou˘ butoane cu care poate fi selectat urm˘torul. acest lucru fiind s a controlat de metoda setEditable. de exemplu: numere intregi intre 1950 si 2050. ¸ a a s s Initializarea se face dintr-un vector sau folosind un model de tipul Com¸ boBoxModel. SpinnerNumberModel a a ¸a sau SpinnerDateModel ce pot fi utilizate. a a a a JComboBox functioneaz˘ dup˘ acelea¸i principii ca ¸i clasa JList. respectiv ¸ a a predecesorul element din domeniu. deoarece ¸a a a ın JComboBox permite ¸i editarea explicit˘ a valorii elementului. Evenimentele generate de obiectele JComboBox sunt de tip ItemEvent generate la navigarea prin list˘. FOLOSIREA COMPONENTELOR 323 celorlalte elemente este afi¸at˘ doar la ap˘sarea unui buton marcat cu o s a a s˘geat˘.

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

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

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

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

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

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

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

a a a • putClientProperty .lineStyle". a a a a a • setShowsRootHandles .gif").getUserObject().gif")..11. ı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. // sau "Horizontal".6. cea folosit˘ a ¸ a implicit fiind DefaultTreeCellRenderer. if (node == null) return. ImageIcon closed = createImageIcon("img/closed. "Angled"). 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. Aceasta implementeaz˘ interfata TreeCellRenderer.getLastSelectedPathComponent(). ImageIcon open = createImageIcon("img/open. . // Obtinem informatia din nod Object nodeInfo = node.gif").Specific˘ dac˘ r˘d˘cina e vizibil˘ sau nu. Acestea sunt: a • setRootVisible . cum ar fi modul s at de reprezentare a relatiilor (liniilor) dintre nodurile p˘rinte ¸i fiu: ¸ a s tree.Stabile¸te diverse propriet˘¸i. . "None" • Specificarea unei iconite pentru nodurile frunz˘ sau interne: ¸ a ImageIcon leaf = createImageIcon("img/leaf. Prin implementarea interfetei ¸ sau extinderea clasei implicite pot fi create modalit˘¸i de personalizare a at nodurilor arborelui ˆ functie de tipul sau valoarea acestora..Specific˘ dac˘ nodurile de pe primul nivel au a a simboluri care s˘ permit˘ expandarea sau restrˆngerea lor.putClientProperty("JTree.

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

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

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

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

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

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

De exemplu. In Swing. Evident.2 Consideratii generale ¸ In continuare vom prezenta cˆteva consideratii generale legate de diferite a ¸ aspecte ale desen˘rii ˆ cadrul modelului Swing. Dimensiunile componentelor Dup˘ cum ¸tim. JLabel label = new JLabel(img). Aceasta este o facilitate extrem de important˘ deoarece permite a crearea de componente care nu au form˘ rectangular˘. Transparenta ¸ Cu ajutorul metodei setOpaque poate fi controlat˘ opacitatea componentelor a Swing. Acestea includ ˆ a ¸i dimsniunile chenarelor. getWidth. exist˘ s ın a cˆteva solutii mai simple pentru afi¸area unei imagini. Imaginea respectiv˘ trebuie creat˘ a a ¸ a a folosind clasa ImageIcon. Trabsparenta ˆ a vine cu un anumit pret. 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. Din acest motiv.338 CAPITOLUL 11. se recomand˘ setarea componentelor ca fiind opace a (setOpaque(true)). de fiecare dat˘ cˆnd s a a este cazul. evident dac˘ acesıns˘ s a tea exist˘. este ın a a a a necesar˘ implementarea de cod specific pentru a trata ap˘sarea acestui tip a a de buton. a ¸ getHeight. SWING 11. orice component˘ este definit˘ de o suprafat˘ rectangua s a a ¸a lar˘. ImageIcon img = new ImageIcon("smiley.7. 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. Dimensiunile acestei pot fi obtinute cu metodele getSize.gif"). a s ˆ ıncetinind astfel procesul de afi¸are. 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. deoarece pentru componentele ¸ ıns˘ ¸ transparente vor trebui redesenate containerele pe care se g˘se¸te aceasta. Suprafata ocupat˘ de acestea poate fi aflat˘ cu metoda getInsets a ¸ a a .

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

mac.swing.java. .. In principiu.java.dispose().4.motif. g2d. Orice L&F este descris de o clas˘ derivat˘ din LookAndFeel. a s • com.windows. y). g2d. (GTK este acronimul de la GNU Image Manipulation Program Toolkit).swing. fie s˘ aib˘ un ın a a aspect specific Java.MotifLookAndFeel Specific˘ interfata CDE/Motif.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.sun. a • com.340 CAPITOLUL 11. Distributia a a ¸ standard Java include urm˘toarele clase ce pot fi utilizate pentru selectarea a unui L&F: • javax. a ¸ • com.GTKLookAndFeel GTK+ reprezint˘ un standard de creare a interfetelor grafice dezvoltat a ¸ independent de limbajul Java.2 exist˘ ¸i implementarea pentru Windows XP .swing.MacLookAndFeel Varianta specific˘ sistemelor de operare Mac.plaf.sun.plaf.swing.gtk.sun. Folosirea unei copii Graphics2D g2d = (Graphics2D)g.java.sun.translate(x.metal. 11.MetalLookAndFeel Este varianta implicit˘ de L&F ¸i are un aspect specific Java.plaf.plaf.java. Folosind acest L&F este posibil˘ ¸i a s .create(). as • com.plaf. 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. Incepˆnd cu versia a unea 1.swing.WindowsLookAndFeel Varianta specific˘ sistemelor de operare Windows. 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. SWING // 2..

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

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

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

datele procesului original. aceea¸i ¸ a s s s . Firele de executie sunt utile ˆ multe privinte. ˆ a uzual ele sunt folosite ¸ ın ¸ ıns˘ pentru executarea unor operatii consumatoare de timp f˘r˘ a bloca procesul ¸ aa principal: calcule matematice. 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. ceea ı¸ ıns˘ ¸ a ce ˆ ınseamn˘ c˘ ˆ cadrul unui proces se pot executa simultan mai multe fire a a ın de executie. a a a s ˆ timp ce la crearea unui fir nu este copiat decˆt codul procesului p˘rinte. firele ˆsi desf˘¸oar˘ ¸ ı¸ as a activitatea ˆ fundal ˆ a. a¸teptarea eliber˘rii unei resurse. Care ar fi ˆ a deosebirile ˆ ıns˘ ıntre un fir de executie ¸i un proces ? In primul. Un fir de executie poate fi asem˘nat cu o versiune redus˘ a unui proces. ın a a toate firele de executie avˆnd acces la acelea¸i date. ¸ a a ambele rulˆnd simultan ¸i independent pe o structur˘ secvential˘ format˘ de a s a ¸ a a instructiunile lor. Din acest motiv firele de executie mai sunt numite ¸i procese ¸ s usoare. evident. De asemenea. ¸ a s A¸adar.344 Program (proces) CAPITOLUL 12. permitˆnd efectuarea concurent˘ a sarcinilor independente ale ¸ ¸a a acelui program. Firele ¸ ¸a de executie definite de o clas˘ vor avea acela¸i cod ¸i. desenarea s a componentelor unei aplicatii GUI. acest lucru nu este obligatoriu.2 Crearea unui fir de executie ¸ Ca orice alt obiect Java. De multe ori ori. FIRE DE EXECUTIE ¸ Program (proces) Un program ˆsi poate defini ˆ a nu doar un fir de executie ci oricˆte. etc. un fir de executie este o instant˘ a unei clase. 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. ¸ 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. prin urmare. ın ıns˘ 12. un fir mai poate fi privit ¸i ca un context de executie ˆ cadrul unui s s ¸ ın proces.

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

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

12. nu mai putem extinde clasa Thread ci trebuie s˘ implement˘m a a direct interfata Runnable. // Pornim firele de executie // Ele vor fi distruse automat la terminarea lor } } 347 Gˆndind secvential. s-ar crede c˘ acest program va afi¸a prima dat˘ nua ¸ a s a merele de la 0 la 100 cu pasul 5. ¸tiind c˘ ˆ Java nu este permis˘ mo¸tenirea a s a ın a s multipl˘ ? a class FirExecutie extends Parinte. interfat˘ Runnable permite unei clase s˘ fie activ˘. a ¸ a s el fiind controlat de procesor ˆ ıntr-o manier˘ ”aparent” aleatoare. 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.lang ¸i este definit˘ astfel: ¸ a s ın s a . CREAREA UNUI FIR DE EXECUTIE ¸ // Numara de la 100 la 200 cu pasul 10 fir1 .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˘. a ¸ s ¸a a a f˘r˘ a extinde clasa Thread. aa Interfata Runnable se g˘se¸te ˆ pachetul java. Clasa Thread implementeaz˘ ea ˆ a¸i interfata ¸ a ıns˘s ¸ Runnable ¸i. ˆ ıntrucˆt primul apel este c˘tre contorul fir1. apoi numerele de la 100 la 200 cu pasul 10. 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. 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. din acest motiv.2. start () . A¸adar. la extinderea ei obtineam implementarea indis ¸ rect˘ a interfetei. fir2 . rezultatul obtinut va fi o intercalare de valori produse de ıns˘ ¸ cele dou˘ fire ce ruleaz˘ simultan. Thread // incorect ! In acest caz. start () .2.

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˘. prin ın a a instructiunea new.start(). Aceste operatiuni pot fi f˘cute chiar ˆ cadrul clasei noastre: ¸ a ın public class FirExecutie implements Runnable { private Thread fir = null. .348 CAPITOLUL 12. ˆ a ¸ a ıns˘ nu la oricare dintre ace¸tia. urmat˘ de un apel la un constructor al clasei Thread. ClasaActiva obiectActiv = new ClasaActiva(). Trebuie apelat constructorul care s˘ primeasc˘ s a a drept argument o instant˘ a clasei noastre. FIRE DE EXECUTIE ¸ public interface Runnable { public abstract void run(). } Prin urmare. o clas˘ care instantiaz˘ fire de executie prin implementarea a ¸ a ¸ interfetei Runnable trebuie obligatoriu s˘ implementeze metoda run. se pierde ˆ a tot suportul oferit a ıns˘ de clasa Thread. public FirExecutie() if (fir == null) { fir = new Thread(this).. firul de executie ¸a a ¸ poate fi lansat printr-un apel al metodei start. ca pentru orice alt obiect. crearea acestora trebuind f˘cut˘ a ¸ a a explicit. } } Spre deosebire de modalitatea anterioar˘. 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 . Thread fir = new Thread(obiectActiv).. Acest lucru se realizeaz˘. Simpla instantiere a unei clase care implemeneaz˘ interfata ¸ a ¸ Runnable nu creeaz˘ nici un fir de executie. fir. Dup˘ creare.

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

drawRect (x . dim . } public void update ( Graphics g ) { paint ( g ) . Color culoare . drawOval (x . } public Dimension getPreferredSize () { return dim . // 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 . facem o pauza de 50 ms */ for ( int i =0. y =0 . 300) . drawRect (0 . dim . width -1 . r ) . this . r =0. int x =0 . figura = figura .350 CAPITOLUL 12. black ) . r ) . if ( figura . r . setColor ( culoare ) . setColor ( Color . y . String figura . // Desenam figura la coordonatele calculate // de firul de executie g . else if ( figura . } public void paint ( Graphics g ) { // Desenam un chenar g . FIRE DE EXECUTIE ¸ // nu mai putem extinde clasa Thread Dimension dim = new Dimension (300 . public Plansa ( String figura . Intre doua afisari . equals ( " cerc " ) ) g . height -1) . i <100. y . i ++) { . culoare = culoare . Color culoare ) { this . 0 . equals ( " patrat " ) ) g . g . r .

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

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. FIRE DE EXECUTIE ¸ 12. se termin˘. la un moment dat. vom analiza s a mai ˆ ındeaproape st˘rile ˆ care se poate g˘si un fir de executie.3 Ciclul de viat˘ al unui fir de executie ¸a ¸ Fiecare fir de executie are propriul s˘u ciclu de viat˘: este creat. 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. In continuare. devine activ ¸ a ¸a prin lansarea sa ¸i. cu alte ¸ a s ın a a cuvinte dup˘ instantierea unui obiect din clasa Thread sau dintr-o subclas˘ a ¸ a a sa. Thread fir = new Thread(obiectActiv). // fir se gaseste in starea "New Thread" .352 CAPITOLUL 12.

• A apelat metoda wait. A¸adar. 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. adic˘ va fi a ın a ˆ executie. a . 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. un fir care ”ruleaz˘” poate ¸ ın s a s˘-¸i a¸tepte de fapt rˆndul la procesor. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ 353 In aceast˘ stare firul este ”vid”. 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. ı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”.start(). a Un fir aflat ˆ starea ”Runnable” nu ˆ ın ınseamn˘ neap˘rat c˘ se g˘¸este a a a as efectiv ˆ executie.12. adic˘ instructiunile sale sunt interpretate de procesor. 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”. ın ¸ fir. a • Planific˘ firul de executie la procesor pentru a fi lansat. s ¸ Starea ”Runnable” Dup˘ apelul metodei start un fir va trece ˆ starea ”Runnable”. //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.3. prin metoda start. a¸teptˆnd ca o anumit˘ conditie s˘ fie satisfas a a ¸ a cut˘. a ¸ • Apeleaz˘ metoda run a obiectului activ al firului.

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

Prin folosirea unei variabile de terminare. odat˘ cu ea. i += pas) System. a ın a // Primul exemplu public void run() { for(int i = a. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ 355 Starea ”Dead” Este starea ˆ care ajunge un fir de executie la terminarea sa. s a s ¸ 2. un fir de executie nu poate fi terminat fortat de c˘tre a ¸ ¸ a program ci trebuie s˘-¸i ”aranjeze” singur terminarea sa. i <= b. vom folosi o variabil˘ membr˘ a clasei ¸ a a a care descrie firul de executie care fie este public˘.3. 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.3. un fir de executie trebuie a s ¸ s˘-¸i ”aranjeze” singur propria sa ”moarte”.12. ci trebuie s˘ se termine a a a ˆ mod natural la ˆ ın ıncheierea metodei run pe care o execut˘. 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˘. Acest lucru poate as fi realizat ˆ dou˘ modalit˘¸i: ın a at 1. La terminarea metodei run se va termina automat ¸i firul de s executie. Spre deosebire de a versiunile curente ale limbajului Java. Prin scrierea unor metode run care s˘-¸i termine executia ˆ mod natas ¸ ın ural. acesta intrˆnd ˆ starea Dead. } Dup˘ afi¸area numerelor din intervalul specificat. ˆ versiunile mai vechi exista metoda ın stop a clasei Thread care termina fortat un fir de executie.print(i + " " ). Uzual.1 Terminarea unui fir de executie ¸ Dup˘ cum am vazut. ˆ a aceasta a ¸ ¸ ıns˘ fost eliminat˘ din motive de securitate. se va termina ¸i firul de executie repsectiv. a a a . Ambele exemple anteriorare ¸ a ın se ˆ ıncadreaz˘ ˆ aceast˘ categorie. A¸adar. as 12. 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. metoda se termin˘ a s a ¸i.out.

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

dac˘ firul este ˆ una din starile ”New Thread” sau ”Dead” a ın Intre st˘rile ”Runnable” sau ”Not Runnable”. 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. Metoda returneaz˘: ınc˘ a • true . Aceste fire de executie se numesc a s ¸ demoni. } catch ( InterruptedEx c e p t i o n e ) {} } . Cu alte cuvinte. sau scos din a ¸ a aceast˘ stare. // isAlive retuneaza false (starea este Dead) 12. getDef aultToo lkit () . // isAlive retuneaza true (starea este Runnable) fir. beep () . ma¸ina virtual˘ Java nu se va ¸ s a opri decˆt atunci cˆnd nu mai exist˘ nici un fir de executie activ. ¸ NumaraSecunde fir = new NumaraSecunde(). De multe ori a a a ¸ ˆ a dorim s˘ folosim fire care s˘ realizeze diverse activit˘¸i.start().3. awt .4: Crearea unui fir de excutie de tip ”daemon” ¸ class Beeper implements Runnable { public void run () { while ( true ) { java . cu metoda setDaemon. repectiv ”New Thread” a sau ”Dead” nu se poate face nici o diferentiere. Dup˘ crearea sa. ı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.3.dac˘ firul este ˆ una din st˘rile ”Runnable” sau ”Not Runnable” a ın a • false . a Listing 12. eventual periodic. un fir de executie poate fi f˘cut demon.2 Fire de executie de tip ”daemon” ¸ Un proces este considerat ˆ executie dac˘ contine cel putin un fir de executie ın ¸ a ¸ ¸ ¸ activ. la rularea unei aplicatii.executie = false. // isAlive retuneaza false (starea este New Thread) fir. sleep (1000) . try { Thread . Toolkit .12.

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

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

s2 .5: Exemplu de fir de executie ”egoist” ¸ class FirEgoist extends Thread { public FirEgoist ( String name ) { super ( name ) . MAX_PRIORITY ) . blocˆnd efectiv executia a a a ¸ celorlalte fire de executie pˆn˘ la terminarea sa. ˆ a nu trebuie s˘ ne baz˘m pe acest a ¸ ıns˘ a a lucru la scrierea unui program. deoarece acesta poate fi diferit ¸ de la un sistem de operare la altul. MAX_PRIORITY ) . s1 = new FirEgoist ( " Firul 1 " ) . trebuie evitat˘ scrierea lor ¸ s ¸ a ˆ ıntrucˆt acapareaz˘ pe termen nedefinit procesorul. setPriority ( Thread . . setPriority ( Thread . if ( i % 100 == 0) System . 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. Listing 12. Evident. while ( i < 100000) { // Bucla care acapareaza procesorul i ++. out . s2 = new FirEgoist ( " Firul 2 " ) . 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. s1 . s2 . } } } public class TestFirEgoist { public static void main ( String args []) { FirEgoist s1 . 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. } public void run () { int i = 0. // yield () . 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.360 CAPITOLUL 12. println ( getName () + " a ajuns la " + i ) .

.12. CICLUL DE VIATA AL UNUI FIR DE EXECUTIE ¸˘ ¸ s1 . fie prin ”adormirea” temporar˘ a s a a a firului curent cu ajutorul metodei sleep. executia celor dou˘ fire se va intercala. 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 .. Firul Firul Firul Firul . s2 .. } } 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.. 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. care determin˘ firul de executie curent s˘ se opreasc˘ tema ¸ a a porar.3. 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. Firul Firul Firul Firul Firul Firul . start () .. dˆnd ocazia ¸i altor fire s˘ se execute.. Decomentˆnd linia ˆ care s at a ın apel˘m yeld din exemplul anterior.. Rezultatul va ar˘ta astfel: a Firul Firul Firul . a ¸ a . acaparˆnd ¸ a ¸ a efectiv procesorul. start () ..

362 CAPITOLUL 12. ˆ care produc˘torul genereaz˘ un flux de date a ın a a care este preluat ¸i prelucrat de c˘tre consumator. In ams bele cazuri avem de-a face cu fire de executie concurente care folosesc o ¸ resurs˘ comun˘: un fi¸ier. fiecare la un interval neregulat cuprins ˆ ıntre 0 ¸i 100 de milisecunde. trebuie s˘ comunice ˆ a a ıntre ele pentru a accesa diferite resurse comune sau pentru a-¸i transmite dinamic rezuls tatele ”muncii” lor. 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. FIRE DE EXECUTIE ¸ 12. 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. a a s a s ele trebuie sincronizate ˆ ıntr-o manier˘ care s˘ permit˘ decurgerea normal˘ a a a a a activit˘¸ii lor. s˘ presupunem s s s a c˘ produc˘torul genereaz˘ ni¸te numere ¸i le plaseaz˘. Sau. 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). at 12. a a • Consumatorul va prelua. 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. Exist˘ ˆ a numeroase situatii cˆnd fire de executie a ıns˘ ¸ a ¸ separate. pe rˆnd. pe rˆnd. dar care ruleaz˘ concurent. respectiv o zon˘ de memorie ¸i. . ˆ a a a s s a a ıntr-un buffer iar consumatorul cite¸te numerele din acel buffer pentru a le procesa.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. cu alte cuvinte care nu depind ˆ nici un fel de executia sau de ın ¸ rezultatele altor fire.4 Sincronizarea firelor de executie ¸ Pˆn˘ acum am v˘zut cum putem crea fire de executie independente ¸i asa a a ¸ s incrone.3. din acest motiv. a s s Pentru a fi accesibil˘ ambelor fire de executie.3. 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.

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

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

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

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

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

pr2 = new PipedReader(). ¸ Fluxurile ”pipe” de ie¸ire ¸i cele de intrare pot fi conectate pentru a s s efectua transmiterea datelor. respectiv • PipedOutputStream. 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. 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. ¸ Functionarea obicetelor care instantiaz˘ PipedWriter ¸i PipedReader ¸ ¸ a s este asem˘n˘toare cu a canalelor de comunicare UNIX (pipes). . 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. firele a a de executie comunicˆnd printr-un canal. La un cap˘t se ¸ a scriu caractere. folosirea lor se va face din cadrul unor fire ¸ de executie. Acestea sunt a implementate prin fluxuri descrise de clasele: • 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). PipedInputStream . ¸ a Realizarea conexiunii se face astfel: PipedWriter PipedReader // sau PipedReader PipedWriter // sau pw1 = new PipedWriter().pentru octeti. La citire. FIRE DE EXECUTIE ¸ 12. la cel˘lalt se citesc. dac˘ nu sunt date disponibile a a firul de executie se va bloca pˆn˘ ce acestea vor deveni disponibile.pentru caractere. pr1 = new PipedReader(pw1). pw2 = new PipedWriter(pr2). PipedWriter .376 CAPITOLUL 12.

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

378 } CAPITOLUL 12. Consumator c1 = new Consumator ( in ) . start () . readInt () . Pa¸ii care trebuie f˘cuti pentru folosirea unui timer sunt: s a ¸ . println ( " Consumatorul a primit :\ t " + value ) . } } } public class TestPipes { public static void main ( String [] args ) throws IOException { PipedOutputStream pipeOut = new Pipe dOutput Stream () . Producator p1 = new Producator ( out ) . } System . p1 . } } 12.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. PipedInputStream pipeIn = new PipedInputStream ( pipeOut ) . DataInputStream in = new DataInputStream ( pipeIn ) . out . } catch ( IOException e ) { e . i ++) { try { value = in . FIRE DE EXECUTIE ¸ public void run () { int value = 0. i < 10. DataOutputStream out = new DataOutputStream ( pipeOut ) . for ( int i = 0. printStackTrace () . 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. start () . c1 .

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

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

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

FIRE DE EXECUTIE ¸ .382 CAPITOLUL 12.

f˘r˘ a a ın ¸ aa a fi nevoie de cuno¸tinte prealabile referitoare la comunicarea efectiv˘ ˆ s ¸ a ıntre calculatoare. Acest protoa ın ¸ col asigur˘ stabilirea unei conexiuni permanente ˆ a ıntre cele dou˘ calcua latoare pe parcursul comunicatiei. sunt necesare cˆteva notiuni fundamentale a ¸ referitoare la retele cum ar fi: protocol. pentru a se ”ˆ ¸elege” ˆ a s s ınt ıntre ele. Cu toate acestea. ¸ • UDP (User Datagram Protocol) este un protocol bazat pe pachete inde383 . 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.net. adresa IP. c˘tre destinatie. Dou˘ dintre cele mai utilizate protocoale sunt TCP ¸i UDP. port. a ¸ Clasele din acest pachet ofer˘ o modalitate facil˘ de programare ˆ retea. socket.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. ¸ Ce este un protocol ? Un protocol reprezint˘ o conventie de reprezentare a datelor folosit˘ ˆ comua ¸ a ın nicarea ˆ ıntre dou˘ calculatoare. ¸ a Pachetul care ofer˘ suport pentru scrierea aplicatiilor de retea este java. octet cu octet. a s • TCP (Transport Control Protocol) este un protocol ce furnizeaz˘ un a flux sigur de date ˆ ıntre dou˘ calculatoare aflate ˆ retea.Capitolul 13 Programare ˆ retea ın ¸ 13. 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.

30. 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.384 CAPITOLUL 13. a a De asemenea. numerele cuprinse ˆ ¸ ıntre 0 ¸i 1023 fiind s ˆ a rezervate unor servicii sistem ¸i. ¸ Clase de baz˘ din java. cum ar fi thor. 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). a Clasa Java care reprezint˘ notiunea de adres˘ IP este InetAddress.net permit comunicarea ˆ ıntre procese folosind protocoalele . Corespunz˘toare unei s a a adrese numerice exista ¸i o adresa IP simbolic˘. a Un port este un num˘r pe 16 biti care identific˘ ˆ mod unic procesele a ¸ a ın care ruleaz˘ pe o anumit˘ masin˘. 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.ro s a pentru adresa numeric˘ anterioar˘. numite datagrame. cum ar fi de exemplu: ¸ ¸ 193. 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).infoiasi. Aceasta reprezint˘ un num˘r a a reprezentat pe 32 de biti. Identificarea proceselor se realizeaz˘ prin intermdiul porturilor. Ins˘ pe un calculator pot exista concurent mai multe s a procese care au stabilite conexiuni ˆ retea. a ¸ a Ce este un port ? Un calculator are ˆ general o singur˘ leg˘tur˘ fizic˘ la retea.131 ¸i este numit adresa IP numeric˘. PROGRAMARE ˆ RETEA IN ¸ pendente de date.231. 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. nu trebuie folosite ˆ ıns˘ s ın aplicatii.net a Clasele din java. fiecare calculator aflat ˆ ıntr-o retea local˘ are un nume unic ¸ a ce poat fi folosit la identificarea local˘ a acestuia. din acest motiv. Orice aplicatie care realizeaz˘ o conexiune a a a ¸ a ˆ retea va trebui s˘ ata¸eze un num˘r de port acelei conexiuni. ın ¸ a ¸ Prin urmare. uzual sub forma a 4 octeti. asteptˆnd diverse informatii. Acest protocol nu stabile¸te o conexiun˘ ın s a permant˘ ˆ a ıntre cele dou˘ calculatoare.

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

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

br = new BufferedReader ( new Inpu tStream Reader ( in ) ) . close () . Fiecare socket este ata¸at unui port astfel ˆ at s˘ poat˘ iden¸ s ıncˆ a a tifica unic programul c˘ruia ˆ sunt destinate datele. Aceast˘ conexiune este reprezentat˘ de un obiect de a a a tip URLConnection. In cazul trimiterii de date.13. obiectul URL este uzual un proces ce ruleaz˘ a pe serverul Web referit prin URL-ul respectiv (jsp.3. etc). php. while (( linie = br . Metoda folosit˘ pentru trimitere este a a POST. ce permite crearea atˆt a unui flux de intrare pentru a citirea informatiilor de la URL-ul specificat. 13. cgi-bin. try { URL url = new URL ( adresa ) .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. println ( " URL invalid !\ n " + e ) . } finally { br . SOCKET-URI BufferedReader br = null . readLine () ) != null ) { // Afisam linia citita System . 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. InputStream in = url . String linie . cˆt ¸i a unui flux de ie¸ire pentru ¸ a s s scrierea de date c˘tre acel URL. println ( linie ) . servlet. err . openStream () . a ıi . } } catch ( Malfo rmedU RLEx c e p t i o n e ) { System . out . } } } 387 Conectarea la un URL Se realizeaz˘ prin metoda openConnection ce stabile¸te o conexiune bidirectional˘ a s ¸ a cu resursa specificat˘.

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

pentru comunis care prin intermediul ¸irurilor de caractere. Fluxurile obtinute vor fi folosite ˆ ¸ ımpreun˘ cu fluxuri de procea sare care s˘ asigure o comunicare facil˘ ˆ a a ıntre cele dou˘ procese. s • DataInputStream. prin intermediul cˆruia va fi reala a a izat˘ leg˘tura cu clientul. In functie a ¸ de specificul aplicatiei acestea pot fi perechile: ¸ • BufferedReader. 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. acesta trebuie s˘ creeze ˆ ai un obiect de tip a ıntˆ ServerSocket. COMUNICAREA PRIN CONEXIUNI 389 La nivelul serverului. respectuv getOuta putStream. Acest lucru se re¸ alizeaz˘ prin intermediul metodelor getInputStream. 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.pentru comunicare prin date primitive. Crearea unui obiect de tip ServerSocket se face a a specificˆnd portul la care ruleaz˘ serverul.pentru cominicare prin intermediul obiectelor. 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˘. DataOutputStream . . cu argumentul dat ˆ a ın milisecunde. constructorul folosit fiind: a a ServerSocket(int port) Metoda clasei ServerSocket care a¸teapt˘ ”ascult˘” reteaua este accept. respectiv scrierea datelor. BufferedWriter ¸i PrintWriter . ObjectOutputStream . • ObjectInputStream.4. Pentru fiecare din cele dou˘ socketuri deschise pot fi create apoi dou˘ a a fluxuri pe octeti pentru citirea.13.

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

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

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

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

int offset. InetAddress address. protocolul TCP/IP folose¸te tot pachete pentru trimiterea informatiilor s ¸ dintr-un nod ˆ altul al retelei. port) int offset. SocketAddress address) DatagramPacket(byte[] buf. ın ın Clasa DatagramPacket contine urm˘torii constructori: ¸ a DatagramPacket(byte[] buf. int length. SocketAddress address) DatagramPacket(byte[] buf. 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. int length) DatagramPacket(byte[] buf. diferenta ˆ ¸ ıntre ele fiind utilizarea claselor InetAddress. InetAddress address. int length. cu deosebirea c˘ asigur˘ respectarea ordinii de ın ¸ a a transmitere a mesajelor ¸i verific˘ ajungerea la destinatie a tuturor pachetelor s a ¸ . PROGRAMARE ˆ RETEA IN ¸ Dup˘ cum am mentionat deja. ¸ A trei pereche de constructori este folosit˘ pentru crearea unui pachet ˆ a ın care vor fi receptionate date. ei nespecificˆnd vreo surs˘ sau destinatie. port) DatagramPacket(byte[] buf. Pe de alt˘ parte. int length. ¸ a a ¸ . int length) Primele dou˘ perechi de constructori sunt pentru creare pachetelor ce a vor fi expediate.ˆ cazul ˆ care unul nu a ajuns. De a a a s fapt. 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. respectiv SocketAddress pentru specificarea adresei desinatie. acesta va fi retrimis automat. int DatagramPacket(byte[] buf. int int length. int offset.394 CAPITOLUL 13.

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

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

extensie a clasei DatagramSocket. } } } 397 13.239. adresa . socket . socket .0. // Afisam raspunsul (" Hello Duke !") System .0.˘ 13.0.255. port ) .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.255. out . getData () ) ) . length ) . as a . length . buf .255 ¸i un port UDP. a ¸ s Gruparea mai multor programe ˆ vederea trimiterii multiple de mesaje se ın realizeaz˘ prin intermediul unui socket special. send ( packet ) . Un grup de clienti abonati pentru trimitere multipl˘ este specificat printr¸ ¸ a o adres˘ IP din intervalul 224. println ( new String ( packet . close () . TRIMITEREA DE MESAJE CATRE MAI MULTI CLIENTI ¸ ¸ packet = new DatagramPacket ( buf .6. buf .1 . // Asteaptam pachetul cu raspunsul de la server buf = new byte [256]. receive ( packet ) . packet = new DatagramPacket ( buf .0 este rezervat˘ ¸i nu trebuie folosit˘. } finally { if ( socket != null ) socket . a s Adresa 224. descris de clasa Multicasta Socket.0.

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

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

400 CAPITOLUL 13. PROGRAMARE ˆ RETEA IN ¸ .

Ciclul de viat˘ al unui applet este complet diferit. as aceasta fiind clasa ce trebuie specificat˘ ˆ documentul HTML ce descrie a ın pagina Web ˆ care dorim s˘ includem appletul.swing exist˘ a a a ¸i clasa JApplet.applet. 401 . a cea mai important˘ clas˘ fiind Applet. s Ca orice alt˘ aplicatie Java. avˆnd ca ara a a gument numele clasei principale a aplicatiei. O aplicatie ın ınc˘ a ¸ ¸ independent˘ este executat˘ prin apelul interpretorului java. Una dintre acestea este principal˘ ¸i extinde clasa Applet.Capitolul 14 Appleturi 14. oferind suport pentru crearea de s appleturi pe arhitectura de componente JFC/Swing. care extinde Applet. In pachetul javax. Un a astfel de program se mai nume¸te miniaplicatie. ¸ a fiind dictat de evenimentele generate de c˘tre browser la vizualizarea docua mentului HTML ce contine appletul. ı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.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. clasa principal˘ fiind cea care ¸ a contine metoda main. ¸ Pachetul care ofer˘ suport pentru crearea de appleturi este java. ci va fi executat de browserul ˆ care este ˆ arcat˘ pagina Web ce contine appletul respectiv.

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

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

a ¸ citirea unor parametri de intrare. ı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. etc.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. In unele situatii ˆ ¸ ¸ ıntreaga executie a appletului se consum˘ la ¸ a etapele de initializare ¸i pornire.404 CAPITOLUL 14. • 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. ¸ s .html folosind unul din browser-ele amintite sau efectuˆnd apelul: a appletviewer simplu. 14. • Initializarea ¸ Este apelat˘ metoda init ce permite initializarea diverselor variabile.html.class width=400 height=400> </applet> </body> </html> • Vizualizarea appletului: se deschide fisierul simplu. APPLETURI <html> <head> <title>Primul applet Java</title> </head> <body> <applet code=FirstApplet. • Inc˘rcarea ˆ memorie a ın Este creat˘ o instanta a clasei principale a appletului ¸i ˆ a ¸ s ıncarcat˘ ˆ a ın memorie.

etc) ¸i ˆ a s ınainte de destroy. va fi reapelat˘ metoda a a start. pentru ¸ ın a nu consuma inutil din timpul procesorului. • Oprirea definitiv˘ a La ˆ ınchiderea tuturor instantelor browserului folosit pentru vizualizare. 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. ¸ appletul va fi eliminat din memorie ¸i va fi apelat˘ metoda destroy a s a acestuia.3. ˆ a. dup˘ o oprire temporar˘. la unele browsere. fereastra browserului a este minimizat˘. Metodele specifice appleturilor A¸adar. la prima a a a afi¸are a appletului ˆ pagin˘. a a a stop De fiecare dat˘ cˆnd appletul nu mai este vizibil a a (pagina Web nu mai este vizibil˘. Apelul a ¸ metodei destroy este ˆ ıntotdeauna precedat de apelul lui stop. destroy La ˆ ınchiderea ultimei instante a browserului ¸ care a ˆ arcat ˆ memorie clasa principal˘ a appletului. ınc˘ ın a Atentie ¸ . pentru a-i permite s˘ elibereze resursele detinute. a start Imediat dup˘ initializare ¸i de fiecare dat˘ a ¸ s a cˆnd appletul redevine activ. dˆndu-i astfel posibilitatea s˘ a a a opreasca temporar executia sa pe perioada ˆ care nu este vizibil. Teoretic. Acela¸i lucru se ˆ ampl˘ s ıntˆ a dac˘ fereastra browserului este minimizat˘.14. In momentul cˆnd pagina a a a Web ce contine appletul devine din nou activ˘. aceast˘ metod˘ ¸ a a ar trebui s˘ se apeleze o singur˘ dat˘. 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. 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.

applet. import java.awt. ˆ a a ınainte de toate. import java.event.406 CAPITOLUL 14.*. ¸ s Plasarea componentelor. . clasa Applet este o extensie a superclasei Container. gestionarea pozition˘rii lor ¸i tratarea evenimentelor ¸ a s generate se realizeaz˘ la fel ca ¸i ˆ cazul aplicatiilor.Applet. a a ceea ce ˆ ınseamn˘ c˘ appleturile sunt.*. suprafete de afi¸are. 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. Uzual. public class StructuraApplet extends Applet { public void init() { } public void start() { } public void stop() { } public void destroy() { } } 14.awt. APPLETURI Aceste metode sunt apelate automat de browser ¸i nu trebuie apelate s explicit din program ! Structura general˘ a unui applet a import java.4 Interfata grafic˘ cu utilizatorul ¸ a Dup˘ cum am v˘zut.

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

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

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

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

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

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

14. int y = ( int ) ( Math . applet . repaint () . try { Thread . random () * getHeight () ) . codul metodei paint trebuie s˘ fie cˆt mai a a a a simplu de executat ceea ce. public void init () { while ( true ) { x = ( int ) ( Math .*.*. try { Thread . } 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. applet . ın O alt˘ idee de rezolvare care ne-ar putea veni. ˆ a a a ın ıncercˆnd s˘ o a a termine.*.3: Incorect: appletul nu termin˘ initializarea a ¸ import java . } catch ( InterruptedE x ce pt io n e ) {} } } public void paint ( Graphics g ) { . nu este cazul ˆ appletul de mai sus. public class AppletRau1 extends Applet { public void paint ( Graphics g ) { while ( true ) { int x = ( int ) ( Math . y ) . awt . import java . FOLOSIREA FIRELOR DE EXECUTIE ˆ APPLETURI ¸ IN Listing 14.*. este a s a urm˘toarea : a Listing 14. sleep (1000) . public class AppletRau2 extends Applet { int x . x . sleep (1000) . g . y .7. import java . evident. Ca regul˘ general˘. de asemenea gre¸it˘.2: Incorect: blocarea metodei paint import java . awt . random () * getWidth () ) . random () * getWidth () ) . y = ( int ) ( Math . random () * getHeight () ) . drawString ( " Hello " .

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

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

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

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

ıl .err. 0 . 0 . ¸i este descris de interfata AppletCona s ¸ text. ¸ a ın a eventual ˆ ımpreun˘ cu alte appleturi.infoiasi.ro").418 CAPITOLUL 14. 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. a AppletContext contex = getAppletContext(). Crearea unui obiect ce implementeaz˘ aceast˘ interfat˘ se realizeaz˘ de a a ¸a a c˘tre browser.showDocument(doc). s Identificarea se face prin intermediu numelui pe care orice instanta a unui ¸ applet ˆ poate specifica prin atributul NAME. etc). this ) . } catch(MalformedURLException e) { System. drawImage ( img . Prin a intermediul acestei interfete un applet poate ”vedea” ˆ jurul sau. getAppletContext(). ¸ Aceast˘ metod˘ este accesat˘ prin intermediul contextului de executie al a a a ¸ appletului. la apelul metodei getAppletContext a clasei Applet. } 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. try { URL doc = new URL("http://www.println("URL invalid! \n" + e). putˆnd ¸ ın a comunica cu alte applet-uri aflate pe aceeasi pagin˘ sau cere browser-ului s˘ a a deschid˘ diverse documente. imagine. APPLETURI public void paint ( Graphics g ) { g . html. } } Aflarea contextului de executie ¸ Contextul de executie al unui applet se refer˘ la pagina ˆ care acesta ruleaz˘.

folosind metodele getApplet. add ( play ) .*. addActionListener ( this ) .applet. addActionListener ( this ) .14. loop . s Listing 14. au " ) . Pentru a reda un sunet aflat ˆ ıntr-un fi¸ier ”. Acestea as a ın sunt descrise prin intermediul unor obiecte ce implementeaz˘ interfata Aua ¸ dioClip din pachetul java. awt .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. Button stop = new Button ( " Stop " ) . event . add ( loop ) . 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. Button loop = new Button ( " Loop " ) .au.*. 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. " sunet . public class Sunete extends Applet implements ActionListener { Button play = new Button ( " Play " ) .7: Redarea sunetelor import java .8. import java . public void init () { // Fisierul cu sunetul trebuie sa fie in acelasi // director cu appletul clip = getAudioClip ( getCodeBase () . stop . Redarea sunetelor Clasa Applet ofer˘ ¸i posibilitatea red˘rii de sunete ˆ format . import java . add ( stop ) . respectiv ¸ getApplets. . play . loop ¸i stop pentru acesta. AudioClip clip = null . addActionListener ( this ) .*. applet . awt .

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

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

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

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

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

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

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

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

2. 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. JDBC-ODBC Bridge Acest tip de driver permite conectarea la o baz˘ de date care a fost a ˆ ınregistrat˘ ˆ prealabil ˆ ODBC. Conectarea efectiv˘ la baza de date se va face prin intermediul a a acestui identificator. De asemenea. Driver JDBC .428 CAPITOLUL 15. De¸i simplu de utilizat.odbc. ODBC (Open Database Conectivity) a ın ın reprezint˘ o modalitate de a uniformiza accesul la baze de date. asociind a acestora un identificator DSN (Data Source Name) ¸i diver¸i parametri neces s sari conect˘rii.jdbc. LUCRUL CU BAZE DE DATE 15. a s a ¸ Clasa Java care descrie acest tip de driver JDBC este: sun. 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.Driver nativ . ın Tip 2.JdbcOdbcDriver ¸i este inclus˘ ˆ distributia standard J2SDK.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. atˆt ODBC-ul cˆt ¸i driver-ul nativ a a s trebuie s˘ existe pe ma¸ina pe care ruleaz˘ aplicatia.

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. Protocolul aa folosit este specific fiec˘rui produc˘tor. distributia standard J2SDK neincluzˆnd nici unul. ¸ a Tip 3. acestea fiind apoi transormate folosind o aplicatie server ˆ ¸ ıntr-un protocol specfic bazei de date. 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.2. Clase Java ın care implementeaz˘ astfel de drivere pot fi procurate de la produc˘torii de a a SGBD-uri.Server Acest tip de driver transform˘ cererile JDBC folosind un protocol de retea a ¸ independent. Driver JDBC . Driver JDBC nativ .˘ 15. a a Tip 4. f˘r˘ nici o modificare la nivelul clientului.

return . fiind preferat˘ la dezvoltarea aplicatiilor care manevreaz˘ volume a a ¸ a mari de date ¸i viteza de executie este critic˘.print("ClassNotFoundException: " + e) .430 CAPITOLUL 15.2. dbproperties).err.forName("sun. } catch(ClassNotFoundException e) { System.getConnection(url. } Connection con . Drivere de acest tip pot fi s ¸ a procurate de la diver¸i produc˘tori de SGBD-uri. password).JdbcOdbcDriver").err. username. Stabilirea unei conexiuni folosind driverul JDBC-ODBC String url = "jdbc:odbc:test" .jdbc. try { Class. Connection c = DriverManager. } catch(SQLException e) { System.PWD=java" .getConnection(url. Aceast˘ solutie este cea mai ¸ a ¸ rapid˘. "duke".UID=duke. Connection c = DriverManager. try { con = DriverManager. 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). s a 15. .getConnection(url).odbc. // sau url = "jdbc:odbc:test. "java").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.getConnection(url.

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

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

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

if(rs != null) { // Proceseaza rezultatul . a • O secvent˘ SQL specificat˘ unui obiect PreparedStatement poate s˘ ¸a a a aib˘ unul sau mai multi parametri de intrare. ˆ cazul ˆ care dorim s˘ introducem valorile ın ın a unor variabile ˆ ıntr-o secvent˘ SQL.2 Interfata PreparedStatement ¸ Interfata PreparedStatement este derivat˘ din Statement.434 CAPITOLUL 15. String sql = "SELECT * FROM persoane WHERE cod=" + cod + " OR nume=’" + nume + "’"...getMoreResults(). care vor fi specificati a ¸ ¸ prin intermediul unui semn de ˆ ıntrebare (”?”) ˆ locul fiec˘ruia dintre ın a .getResultSet(). String nume = "Popescu". ResultSet rs = stmt.getMoreResults().3. 15. } // Nu mai avem nici un rezultat break.executeQuery(sql). continue. } // rowCount este -1 // Avem unul sau mai multe ResultSet-uri ResultSet rs = stmt. } Folosind clasa Statement. continue. 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. 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”). stmt. LUCRUL CU BAZE DE DATE stmt.

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

Types. Pentru a realiza a at a .setInt(2. null). Fiec˘rui tip Java ˆ corespunde un tip generic SQL. Metoda setObject permite specificarea unor valori pentru parametrii de intrare. 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. pstmt. 100). pstmt. "Popescu"). Cu ajutorul metodelor setBytes sau setString avem posibilitatea de a specifica date de orice dimensiuni ca valori pentru anumite articole din baza de date.setObject(2. 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. pstmt.436 CAPITOLUL 15.CHAR). Statement pstmt = con. este definit˘ de clasa Types.setString(1.setInt(2. // sau doar pstmt.setInt(1. pstmt. numite ¸i tipuri JDBC.executeUpdate(). pstmt. pstmt = con. Lista tuturor tipurilor generice disponibile.setString(1. 100). Folosind metoda setNull putem s˘ atribuim unui parametru de intrare a valoare SQL NULL. "Ionescu"). LUCRUL CU BAZE DE DATE String sql = "UPDATE persoane SET nume=? WHERE cod=?".setObject(2. 200). pstmt. pstmt.prepareStatement(sql). Acela¸i lucru poate fi realizat cu metode de a s tipul setXXX dac˘ argumentul folosit are valoarea null.setInt(2. Types.setObject(1. a pstmt. sql = "SELECT * from persoane WHERE cod >= ?". prin cons a stantelor declarate de aceasta.executeQuery(). 100. ResultSet rs = pstmt.setNull(1. trebuind ˆ a s˘ specific˘m ¸i tipul de date al coloanei ˆ ıns˘ a a s ın care vom scrie aceast˘ valoare. "Ionescu". pstmt.INTEGER).prepareStatement(sql). pstmt.CHAR). Types. pstmt. 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.executeUpdate(). 100).

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

java.3. functie de secventa executat˘. obiectul va contine ¸i meta-datele interog˘rii cum ar fi denumirele ¸ s a coloanelor selectate.FLOAT). a Statement stmt = con. LUCRUL CU BAZE DE DATE "{call calculMedie(?)}"). Forma general˘ a unui ResultSet este tabelar˘. a a a a .createStatement(). num˘rul lor.registerOutParameter(1. va fi a a s ˆ ınregistrat cu registerOutParameter.sql.executeQuery(). 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. fie numele acestuia. float medie = cstmt. String sql = "SELECT cod. etc.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. In a s s acest caz el trebuie s˘ primeasc˘ o valoare cu setXXX ¸i. cstmt. ResultSet rs = stmt. Coloanele sunt numerotate de la stˆnga a la dreapta.3.getDouble(1). De a a s ¸ ¸ a asemenea. De asemenea. Pentru s a acest lucru vom folosi metode de tip getXXX. tipurile de date specificate trebuind s˘ coincid˘. ce va contine toate liniile ce satisfac conditiile ¸ ¸ impuse de comanda SQL.4 15. 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˘. nume FROM persoane".438 CAPITOLUL 15.Types. unde XXX este tipul de dat˘ al unei coloane iar argumentul primit indic˘ fie num˘rul de ordine din a a a cadrul tabelului. folosirea indexului coloanei ˆ loc de a ın numele s˘u va fi mai eficient˘. a a 15. Este posibil ca un parametru de intrare s˘ fie ¸i parametru de ie¸ire. cstmt. de asemenea. ˆ ıncepˆnd cu 1.executeQuery(sql). In general. a a avˆnd un num˘r de coloane ¸i de linii.

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

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

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

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

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

LUCRUL CU BAZE DE DATE .444 CAPITOLUL 15.

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

Atunci cˆnd nu mai exist˘ nici o referint˘ de tipul clasei a a a ¸a respective. etc. bootstrap) . a ˆ care class loader-ele sunt dispuse ierarhic ˆ ın ıntr-un arbore. . 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. LUCRUL DINAMIC CU CLASE 4. r˘d˘cina acestuia a a fiind class loader-ul primordial. va ˆ s s ıncerca s˘ execute operatiunea de a ¸ ˆ arcare a clasei. De¸i acest comportament nu este obligatoriu.ClassLoader. In momentul cˆnd este solicitat˘ ˆ arcarea unei clase. Desc˘rcarea . a fost introdus un model de tip delegat. acesta fiind specificat la s a ¸ a a crearea sa. Dac˘ nici ea nu va reu¸i. mai putin r˘d˘cina).Acestea nu fac parte intrinsec˘ din JVM ¸i a s sunt instante ale clasei java. Fiecare instanta de tip ClassLoader va avea ¸ a¸adar un p˘rinte (evident. tipul efectiv al obiectului fiind a¸adar derivat din aceasta. a s Dup˘ cum vom vedea. ¸ 2. Class loader-ul primordial (eng. Astfel. obiectul de tip Class creat va fi marcat pentru a fi eliminat din memorie de c˘tre garbage collector. ˆ arcarea unei clase poate a a ınc˘ determina ˆ arcarea unor altor clase care sigur vor fi folosite ˆ ınc˘ ımpreun˘ cu a prima. Aceasta este o clas˘ ¸ a abstract˘. Acestea sunt de dou˘ tipuri: a 1. 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. folosind class loader-e diferite. 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.lang. sau a unor resurse ce sunt necesare function˘rii acesteia.2 de Java.446 CAPITOLUL 16. Abia ˆ cazul ˆ ın ın care nici unul din ace¸tia nu a reu¸it. va fi aruncat˘ o exceptie de tipul ınc˘ a s a ¸ ClassNotFoundException. ¸ a Incepˆnd cu versiunea 1. pentru a minimiza ˆ arcarea aceleia¸i ın ¸ ınc˘ s clase de mai multe ori.Reprezint˘ o parte intea grant˘ a ma¸inii virtuale. Class loader-e proprii . s ˆ multe situatii el este de preferat. fiind responsabil cu ˆ arcarea claselor stana s ınc˘ dard din distributia 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.

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

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

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

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

Bineˆ ¸eles. adresele URL pot specifica a a a ınt ¸i directoare ale sistemului de fi¸iere local.getClassLoader(). iar cu addURL putem ad˘uga a o nou˘ adres˘ de c˘utare a claselor.˘ 16. } } Inc˘rcarea claselor folosind clasa nou creat˘ se va face astfel: a a . // Incarcam clasa urlLoader. s a ¸ ori de cˆte ori dorim s˘ fort˘m reˆ arcarea claselor. Folosind ¸ ¸ metoda getURLs putem afla aceste adrese. In cazul ˆ care dorim s˘ avem posia a ın a bilitatea de a o reˆ arca. trebuie s˘ ınc˘ as a a folosim class-loadere proprii ¸i s˘ instantiem noi obiecte de tip ClassLoader.addURL(new File("c:\\clase"). S˘ presupunem c˘ ˆ directorul s s a a ın c:\clase\demo exist˘ clasa cu numele Test. // Adaugam directorul sub forma unui URL urlLoader. 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.toURL()). 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. o variant˘ simplist˘ fiind prezentat˘ mai jos: a a a public class MyClassLoader extends URLClassLoader{ public MyClassLoader(URL[] urls){ super(urls). ea nu va mai a a ınc˘ a putea fi desc˘rcat˘ explicit din memorie. Dup˘ ce o clas˘ a fost ˆ arcat˘ folosind un class loader. 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. Implicit.getClass(). deoarece a fost modificat˘ ¸i recompilat˘.loadClass("demo.Test").1. Crearea unui class a a ¸a ınc˘ loader propriu se face uzual prin extinderea clasei URLClassLoader.

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

lang.1 Examinarea claselor ¸i interfetelor s ¸ Examinarea claselor ¸i interfetelor se realizeaz˘ cu metode ale clasei java.Class • java.lang. . MECANISMUL REFLECTARII • java. Class c = java.lang.awt. Aflarea numelui unei clase .class.. String nume = clasa. a a a a a s ¸a diferentierea acestora f˘cˆndu-se prin intermediul metodei isInterface. s ¸ a un obiect de acest tip putˆnd s˘ reprezinte atˆt o clas˘ cˆt ¸i o interfat˘.reflect ¸i anume: s – Array – Constructor – Field – Method – Modifier 453 16.getName(). diferentierea lor f˘cˆndu¸ a a se cu ajutorul metodei isPrimitive.Button.2.getClass().˘ 16.class.class.Class. Tipurile primitive sunt descrise ¸i ele de instante de tip Class avˆnd forma s ¸ a TipPrimitiv.2. double.lang. Class c = Class.class: int.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. etc.Object • Clasele din pachetul java.getClass().Se realizeaz˘ cu metoda getName: a Class clasa = obiect.

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

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

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

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

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

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

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

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

Sign up to vote on this title
UsefulNot useful