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 ¸

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

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

10 CUPRINS .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ın s a class Student { . C++ ¸i limbajul de asamblare.. } }// Eroare la compilare ! • native In cazul ˆ care avem o libr˘rie important˘ de functii scrise ˆ alt limbaj ın a a ¸ ın de programare. } class StudentInformatica extends Student { float calcMedie(float note[].2. Are ca efect construirea a a unui monitor care nu permite executarea metodei. ın ¸ ¸ ˆ aceea¸i manier˘. float ponderi[]) { return 10. 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[]) { .. cum ar fi C. (vezi ”Fire de executie”) a ¸ . decˆt unui singur fir de executie. acestea s pot fi refolosite din programele Java. la un moment dat. final float calcMedie(float note[].. fiind critic˘ pentru consistenta a a ın a ¸ st˘rii unui obiect.00. ˆ functie de notele obtinute la examene.3. Acest lucru este ın a a util dac˘ respectiva metod˘ are o implementare care nu trebuie schima a bat˘ sub nici o form˘ ˆ subclasele ei.. } .. ¸ • synchronized Este folosit ˆ cazul ˆ care se lucreaz˘ cu mai multe fire de executie iar ın ın a ¸ metoda respectiv˘ gestioneaz˘ resurse comune. indiferent de facultatea la care sunt. 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.. studentilor unei universit˘¸i trebuie s˘ a ¸ at a li se calculeze media finala. De exemplu.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

76 CAPITOLUL 2. OBIECTE SI CLASE ¸ .

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

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

out. Folosind mecanismul exceptiilor metoda ¸ citeste ˆsi poate trata singur˘ erorile care pot surveni pe parcursul executiei ı¸ a ¸ sale.out.out. finally { // Cod care se executa indiferent // daca apar sau nu exceptii } 79 S˘ consider˘m urm˘torul exemplu: citirea unui fi¸ier octet cu octet ¸i a a a s s afisarea lui pe ecran. f. . // Inchidem fisierul System. } Aceast˘ secvent˘ de cod va furniza erori la compilare deoarece ˆ Java a ¸a ın tratarea erorilor este obligatorie. .println("Deschidem fisierul " + fis).println("\\nInchidem fisierul " + fis).read()) != -1) System. ”PRINDEREA” SI TRATAREA EXCEPTIILOR ¸ ¸ } catch (TipExceptie2 variabila) { // Tratarea exceptiilor de tipul 2 } . Tratarea exceptiilor este realizat˘ complet chiar de c˘tre metoda a ¸ a a citeste. f = new FileReader(fis). // Citim si afisam fisierul caracter cu caracter int c.2. .close(). 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.print((char)c). // Deschidem fisierul System.3. while ( (c=f. 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˘.

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

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

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

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

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

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

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

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

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

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

. 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. 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.90 CAPITOLUL 3. obiecte de tip Error. sunt cazuri speciale de exceptii generate ¸ de functionarea anormal˘ a echipamentului hard pe care ruleaz˘ un pro¸ a a gram Java ¸i sunt invizibile programatorilor. a ¸ Erorile.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. care s sunt la rˆndul lor superclase pentru o serie ˆ a ıntreag˘ de tipuri de exceptii. Exception ¸i RuntimeException.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

a . Solutia la aceast˘ problem˘ este a ¸ ¸ a a folosirea adaptorilor.. public void metoda_n() {} } In situatia cˆnd avem nevoie de un obiect de tip X vom folosi clasa ¸ a abstract˘. 143 Aceast˘ abordare poate fi nepl˘cut˘ dac˘ avem frecvent nevoie de obiecte a a a a ale unor clase ce implementeaz˘ interfata X.. supradefinind doar metoda care ne intereseaz˘: a a functie(new XAdapter() { public void metoda_1() { // Singura metoda care ne intereseaza .8. ADAPTORI }).. aa ¸ public abstract class XAdapter implements X { public void metoda_1() {} public void metoda_2() {} . 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”.5..

144 CAPITOLUL 5. INTERFETE ¸ .

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

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

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

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

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

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

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

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. 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 . cerc. Din acest motiv. Este recomandat ca strategia de organizare a a fi¸ierelor surs˘ s˘ respecte urm˘toarele conventii: s a a a ¸ • Codul surs˘ al claselor ¸i interfetelor s˘ se gaseasc˘ ˆ fi¸iere ale c˘ror a s ¸ a a ın s a nume s˘ fie chiar numele lor scurt ¸i care s˘ aib˘ extensia .1 Organizarea fi¸ierelor s Organizarea fi¸ierelor surs˘ s a Orice aplicatie nebanal˘ trebuie s˘ fie construit˘ folosind o organizare ier¸ a a a arhic˘ a componentelor sale. ci doar recomandat. Pentru a simplifica lucrurile.java. s˘ a a a presupunem c˘ dorim s˘ cre˘m clase care s˘ descrie urm˘toarele notiuni: a a a a a poligon. ın a s ¸ s Cu alte cuvinte. poliedru. 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 . 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. un director va contine surse pentru clase ¸i interfete ¸ s ¸ din acela¸i pachet iar numele directorului va fi chiar numele pachetus lui. S˘ presupunem c˘ dorim crearea unor compoa a nente care s˘ reprezinte diverse notiuni matematice din domenii diferite.java. algebr˘.2. Intr-un fi¸ier surs˘ s a pot exista oricˆte clase sau interfete care nu sunt publice.2 6. 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. sfer˘. functie. sau compilatorul s a ¸ s va furniza o eroare. grup. a ¸ cum ar fi geometrie. analiz˘.152 CAPITOLUL 6. ˆ ıntr-un fi¸ier surs˘ nu pot exista s a dou˘ clase sau interfete publice. ORGANIZAREA CLASELOR 6. s ¸ Vom clarifica modalitatea de organizare a fi¸ierelor surs˘ ale unei aplicatii s a printr-un exemplu concret. etc.

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

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

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

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

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

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

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

160 CAPITOLUL 6. ORGANIZAREA CLASELOR .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

COLECTII ¸ .176 CAPITOLUL 7.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

198 CAPITOLUL 8. SERIALIZAREA OBIECTELOR .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

exit(0). ı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. iar ¸ a a a a a ın clasele anonime sunt clase interne folosite pentru instantierea unui singur ¸ obiect de un anumit tip. s a a a Vom vedea ˆ a c˘ acest dezavantaj poate fi eliminat prin folosirea unei clase ıns˘ a anonime. } } In tabelul de mai jos sunt dati toti adaptorii interfetelor de tip ”listener” ¸ ¸ ¸ . ¸ 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. va crea o metod˘ a clasei respective. 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. INTERFATA GRAFICA CU UTILIZATORUL ¸ clasa Fereastra nu poate extinde WindowAdapter deoarece ea extinde deja clasa Frame ¸i din acest motiv am construit o nou˘ clas˘ numit˘ Ascultator. Un exemplu tipic de folosire a lor este instantierea ¸ . 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.230 ˘ CAPITOLUL 9.se oberv˘ c˘ o interfat˘ XXXListener are un adaptor de tipul XXXAdapter. pur ¸i simplu.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

268 ˘ CAPITOLUL 9. INTERFATA GRAFICA CU UTILIZATORUL ¸ .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Aceste informatii pot fi aflate prin intermediul constantelor ¸ definite de interfat˘: ¸a . In sectiunea urm˘toare vom detalia acest aspect.10. 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. 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. FOLOSIREA IMAGINILOR 289 Metoda drawImage returneaz˘ true dac˘ imaginea a fost afi¸at˘ ˆ ˆ a a s a ın ıntregime ¸i false ˆ caz contrar. pˆn˘ la ın ın ¸ a a afi¸area sa complet˘. Intregul f lags furnizeaz˘ informatii despre starea ¸ a ¸ transferului. Ca urmare. dup˘ care red˘ imediat conınc˘ s a a trolul apelantului. implementat˘ de clasa Component ¸i deci de toate compoa s nentele. ¸ a 10. int y. int flags. int x. Aceast˘ interfat˘ descrie obiecte care au ˆ a ¸a ınceput s˘ utilizeze o imaga ine incomplet˘ ¸i care trebuie anuntate de noile date obtinute ˆ legatur˘ cu as ¸ ¸ ın a imaginea respectiv˘. f˘r˘ interventia programatorului.5.5. a Interfata ImageObserver are o singur˘ metod˘ numit˘ imageUpdate. Acest a aa ¸ lucru se ˆ ampl˘ deoarece metoda drawImage nu face decˆt s˘ declan¸eze ıntˆ a a a s procesul de ˆ arcare ¸i desenare a imaginii. De aceea a ¸ s a trebuie s˘ existe un mecanism prin care componenta s˘ fie redesenat˘ aua a a tomat ˆ momentul ˆ care au mai sosit informatii legate de imagine. 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˘. 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˘. ¸ a a a ce va fi apelat˘ periodic de firul de executie (creat automat) care se ocup˘ a ¸ a cu ˆ arcarea imaginii. Acest mecanism este realizat prin intermediul interfetei s a ¸ ImageObserver. Formatul acestei metode este: ınc˘ boolean imageUpdate (Image img.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. int w.

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

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

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

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

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

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

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

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

298 CAPITOLUL 10. DESENAREA .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

start () .2.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˘. ˆ ıntrucˆt primul apel este c˘tre contorul fir1. la extinderea ei obtineam implementarea indis ¸ rect˘ a interfetei. A¸adar. start () .2. s-ar crede c˘ acest program va afi¸a prima dat˘ nua ¸ a s a merele de la 0 la 100 cu pasul 5. a ¸ a s el fiind controlat de procesor ˆ ıntr-o manier˘ ”aparent” aleatoare. a ¸ s ¸a a a f˘r˘ a extinde clasa Thread. 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.lang ¸i este definit˘ astfel: ¸ a s ın s a . Thread // incorect ! In acest caz. rezultatul obtinut va fi o intercalare de valori produse de ıns˘ ¸ cele dou˘ fire ce ruleaz˘ simultan. deci rezultatul afi¸at pe ecran a a s ar trbui s˘ fie: a 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 100 110 120 130 140 150 160 170 180 190 200 In realitate ˆ a.12. 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. aa Interfata Runnable se g˘se¸te ˆ pachetul java. fir2 . interfat˘ Runnable permite unei clase s˘ fie activ˘. ¸tiind c˘ ˆ Java nu este permis˘ mo¸tenirea a s a ın a s multipl˘ ? a class FirExecutie extends Parinte. apoi numerele de la 100 la 200 cu pasul 10. CREAREA UNUI FIR DE EXECUTIE ¸ // Numara de la 100 la 200 cu pasul 10 fir1 . 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. din acest motiv. Clasa Thread implementeaz˘ ea ˆ a¸i interfata ¸ a ıns˘s ¸ Runnable ¸i.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

382 CAPITOLUL 12. FIRE DE EXECUTIE ¸ .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

400 CAPITOLUL 13. PROGRAMARE ˆ RETEA IN ¸ .

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

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

} } 403 Pentru a putea fi executat˘ de browser. Mozilla. avˆnd continutul de mai jos: a s a ¸ . clasa principala a appletului va fi salvat˘ ˆ a a a ıntr-un fi¸ier cu acela¸i nume ¸i extensia .class. s ¸ javac FirstApplet. Rularea appletului Applet-urile nu ruleaza independent. 0. 0. A¸adar.drawOval(100. g. S˘ cons ın a sider˘m fi¸ierul simplu. vom salva clasa de mai sus s s s s ˆ ıntr-un fi¸ier FirstApplet.java. Opera. Salvarea fisierelor surs˘ a Ca orice clas˘ public˘. clasa principal˘ a appletului trea a buie s˘ fie public˘.java.java In cazul ˆ care compilarea a reu¸it va fi generat fisierul FirstApplet. CREAREA UNUI APPLET SIMPLU public void paint (Graphics g) { g.0. g. Ele pot fi rulate doar prin intermediul unui browser: Internet Explorer. a a 2. 110. folosind compis ¸ latorul javac apelat pentru fi¸ierul ce contine appletul.2. Netscape. this).150.drawString("Hello! My name is Taz!".drawImage(img. sau printr-un program special cum ar fi appletviewer din kitul de dezvoltare J2SDK. ın s 4. 25). s 3.50).html. etc. Compilarea Compilarea se face la fel ca ¸i la aplicatiile independente. Pentru a executa un applet trebuie s˘ facem dou˘ operatii: a a ¸ • Crearea unui fi¸ier HTML ˆ care vom include applet-ul.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. etc.html. In unele situatii ˆ ¸ ¸ ıntreaga executie a appletului se consum˘ la ¸ a etapele de initializare ¸i pornire. 14. ¸ s . • Inc˘rcarea ˆ memorie a ın Este creat˘ o instanta a clasei principale a appletului ¸i ˆ a ¸ s ıncarcat˘ ˆ a ın memorie. • Initializarea ¸ Este apelat˘ metoda init ce permite initializarea diverselor variabile.html folosind unul din browser-ele amintite sau efectuˆnd apelul: a appletviewer simplu.3 Ciclul de viat˘ al unui applet ¸a Executia unui applet ˆ ¸ ıncepe ˆ momentul ˆ care un browser afi¸eaz˘ o pagin˘ ın ın s a a Web ˆ care este inclus appletul respectiv ¸i poate trece prin mai multe etape.class width=400 height=400> </applet> </body> </html> • Vizualizarea appletului: se deschide fisierul simplu. ı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.404 CAPITOLUL 14. APPLETURI <html> <head> <title>Primul applet Java</title> </head> <body> <applet code=FirstApplet. a ¸ citirea unor parametri de intrare.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

444 CAPITOLUL 15. LUCRUL CU BAZE DE DATE .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Sign up to vote on this title
UsefulNot useful