Tudor Sorin Vlad Tudor (Huţanu) JAVA L&S Info-mat Copyright 2005-2018 Editura L&S INFO-MAT ISBN: 978-973-7658-03-6 Această carte în format electronic este protejată de legea dreptului de autor. Toate drepturile asupra acestei lucrǎri aparţin editurii L&S INFO-MAT. Reproducerea integralǎ sau parţialǎ a textului din aceastǎ carte este posibilǎ doar cu acordul în scris al editurii L&S INFO-MAT. După confirmarea plății, fiecare carte poate fi descărcată de maximum 5 ori şi este disponibilă 30 de zile. Drepturi de autor / Copyright. Fiecare PDF este securizat în 28 de zone cu watermark invizibil (id comandă, e-mail) pentru a nu putea fi distribuit pe alte căi virtuale. Sistemul este unul complex şi se detectează automat persoana care a redistribuit cartea ilegal. Redistribuirea ilegală este pedepsită de lege! Mulțumim! Adresa: Str. Stânjeneilor nr. 6, Sector 4, Bucureşti E-mail: office@ls-infomat.ro www.ls-infomat.ro www.manuale-de-informatica.ro Biblioteca Digitală de Informatică “Tudor Sorin” www.infobits.ro Laboratorul Virtual de Informatică şi TIC http://lab.infobits.ro Cuprins Capitolul 1. Java, primele noţiuni.......................................... 11 1.1. Instalarea mediului de programare ........................................ 12 1.2. Primul program ..................................................................... 14 1.3. Conceptul de Maşină Virtuală Java (JVM)................................. 15 1.4. Tipuri de aplicaţii Java ........................................................... 16 1.5. Comentarii ............................................................................ 17 1.6. Afişarea şirurilor de caractere ................................................ 17 1.7. Programe care se găsesc în alte folder-e ............................... 17 Capitolul 2. Tipuri şi operaţii de date ........................................ 19 2.1. Tipuri de date ........................................................................ 20 2.1.1. Tipurile de date primitive ....................................................... 20 2.1.2. Tipul referinţă ........................................................................ 22 2.1.3. Observaţii importante ............................................................ 22 2.2. Operatori ............................................................................... 23 2.2.1. Operatori aritmetici ................................................................ 23 2.2.2. Operatori relaţionali ............................................................... 25 2.2.3. Operatori de egalitate ............................................................ 25 2.2.4. Operatori de incrementare şi decrementare ........................... 25 2.2.5. Operatori logici ...................................................................... 26 2.2.6. Operatori logici pe biţi ........................................................... 27 2.2.7. Operatori de atribuire ............................................................ 28 2.2.8. Operatori condiţional ............................................................. 30 2.2.9. Operatori de conversie explicită ............................................. 31 2.2.10. Prioritatea (precedenţa) operatorilor .................................... 31 2.3. Instrucţiuni ............................................................................ 32 2.4. Masive ................................................................................... 38 2.5. Citirea datelor de la tastatură ................................................ 43 2.6. Probleme rezolvate ................................................................ 45 Probleme propuse ........................................................................ 49 Răspunsuri ................................................................................... 55 6 Cuprins Capitolul 3. Metode ..................................................................... 57 3.1. Generalităţi ............................................................................ 58 3.2. Structura unei metode şi apelul ei .......................................... 59 3.3. Transmiterea parametrilor ..................................................... 61 3.4. Despre variabile ..................................................................... 63 3.5. Exemple de utilizare ale metodelor ........................................ 64 3.5.1. Exemple elementare............................................................... 64 3.5.2. Un exemplu de backtracking n Java ...................................... 67 3.6. Metode recursive ................................................................... 68 3.7. Exemple de utilizare a metodelor recursive.............................. 70 3.7.1. Exemple elementare............................................................... 70 3.7.2. Backtracking ............................................................. 71 3.8 Supra ncărcarea metodelor ..................................................... 73 Probleme propuse ........................................................................ 74 Răspunsuri ................................................................................... 79 Capitolul 4. Clase – primele noţiuni, exemple ........................... 80 4.1. Ce este o clasă ? .................................................................... 81 4.2. Constructori .......................................................................... 83 4.3. Date membru statice şi metode statice .................................. 84 4.4. Cuvântul cheie this .............................................................. 85 4.5. Referinţe către obiecte ........................................................... 85 4.6. Masive de obiecte .................................................................. 87 4.7. Aplicaţii ale noţiunilor prezentate............................................ 88 4.7.1. Lucrul cu numere raţionale...................................................... 89 4.7.2. Lucrul cu mulţimi de numere naturale ..................................... 92 4.8. Garbage Collector ........................................................... 96 4.9. Cum sunt memorate clasele ? ................................................ 96 4.10. Pachete................................................................................ 98 4.11. Clase interioare ................................................................. 101 4.12. O problemă de terminologie .............................................. 102 Probleme propuse ...................................................................... 103 Răspunsuri ................................................................................. 106 Bazele programării în Java 7 Capitolul 5. Studiul unor clase ale limbajului Java ............... 110 5.1. Clasa Math .......................................................................... 111 5.2. Clasa String ...................................................................... 112 5.2.1. Constructorii şi lungimea unui şir de caractere ................... 112 5.2.2. Compararea şirurilor de caractere ....................................... 113 5.2.3. Subşiruri ............................................................................. 114 5.2.4. ş ..................................... 115 5.2.5. Parametrii metodei main() ................................................ 116 5.2.6. Aplicaţii............................................................................... 117 5.3. Clasa StringTokenizer ...................................................... 119 5.4. Clase nfăşurătoare .............................................................. 120 5.5. Lucrul cu numere mari ......................................................... 123 Probleme propuse ...................................................................... 125 Indicaţii / rezolvări ..................................................................... 128 Capitolul 6. Extinderea claselor .......................................... 131 6.1. Noţiuni generale .................................................................. 132 6.2. Un exemplu de extindere al unei clase ................................. 134 6.3. O modalitate de simulare a extinderii multiple ................... 138 6.4. Referinţe către obiectele superclaselor şi referinţe către obiectele subclaselor .................................................................. 139 Probleme propuse ...................................................................... 142 Indicaţii / rezolvări ..................................................................... 144 Capitolul 7. Noţiuni avansate de programare orientată pe obiecte .............................................................................. 147 7.1. Polimorfism ......................................................................... 148 7.2. Un exemplu de polimorfism................................................. 150 7.3. Clase abstracte.................................................................... 152 7.4. Un exemplu de clasă abstractă ............................................ 153 7.5. Interfeţe .............................................................................. 155 7.6. Aplicaţii ale interfeţelor ....................................................... 158 7.7. Modificatori ......................................................................... 161 8 Cuprins Probleme propuse ...................................................................... 165 Răspunsuri ................................................................................. 167 Capitolul 8. Excepţii ........................................................... 169 8.1. Noţiunea de excepţie ........................................................... 170 8.2. Mecanismul de tratare a excepţiilor ..................................... 170 8.3. Metodele care pot returna, n caz de excepţii, obiecte ale unor alte clase .................................................................................... 176 8.4. Exemple de tratare a excepţiilor .......................................... 177 Probleme propuse ...................................................................... 178 Răspunsuri ................................................................................. 179 Capitolul 9. Alte clase esenţiale în Java ............................... 181 9.1. Clasa Vector ....................................................................... 182 9.2. Fişiere ................................................................................. 184 9.2.1. Noţiunea de flux ................................................................. 184 9.2.2. Fluxuri de octeţi .................................................................. 184 9.2.3. Fluxuri de caractere ............................................................ 186 9.2.4. Intrări de la tastatură .......................................................... 188 9.3 Fire de execuţie. ................................................................... 188 Probleme propuse ...................................................................... 190 Răspunsuri ................................................................................. 191 Capitolul 10. Iniţiere în programarea vizuală ...................... 193 10.1. Prima fereastră .................................................................. 194 10.2. Mecanismul prin care se ataşează componente ferestrei. Clasa Container ................................................................................. 195 10.3. Un mecanism prin care butoanele răspund evenimentului de “apăsare” .................................................................................... 197 10.4. Clasa JComponent ............................................................. 198 10.5. Clasa ToolKit .................................................................. 200 10.6. Poziţionarea componentelor .............................................. 200 10.6.1. Poziţionarea absolută ........................................................ 201 Bazele programării în Java 9 10.6.2. Gestionarul de poziţionare FlowLayout ........................... 201 10.6.3. Gestionarul de poziţionare GridLayout ........................... 203 10.6.4. Gestionarul de poziţionare BorderLayout ........................ 204 10.6.5. Gestionarul GridBagLayout ............................................. 205 10.6.6. Gestionarul CardLayout ................................................... 207 10.7. Studiul principalelor componente ...................................... 208 10.7.1. Componente de tip JButton ............................................. 208 10.7.2. Componente de tip JLabel ............................................... 209 10.7.3. Componente de tip JPanel ............................................... 210 10.7.4. Componente de tip JTextField ....................................... 211 10.7.5. Componente de tip JComboBox ......................................... 214 10.7.6. Componente de tip JCheckBox şi JRadioButton şi gruparea lor .................................................................................. 215 10.7.7. Meniuri ............................................................................. 218 10.7.8. Cutii (casete) de dialog predefinite .................................... 221 10.7.8.1. Cutii de dialog de intrare....................................... 222 10.7.8.2. Cutii de dialog pentru afişarea mesajelor .............. 222 10.7.8.3. Cutii de dialog de confirmare ................................ 223 10.7.8.4. Cutii de dialog cu opţiuni ...................................... 223 10.7.9. Componente de tip JTextArea ........................................... 225 10.7.10. Componente de tip JProgressBar ..................................... 227 10.7.11. Componente de tip JSpinner ........................................... 228 10.7.12. Cutii de tip Open / Save ................................................ 231 10.7.13. Componente de tip JColorChooser ............................. 235 10.7.14. Componente de tip JToolBar ....................................... 237 10.7.15. Componente de tip JTable ........................................... 238 10.8. Mai mult despre clasa Container ..................................... 242 10.9. Cutii de dialog ................................................................... 246 10.10. Clasa Graphics .............................................................. 250 10.10.1. Afişarea imaginilor .......................................................... 250 10.10.2. Cum scriem ? .................................................................. 251 10.10.3. Cum desenăm ?............................................................... 252 10.11. Clasa Graphics2D .......................................................... 254 10 Cuprins 10.11.1. Cum desenăm ?............................................................... 254 10.11.2. Stabilirea modului de trasare a liniilor ............................. 256 10.11.3. Gradient .......................................................................... 257 10.11.4. Clasa BufferedImage .................................................... 259 10.11.5. Texturi ............................................................................ 260 10.11.6. Dreptunghiuri 3D ............................................................ 262 10.11.7. Spaţiul de coordonate al utilizatorului ............................ 263 10.12. Evenimente ...................................................................... 265 10.12.1. Generalităţi ..................................................................... 265 10.12.2. Evenimente de tip Action ......................................... 265 10.12.3. Evenimente de tip MouseEvent ............................... 267 10.12.4. Focus, evenimente de tip FocusEvent .................... 271 10.12.6. Evenimemente de selectare a item-ilor ........................... 273 10.12.7. Evenimemente pentru fereastră ...................................... 274 10.13. Animarea imaginilor ........................................................ 276 Probleme propuse ...................................................................... 278 Indicaţii ...................................................................................... 281 Capitolul 11. Applet-uri ..................................................... 285 11.1. Generalităţi ........................................................................ 286 11.2. Crearea şi executarea applet-urilor ................................... 286 11.3. Arhive Java şi atributele elementului APPLET ...................... 287 11.4. Redefinirea unor metode ale applet-ului ........................... 289 11.5. Afişarea imaginilor. Clasa URL ........................................... 290 11.6. Redarea sunetelor ............................................................. 291 11.7. Exemple de applet-uri....................................................... 292 CAPITOLUL 1 Java, primele noţiuni Din cuprins: Instalarea mediului de programare Primul program Maşina Virtuală Java Tipuri de aplicaţii Comentarii Afişarea şirurilor de caractere Programe care se găsesc în alte folder-e 12 Bazele programării în Java 1.1. Instalarea mediului de programare Pentru a lucra \n Java, utiliz`m soft-ul pus la dispozi]ie de firma Sun, creatoarea limbajului. Mai precis, utiliz`m Java 2 Platform, Standard Edition (J2SE), v1.4.2, Software Development Kit (SDK). |n cele ce urmeaz`, consider`m c` lucr`m sub sistemul de operare Windows 2000 [i calculatorul are acces la Internet. A. |ncepem prin a download-a softul. Adresa este: http:\\java.sun.com. Evident, vom alege o versiune recent` pentru Windows. |n continuare, instal`m soft-ul download-at. De exemplu, eu l-am instalat \n c:\j2sdk1.4.2_04. Poate p@n` la apari]ia acestei c`r]i ve]i g`si versiuni mai noi. B. Pentru c` soft-ul pus la dispozi]ie de firma Sun lucreaz` prin comenzi date de la tastatur` (ca \n MS-DOS, un sistem de operare mai vechi, creat de Microsoft) va trebui s` folosim un program, numit CMD.exe, care simuleaz` sistemul de operare amintit. Programul se g`se[te \n folder-ul WINNT. Identifica]i-l cu Search. El creeaz` o fereastr` prin care se pot da comenzi MS-DOS. C. Pentru a utiliza cu u[urin]` acest WINNT, vom crea pe Desktop un shortcut c`tre el (vede]i al`turat). D. Va trebui ca fereastra CMD s` fie deschis` \n subfolder-ul bin, al folder-ului care con]ine softul downloadat [i instalat. Executa]i click cu butonul drept al mouseului [i selecta]i Properties. La apari]ia cutiei de dialog al`turate, intoduce]i calea folder-ul amintit \n edit-ul Start in. Dac` shortcut-ul a fost creat corect, atunci c@nd executa]i dublu click pe el va ap`rea fereastra al`turat`, de unde vom da comenzi de la tastatur`. Capitolul 1. Java, primele noţiuni 13 E. |ntruc@t \n perioada de ini]iere programele noastre se vor g`si \n folder-ul bin, pentru a lucra mai u[or, este recomandabil s` cre`m pe Desktop [i un shortcut c`tre acest folder. F. De[i de la instalare, mediul Java ar folder-ul bin, este bine ca dvs. s`-l seta]i vom folosi variabila de sistem CLASSPATH ini]ializat` cu respectiva cale. Pentru aceasta, trebui, implicit, s` lucreze \n corespunz`tor. |n acest scop, (calea c`tre clase) care este vom respecta urm`torii pa[i: 1. Din meniul Start, apela]i Settings, Control Panel [i System. 2. Va ap`rea o cutie de dialog Environment Variables... \n care 3. |n cutia de dialog de mai jos, ap`sa]i New. 4. |n cutia de dialog al`turat`, introduce]i numele variabilei de sistem (CLASSPATH) apoi calea c`tre folder-ul bin. Aten]ie! Calea trebuie s` corespund` locului unde ave]i instalat mediul Java pe calculatorul dv. Apoi, ap`sa]i OK! selecta]i Advanced [i 14 Bazele programării în Java 1.2. Primul program De acum, putem scrie primul program. Trebuie s` [tim c` mediul Java, pus la dispozi]ie de firma Sun, nu ne ofer` un editor de text. Din acest motiv, textul program va fi introdus cu ajutorul NOTEPAD-ului, dar va trebui s` fim aten]i ca extensia fi[ierului text astfel ob]inut s` fie .java. Nu uita]i: pentru \nceput, fi[ierul text care con]ine programul trebuie s` se g`seasc` \n folder-ul bin. Pentru a introduce [i rula un program, vom respecta pa[ii urm`tori: A. Vom deschide shortcut-ul c`tre bin din meniul flotant, vom alege New [i Text Document, apoi schimb`m numele fi[ierului \n prima.java. Fi[ierul cu acest nume va fi deschis din meniul flotant asociat, cu Open with... [i Notepad. Apoi, se introduce programul de mai jos, care afi[eaz` mesajul Acesta este primul program Java [i salv`m programul: class prima { public static void main(String[] args) { System.out.println("Acesta este primul program Java");} } Este obligatoriu ca numele clasei s` coincid` cu numele fi[ierului. |n exemplu, clasa se nume[te prima, iar fi[ierul este prima.java. Este obligatoriu ca extensia fi[ierului text s` fie .java ! B. Din fereastra CMD, apel`m compilatorul Java prin comanda: javac prima.java |n urma acestei comenzi, se va crea fi[ierul prima.class. Acest fi[ier con]ine programul compilat. Verifica]i existen]a lui \n bin! C. Pentru a executa programul astfel compilat, vom da comanda: java prima Iat` cum arat` acum fereastra CMD: Capitolul 1. Java, primele noţiuni 15 Dac` a]i reu[it s` rula]i acest prim program, a]i f`cut un pas important. |nseamn` c` a]i instalat corect mediul [i de acum pute]i lucra lini[it. Sunt mul]i cei care se \mpotmolesc \n acest punct [i, din acest motiv, renun]`… S` arunc`m o privire asupra programului: Orice program este inclus \ntr-o clas`. No]iunea de clas` apar]ine program`rii orientate pe obiecte [i va fi explicat` pe larg \n aceast` carte. |n exemplu, clasa se nume[te prima. A[a cum am precizat, numele clasei trebuie s` coincid` cu numele fi[ierului text surs` (cel creat cu NOTEPAD), numai c` acesta din urm` trebuie s` aib` extensia .java. Orice program are o metod` (func]ie main()) [i executarea sa \ncepe cu instruc]iunile acestei metode. |n exemplu, programul afi[eaz` un [ir de caractere. Instruc]iunea (apelul de metod`) care afi[eaz` acest [ir de caractere este system.out.println(). Dup` afi[are, cursorul sare pe r@ndul urm`tor. |n Java, \n locul termenului consacrat “func]ie”, vom folosi pe acela de metod`. Este obligatoriu ca metoda main() s` con]in` anumi]i parametri de intrare: String[] args. Asupra semnifica]iei acestor parametri revenim \n capitolele urm`toare. Elementele public [i static sunt modificatori. Prezen]a lor antetul metodei main() este obligatorie. {i asupra lor vom reveni. void este tipul metodei main(). Semnifica]ia este cea din C++, adic` metoda nu returneaz` nici o valoare. |n Java, se face distinc]ie \ntre literele mari [i cele mici. De exemplu, Mama si mama sunt identificatori diferi]i. \n 1.3. Conceptul de Maşină Virtuală Java (JVM) Una dintre cerin]ele care au stat la baza cre`rii limbajului Java a fost aceea de a ob]ine un limbaj portabil. Aceasta \nseamn` c` un program scris pe un anumit calculator, pe care ruleaz` un anumit sistem de operare, s` poat` rula f`r` modific`ri [i pe un alt calculator, pe care ruleaz` alt sistem de operare. De exemplu, s` se poate scrie un program care s` fie rulat pe Windows [i pe Linux. 16 Bazele programării în Java Pentru a rezolva aceast` problem`, cei de la Sun au recurs la urm`torul procedeu: Fiecare utilizator al unui sistem de operare poate download-a mediul specific acelui sistem de operare. De aceasta v-a]i convins atunci c@nd a]i download-at mediul pentru Windows. Mediul specific pentru un anumit sistem de operare con]ine un compilator special creat pentru el. El preia programul din fi[ierul surs` [i “\l traduce” \ntr-un cod anume, numit byte-code. Compilatorul este programul javac, iar fi[ierul compilat are extensia .class. Programele \n byte-code sunt rulate pe a[a numita Ma[in` Virtual` Java (JVM). Ma[ina virtual` Java este un suport soft care trebuie s` fie instalat pe calculatoarele care ruleaz` astfel de fi[iere. C@nd a]i instalat mediul Java, implicit a]i instalat [i ma[ina virtual` java. De altfel, ma[ina virtual` Java poate fi instalat` [i \n absen]a mediului de dezvoltare Java. Un fi[ier \n byte-code (extensia .class) poate fi rulat pe orice calculator, indiferent de sistemul de operare pe care-l are, dac` are instalat` ma[ina virtual` Java. Practic, se ia prima instruc]iune din fi[ierul byte-code, este tradus` \n instruc]iuni ale calculatorului pe care ruleaz` aplica]ia [i acestea din urm` sunt executate; se ia o a doua instruc]iune din byte-code carte se traduce [i se ruleaz`, [.a.m.d. Se poate observa c` Java are [i un compilator care traduce sursa \n byte-code (javac.exe) dar [i un interpreter care traduce [i execut` fiecare instruc]iune din byte-code \n instruc]iuni ale calculatorului pe care se execut` aplica]ia. Datorit` faptului c` Java este \nzestrat instruc]iune, o traduce [i o execut`, apoi alt` [i o execut`...), programele se execut` mai compensat de procesoarele din ce \n ce mai performan]ele interpreterului. cu interpreter (ia o instruc]iune, o traduce lent. Acest fapt este performante, dar [i de 1.4. Tipuri de aplicaţii Java |n Java exist` trei tipuri de aplica]ii: 1. Aplica]ii de sine st`t`toare (stand-alone). Acestea sunt precum aplica]iile studiate \n Pascal sau C++: se ruleaz` pe un anumit calculator. 2. Aplica]ii care se ruleaz` pe partea de client (applet-uri). Un applet este alc`tuit dintr-unul sau mai multe fi[iere cu extensia .class [i este utilizat \n cadrul paginilor web. Practic, el este ata[at textului HTML, la fel Capitolul 1. Java, primele noţiuni 17 cum se ata[eaz` o imagine, iar fi[ierele care-l alc`tuiesc se transfer` pe site. El este adus pe calculatorul clientului atunci c@nd se apeleaz` pagina respectiv` [i este executat prin intermediul browser-ului. 3. Aplica]ii care se execut` pe partea de server (servlet-uri). ! |n aceast` carte sunt tratate doar aplica]iile din primele dou` tipuri. 1.5. Comentarii |n Java, se pot pune comentarii oriunde dorim, la fel ca [i \n C++. Ele sunt de dou` feluri: 1. Comentariile la nivel de linie: // tot ce urmeaz` dup` ele, pe linia celor dou` caractere, este considerat comentariu. 2. Comentarii pe mai multe linii se g`sesc \ntre /* [i */. class prima { // un comentariu public static void main(String[] args) { /* Acesta este alt comentariu */ System.out.println("Acesta este primul program Java");} } 1.6. Afişarea şirurilor de caractere Pentru afi[area datelor vom utiliza dou` metode: 1. System.out.print( sir_de_caractere); 2. System.out.println(sir_de_caractere); Ambele metode afi[eaz` [irul de caractere c`utat. Diferen]a dintre ele este dat` de faptul c` dup` afi[are, \n cazul System.out.print(), cursorul r`m@ne pe r@ndul curent (dup` ultimul caracter scris), iar \n cazul System.out.println(), dup` ce s-a scris [irul de caractere, cursorul trece pe linia urm`toare. 1.7. Programe care se găsesc în alte folder-e Nu este obligatoriu ca programele s` se g`sesc` \n folder-ul bin. Exist` posibilitatea ca programele Java s` se re]in` [i \n alte folder-e. S` vedem cum! Crea]i un folder pe C:\, numit TestJava. prima.java, prezentat \n primul paragraf. Muta]i acolo fi[ierul 18 Bazele programării în Java Pentru a-l compila, da]i comanda urm`toare, unde a]i scris [i calea c`tre fi[ier: javac c:\testjava\prima.java Pentru a-l rula, da]i comanda urm`toare, unde parametrul –classpath spune programului java.exe unde g`se[te fi[ierul cu extensia .class. java –classpath c:\testjava prima De altfel, parametrul classpath poate fi pus [i \n variabila de mediu CLASSPATH, a[a cum am ar`tat. Mai mult, calea se poate scrie \n continuarea celei existente, a[a cum vede]i mai jos: |n acest caz, la apelul programului Java nu mai este necesar s` d`m parametrul -classpath. Aten]ie: dac` set`m calea ca mai sus, cu ajutorul variabilei de mediu CLASSPATH, fi[ierul cu extensia .class se caut` \n fiecare cale trecut`, \n ordinea \n care au fost trecute c`ile. De exemplu, mai \nt@i fi[ierul cu extensia .class este c`utat \n bin [i apoi este c`utat \n TestJava. Aceasta \nseamn` c` dac` \l avem \n ambele locuri, este executat cel aflat \n bin. CAPITOLUL 2 Manipularea datelor Din cuprins: Tipuri de date Operatori Instrucţiuni Masive Citirea datelor de la tastatură Probleme rezolvate Probleme propuse 20 Bazele programării în Java 2.1. Tipuri de date |n teoria clasic` a limbajelor de programare, prin tip de date se \n]elege: o mul]ime de valori; o regul` prin care aceste valori se codific`; o mul]ime de opera]ii definite pe mul]imea valorilor. Limbajul Java extinde no]iunea de tip de date, la aceea de tip. Aici se lucreaz` cu clase, care descriu \ntr-o unic` structur` at@t date c@t [i metode (func]ii). Obiectele sunt instan]ieri ale claselor, deci fiecare obiect con]ine at@t date c@t [i metode. Asupra acestor probleme vom reveni, dar re]ine]i faptul c`, \n Java, prin tip vom \n]elege o clas`, iar un obiect are un anumit tip dac` rezult` ca instan]iere a unei clase. Totu[i, limbajul Java utilizeaz` [i tipuri \n sens clasic, vezi prima defini]ie. Pentru a nu se crea confuzii, aceste tipuri se numesc tipuri primitive. Astfel, avem tipuri de date primitive [i tipuri referin]`. 2.1.1. Tipurile de date primitive a) Tipuri \ntregi Tip Octe]i ocupa]i Numere \ntregi din intervalul byte short int long 1 2 4 8 [-128,127] [-32768,32768] [-2147483648, +2147483647] [-9223372036854775808,9223372036854775807] Exemple: Declar`m [i afi[`m mai multe variabile de tip \ntreg: short t=32767; byte z=-128, x=15; int a=100000; System.out.println(t); System.out.println(z); System.out.println(x); System.out.println(a); Capitolul 2. Tipuri şi operaţii de date 21 b) Tipuri reale Tip Octe]i ocupa]i Modulul valorilor \ntre float double 4 8 [3.410-38, 3.41038] [1.710-308,1.710308] Pentru ini]ializarea tipurilor reale se folosesc literali. Pentru tipul real float, literalii trebuie urma]i \n mod obligatoriu de litera f. Excep]ie fac literalii care reprezint` valori \ntregi. Exemple: 1. float a=3,b=2.5f,c=-7,d=3E2f,g=-2.4E-2f; Valorile cu care am ini]ializat variabilele sunt: 3, 2, 2.5, -7, 3102, -2.410-2. Acelea[i valori se folosesc pentru a ini]ializa variabile de tip double: 2. double a=3,b=2.5,c=-7,d=3E2,g=-2.4E-2; c) Tipul char O variabil` de tipul char re]ine un caracter. |n Pascal, C/C++, caracterele sunt re]inute prin utilizarea codului ASCII. |n Java, codul utilizat pentru memorarea caracterelor este Unicode [i, \n acest cod, un caracter ocup` 2 octe]i. Exemplu: mai jos pute]i observa declara]ia a trei variabile de tip char: char a='m', b='\u006d', c=109; System.out.println(a); System.out.println(b); System.out.println(c); Toate variabilele re]in caracterul m. Prima dat` caracterul este declarat \n mod clasic, a doua oar` este declarat prin codul s`u \n hexa [i a treia oar` este declarat \n zecimal. Cele afirmate sunt probate prin afi[are, pentru c` se afi[eaz` de trei ori m. Caracterele se pot declara sub form` de coduri escape: Caracter \\ \n \' \” \r \t \f Semnifica]ie backslash newline apostrof ghilimele carriage return tab salt la pagin` nou` 22 Bazele programării în Java Exemple: 1. char a='\''; am declarat caracterul apostrof. Dac` am \ncerca s` declar`m acest caracter prin char a='''; primim eroare de sintax`. 2. char b='\n'; am declarat caracterul newline. Dac` se afi[eaz` acest caracter, cursorul sare pe linia urm`toare. 3. char c='\\'; am declarat caracterul backslash. Dac` am \ncerca s` declar`m acest caracter prin char a='\'; primim eroare de sintax`. d) Tipul boolean O variabil` de acest tip poate re]ine la un moment dat, una din cele dou` valori: false (fals) sau true (adev`rat). Exemplu: se declar`, se ini]ializeaz` [i se afi[eaz` con]inutul unei variabile de tip boolean: boolean c=true; System.out.println(c); Metodele System.out.print() [i System.out.println() permit afi[area tuturor tipurilor primitive. 2.1.2. Tipul referinţă O variabil` de tip referin]` re]ine o referin]` (adres`) c`tre un obiect. Cu ajutorul referin]ei, putem accesa datele membru [i metodele obiectului. Numele tipului unei astfel de variabile coincide cu numele clasei. Cum obiectele sunt instan]eri ale claselor [i cum putem proiecta o infinitate de clase, \nseamn` c` exist` o infinitate de de tipuri referin]`. Prin abuz de limbaj, vom spune despre o variabil` care poate re]ine o referin]` c`tre un anumit obiect. c` este de tip referin]`. Orice variabil` de tip referin]` poate re]ine valoarea null. Ea are semnifica]ia de “nici o referin]`”. 2.1.3. Observaţii importante A[a cum am ar`tat, cu ajutorul celor dou` metode, System.out.print() [i System.out.println(), putem afi[a con]inuturile variabilelor de un tip primitiv. Mai avem de precizat dou` lucruri esen]iale: a. Dac` \n corpul unei metode, \n exemplu main(), se g`se[te o variabil` neini]ializat` [i se \ncearc` afi[area con]inutului pe Capitolul 2. Tipuri şi operaţii de date 23 care \l are, tentativa este sanc]ionat` prin eroare de sintax`. Vede]i mai jos: int i; System.out.println(i); b. Avem posibilitatea de a afi[a mai multe variabile pe aceea[i linie. Aceasta se ob]ine prin convertirea con]inutului variabilelor \n [iruri de caractere [i concatenarea [irurilor cu ajutorul operatorului +. Vede]i exemplul de mai jos care afi[eaz` pe o linie a=2 b=4.5: int a=2; float b=4.5f; System.out.println("a="+a+" b="+b); 2.2. Operatori |n acest paragraf vor fi prezenta]i operatorii utiliza]i \n Java. 2.2.1. Operatori aritmetici Exist` urm`torii operatori aritmetici: - minus (unar, adic` ac]ioneaz` asupra unui singur operand); + plus (unar); + (binar), pentru adunare; - (binar), pentru sc`dere; * (binar), are semnifica]ia de \nmul]ire; / (binar), pentru \mp`r]ire; % (binar) restul \mp`r]irii \ntregi. Observa]ii: 1. Operatorul '/' (\mp`r]ire) ac]ioneaz` \n mod diferit \n func]ie de operanzi: a) dac` ambii sunt de tip \ntreg, rezultatul este \ntreg [i are semnifica]ia de \mp`r]ire \ntreag`. Cu toate acestea, rezultatul este corect (din punct de vedere matematic) numai dac` valorile care se \mpart sunt pozitive. b) dac` cel pu]in un operand este de unul din tipurile reale rezultatul este real (se efectueaz` \mp`r]irea obi[nuit`). 2. Operatorul '%' ac]ioneaz` numai asupra operanzilor de tip \ntreg. Rezultatul ob]inut este corect din punct de vedere matematic numai dac` ambii operanzi sunt numere naturale. 24 Bazele programării în Java 3. |n cazul \n care se \mpart dou` valori \ntregi se procedeaz` astfel: se face \mp`r]irea \ntreag` a celor dou` valori care sunt considerate \n modul; semnul c@tului se stabile[te dup` regula semnelor (+ cu + rezultat +, + cu -, rezultat -), etc. |n cazul operatorului '%', se face \mp`r]irea ca anterior (se ob]ine C), iar restul se o]ine dup` formula R=D-|C. Se pot utiliza oric@te perechi de paranteze rotunde, pentru a impune ca anumite opera]ii s` se fac` prioritar. Exemple: 1. Fie declara]ia: int a=10;. Atunci expresia 4*a/3 este de tip int [i la evaluare se ob]ine 13. S-a \nmul]it 4 cu con]inutul variabilei a (10) [i s-a ob]inut 40. Apoi, 40/3=13 (a fost efectuat` \mp`r]irea \ntreag`). |n acelea[i condi]ii, expresia 4*(a/3) are ca rezultat num`rul 12. La \nceput s-a efectuat a/3 [i s-a ob]inut 3, apoi 4*3=12. Iat` un exemplu \n care se observ` faptul c` una este o expresie la matematic`, [i alta \n Java. 2. Fie declara]ia: float a=10;. Expresia 4*(a/3) are rezultatul 13.3333, la fel ca expresia 4*a/3. De aceast` dat`, s-a efectuat \mp`r]irea a dou` numere reale. 3. Fie declara]ia: int a= -10;. Atunci expresia a%3 are ca rezultat num`rul -1. 4. Fie declara]ia: int a=-10;. Atunci expresia a*-3 are ca rezultat 30. 5. Fie declara]iile: int a=10; char b=2; float c=5;. Atunci expresia: a+b+c are rezultatul 17.0. |n exemple, apare o problem` foarte important`: care este tipul rezultatului, \n cazul \n care o expresie aritmetic` are operanzi de mai multe tipuri? Problema de mai sus se nume[te problema conversiilor aritmetice implicite (dup` cum vom vedea, conversiile se pot face [i explicit). Regula general` este: se converte[te unul din operanzi c`tre tipul celuilalt (mai cuprinz`tor). De exemplu, dac` unul din operanzi este de tip int, iar cel`lalt de tip float, rezultatul va fi de tip float. F`r` o conversie prealabil`, operatorii aritmetici nu ac]ioneaz` asupra variabilelor de tip char. De exemplu, secven]a char x=’1’; x=x+1; este eronat` din punct de vedere sintactic. Capitolul 2. Tipuri şi operaţii de date 25 2.2.2. Operatori relaţionali |n Java exist` urm`torii operatori rela]ionali: < (mai mic); <= (mai mic sau egal); > (mai mare); >= (mai mare sau egal). |ntruc@t \n Java exist` valorile logice true [i false, rezultatul unei opera]ii logice este una dintre aceste valori. Exemple: 1. 3>5 - expresia ia valoarea false; 2. 3<5 - expresia ia valoarea true; 3. 3+7>=11-1 - expresia ia valoarea true (este posibil s` scriem astfel de expresii, \ntruc@t operatorii rela]ionali au o prioritate mai mic` dec@t operatorul aditiv). 2.2.3. Operatori de egalitate Ace[tia sunt: == pentru egalitate; != pentru inegalitate. Ca [i operatorii rela]ionali, expresiile de acest tip returneaz` 0 sau 1 \n func]ie de modul \n care este respectat` sau nu egalitatea (inegalitatea). Exemple: 1. 3==3, rezultat true; 2. 3!=3 rezultat false; 2.2.4. Operatorii de incrementare şi decrementare Ace[ti operatori sunt unari [i au rolul de a incrementa (adun` 1) sau decrementa (scad 1) con]inutul unei variabile. Operatorii sunt: ++ pentru incrementare; -- pentru decrementare. Operatorii pot fi prefixa]i (aplica]i \n fa]a operandului) sau postfixa]i (aplica]i dup` operand). Exemplu: fie a o variabil` de tip int. Operatorul Operatorul Operatorul Operatorul de de de de incrementare prefixat aplicat variabilei a este ++a; incrementare postfixat aplicat variabilei a este a++; decrementare prefixat aplicat variabilei a este --a; decrementare postfixat aplicat variabilei a este a--. 26 Bazele programării în Java Care este diferen]a \ntre efectul unui operator aplicat prefixat sau postfixat? S` ne g@ndim la faptul c` pot fi expresii care con]in [i al]i operatori \n afara celor de incrementare (decrementare). Dac` operatorul este prefixat, variabila este incrementat` (decrementat`) \nainte ca valoarea re]inut` de ea s` intre \n calcul. Dac` operatorul este postfixat, variabila este incrementat` (decrementat`) dup` ce valoarea re]inut` de ea intr` \n calcul. Exemple: 1. Fie a o variabil` de tip int care re]ine valoarea 1. |n urma evalu`rii expresiei 1+a++ se ob]ine valoarea 2, dar dup` evaluare, a va re]ine valoarea 2 (variabila a fost incrementat` dup` ce valoarea re]inut` de ea a intrat \n calcul). 2. La fel ca \n cazul anterior, expresia 1-++a produce valoarea -1 (variabila a fost \nt@i incrementat`, s-a ob]inut 2, apoi s-a efectuat 1-2). 3. Expresia 1+++a este eronat` sintactic. S-a considerat c` operatorul de incrementare este aplicat postfixat pentru 1 [i nu prefixat pentru a. Aplicarea unui operator de acest tip se poate face pentru o variabil`. 4. Dac` a [i b sunt variabile de tip int care re]in valorile 1 [i 3, atunci expresia a++*b++ produce valoarea 3, dar dup` evaluare cele dou` variabile re]in 2 [i 4. 5. |n acelea[i condi]ii, expresia ++a*++b produce valoarea 8, iar dup` evaluare a [i b re]in 2 [i 4 (ca \n cazul anterior). ! Ac]iunea operatorului de decrementare este similar` celei de incrementare, cu diferen]a c` se scade 1 din con]inutul variabilei. 2.2.5. Operatori logici Exist` trei tipuri de operatori logici care ac]ioneaz` asupra datelor de tip boolean: ! negare logic`; && [i logic; || sau logic. Ace[ti operatori se aplic` oric`rei variabile [i constante de tip logic. Operatorul negare logic` ac]ioneaz` astfel: dac` operandul este o valoare true, rezultatul este false, altfel rezultatul este true. Operatorul [i logic (binar) ac]ioneaz` astfel: dac` ambii operanzi sunt true rezultatul este true, altfel el este false. Capitolul 2. Tipuri şi operaţii de date 27 Operatorul sau logic (binar) ac]ioneaz` astfel: dac` cel pu]in unul din operanzi este true, rezultatul este true, altfel rezultatul este false. Exemple: \n condi]iile: boolean a=true, b=false; 1. !a returneaz` false; 2. a||b returneaz` true; 3. a&&b returneaz` false; Operatorii logici binari garanteaz` modul \n care se trateaz` operanzii - \nt@i cel din st@nga, apoi (dac` este cazul) cei din dreapta. Astfel, dac` operandul din st@nga este true, operatorul sau logic nu mai ac]ioneaz` asupra operandului din dreapta (este clar c` rezultatul este true). Tot a[a, dac` operandul din st@nga este false, operatorul [i logic nu mai evalueaz` operandul din dreapta (oricum rezultatul este false). Observa]ia este foarte important` pentru cazul \n care al doilea argument este func]ie (metod`) de tip boolean. 2.2.6. Operatori logici pe biţi Limbajul Java este dotat cu un set de operatori care permit accesul la bit. Ace[tia sunt: <<, >>, >>> operatori de deplasare; & [i pe bi]i; | sau pe bi]i; ^ sau exclusiv pe bi]i; ~ negare pe bi]i (operator unar). Ace[ti operatori ac]ioneaz` numai asupra operanzilor de tip \ntreg. Operatorul << este binar. El are rolul de a deplasa c`tre st@nga con]inutul tuturor bi]ilor operandului din st@nga sa, cu un num`r de pozi]ii egal cu valoarea re]inut` de al doilea operand. Pozi]iile r`mase libere (\n dreapta) vor re]ine valoarea 0. Dac` al doilea operand re]ine valoarea m, o astfel de deplasare este echivalent` cu \nmul]irea cu 2m (evident, dac` m este mai mic dec@t num`rul de bi]i rezervat primului operand). Operatorul >> este binar. El are rolul de a deplasa c`tre dreapta con]inutul tuturor bi]ilor operandului din st@nga cu un num`r de pozi]ii egal cu valoarea re]inut` de al doilea operand. Aten]ie: \n pozi]iile din st@nga, r`mase libere dup` deplasare, se copiaz` con]inutul bitului de semn (acesta re]ine 1 \n cazul numerelor negative [i 0, \n cazul numerelor pozitive). Dac` operandul din st@nga este un \ntreg pozitiv, pozi]iile r`mase libere (\n st@nga) vor re]ine valoarea 0. |n cazul \ntregilor pozitivi, dac` al doilea 28 Bazele programării în Java operand re]ine valoarea m, o astfel de deplasare este echivalent` cu \mp`r]irea \ntreag` cu 2m. Operatorul >>> ac]ioneaz` la fel ca [i operatorul >>, dar diferen]a este dat` de faptul c` pozi]iile r`mase libere din dreapta vor re]ine 0. Aten]ie: operatorii de deplasare sunt utiliza]i doar pentru evaluarea expresiilor, operanzii, chiar dac` sunt variabile, r`m@n nemodifica]i! Desigur, valorile astfel ob]inute pot fi atribuite. Aceasta \nseamn`, de fapt, acces la bit. |n cazul operatorilor binari &, ^, |, rezultatul se ob]ine aplic@nd pentru fiecare pereche de bi]i afla]i pe aceea[i pozi]ie regulile din tabelul urm`tor: OP1 OP2 OP1&OP2 OP1^OP2 OP1|OP2 0 0 0 0 0 1 0 0 1 1 0 1 0 1 1 1 1 1 0 1 Operatorul ~ (negare pe bi]i) are rolul de a inversa con]inutul bi]ilor (dac` un bit con]ine 0 va con]ine 1 [i invers). Exemple: dac` a este de tip int [i re]ine 3, iar b este de acela[i tip [i re]ine 1 atunci: 1. a&b returneaz` 1; 2. a|b returneaz` 3; 3. a^b returneaz` 2; 4. a<<2 returneaz` 6; 5. a>>1 returneaz` 1; 6. ~a returneaz` -4. 2.2.7. Operatori de atribuire |n Java atribuirea este operator, dar dup` cum vom vedea, este [i instruc]iune. |n plus, avem mai mul]i operatori de atribuire. Operatorul '=' se folose[te \ntr-o expresie de forma: v=expresie Aici, v este o variabil`. Capitolul 2. Tipuri şi operaţii de date 29 Principiul de executare este urm`torul: se evalueaz` expresia; varibilei v i se atribuie valoarea ob]inut` (dac` este cazul se efectueaz` conversia respectiv`). Se pot efectua [i atribuiri multiple de forma: v=v1=v2=.......=vn=expresie, unde v, v1........vn sunt variabile. |n acest caz, principiul de executare este urm`torul: se evalueaz` expresia; valoarea ob]inut` este atribuit` variabilei vn (eventual convertit` dac` este cazul); con]inutul variabilei vn este atribuit variabilei vn-1 (eventual se efectueaz` conversia necesar`); . . . con]inutul variabilei v1 este atribuit variabilei efectueaz` conversia necesar`). v (eventual se Acest operator se asociaz` de la dreapta la st@nga. Ce am prezentat anterior eviden]iaz` acest lucru. Pentru atribuiri se mai pot utiliza [i operatorii: *=, /=, %=, +=, -=, <<=, >>=, &>, ^=, |=. O atribuire de forma: v op=expresie, are acela[i rezultat ca v=v op expresie (diferen]a este c` \n primul caz se genereaz` un cod ma[in` eficient). Observa]ie! Am v`zut faptul c` atribuirea este operator care figureaz` \ntr-o expresie. Ca orice expresie, aceasta are o valoare rezultat` \n urma evalu`rii. |n cazul atribuirilor, valoarea rezultat` este valoarea atribuit` variabilei care este prima din st@nga, (\ntr-un [ir de atribuiri, eventual dup` conversie). Exemple: 1. Fie declara]iile: int a=5, b=3; float c;. |n urma atribuirii c=a/b, c va con]ine valoarea real` 1.0. Este normal s` fie a[a \ntruc@t expresia a/b este de tip int (se efectueaz` \mp`r]irea \ntreag` [i se ob]ine 1), apoi aceast` valoare este atribuit` variabilei c (dup` ce este convertit`). 30 Bazele programării în Java 2. Fie declara]iile: int a,b; float c; [i expresia c=a=b=1. Dup` evaluare, a re]ine 1, b re]ine 1, c re]ine 1.0, iar valoarea rezultat` \n urma evalu`rii este 1.0 (real`). 3. Fie declara]ia: int a=3; [i expresia a*=2. |n urma evalu`rii, a re]ine valoarea 6, iar expresia va produce valoarea de tip int 6. Observa]ie foarte important`! Sunt permise doar atribuiri \n care tipul variabilei c`reia i se atribuie con]intul unei variabile de alt tip, con]ine, printre valorile permise, cele ale tipului variabilei care este atribuit`. Exemple: 1. Fie declara]iile: long a=2; int b=3; a=b; //corect b=a; //incorect 2) Fie declara]iile: char a=2; int b=3; b=a; //corect a=b; //incorect 3) Fie declara]iile: float a=2; int b=3; a=b; //corect b=a; //incorect 4) Fie declara]iile: float a=2; double b=3; b=a; //corect a=b; //incorect Dup` cum observa]i, aici apare o diferen]` fa]` de C/C++. Java, ca [i Pascal-ul, \ncearc` s` te fereasc` de erori ascunse, rezultate \n urma conversiilor implicite. 2.2.8. Operatorul condiţional Se folose[te \n expresii de genul: exp1?exp2:exp3 Cerin]a este ca exp1 s` fie de tipul boolean. Principiul de executare este urm`torul: se evalueaz` exp1; dac` aceasta produce true, se evalueaz` exp2 [i exp3 este ignorat` (nu se evalueaz`); altfel, se evalueaz` exp3 [i exp2 este ignorat`. Capitolul 2. Tipuri şi operaţii de date 31 |n ansamblu, expresia este de tipul lui exp2 sau exp3 [i produce valoarea exp2 sau exp3 (\n func]ie de cea care se evalueaz`). Exemple: 1. Variabila c ia valoarea 5 (valoarea maxim`). int a=1, b=5, c; c=a>b?a:b; 2. Se afiseaz` valoarea 5. int a=1, b=5, c; System.out.println(a>b?a:b); 3. Variabila h ia valoarea 9. Aici se observ` c` nu este obligatoriu ca exp2 [i exp3 s` aib` acela[i tip: int a=1, b=5; float d=9,h; h=a>b?a:d; 2.2.9. Operatorul de conversie explicită De multe ori, vrem ca unul sau mai mul]i operanzi s` intre \n calcul converti]i a[a cum dorim (nu implicit). Pentru aceasta, \naintea operandului se trece \ntre paranteze tipul s`u. Exemple: 1) Variabila a ia valoarea 9. Iat` c`, desi implicit conversia nu poate fi realizat`, \n acest mod s-a efectuat f`r` probleme. int a=1; double d=9.6; a=(int)d; 2) Se afi[eaz` 0.5. Iat` c`, de[i, operanzii sunt \ntregi [i rezultatul ar trebui s` fie 0, prin utilizarea operatorului de conversie explicit` se ob]ine rezultatul corect. int a=3, b=6; System.out.println((float) a/b); 2.2.10. Prioritatea (precedenţa) operatorilor Operatorii au o anumit` prioritate (preceden]`). Mai jos, sunt prezenta]i operatorii \n ordinea descresc`toare a priorit`]ii. 1) 2) (), . , [] ++, --, +(unar),–(unar),!, new, operatorul de conversie explicit` 3) *, /; % 32 Bazele programării în Java 4) 5) 6) 7) 8) 9) 10) 11) 12) 13) 14) +, - (privi]i ca operatori binari) <<, >>,>>> <, <=,>,>= ==, != & ^ | && || ?: =, +=, etc (operatori de atribuire) 2.3. Instrucţiuni 1. Instruc]iunea vid`. Instruc]iunea nu face nimic, dar are sens \n programul Java, dup` cum va rezulta Instruc]iunea vid` se marcheaz` prin ;. din studiul altor instruc]iuni. 2. Instruc]iunea compus`. Se utilizeaz` atunci c@nd se dore[te ca mai multe instruc]iuni s` fie considerate ca o singur` instruc]iune. Mai jos, pute]i observa o instruc]iune compus` care subordoneaz` mai multe instruc]iuni vide. { ; ; ; } 3. Instruc]iunile de incrementare [i decrementare. Se utilizeaz` pentru a incrementa sau decrementa o anumit` variabil`. Exemple: a++; ++a; a--; --a; Exist` o diferen]` \ntre operatorii de incrementare (decrementare) [i instruc]iunea de incrementare (decrementare). Instruc]iunea de incrementare (decrementare) con]ine numai un operator de incrementare (decrementare), dar de exemplu, b=++a+1 este o instruc]iune (atribuire, vezi mai jos) care con]ine [i un operator de incrementare. 4. Instruc]iunea de atribuire. Con]ine o expresie prin care unei variabile i se atribuie o alt` expresie (aflat` \n dreapta operatorului de atribuire). Capitolul 2. Tipuri şi operaţii de date 33 Exemple: a) int a, b=6; a=b+5; // dup` atribuire a re]ine 11. b) int a, b=6; a=++b+5; // dup` atribuire a re]ine 12. c) int a=1, b=6; a+=b; // dup` atribuire a re]ine 7. d) a=b=c=1; // a, b, c sunt de tip int. Iat` o atribuire multipl`. Ini]ial, c ia valoarea 1, apoi b=c, atunci b=1, apoi a=b, deci a=1. Dup` atribuire a, b, [i c re]in 1. Observa]ii: Nu sunt permise atribuiri de genul: ++a=b+5; Exist` o diferen]` \ntre operatorul de atribuire [i instruc]iunea de atribuire. De exemplu, a=b=c=1 este o instruc]iune de atribuire, dar con]ine 3 operatori (de atribuire). Practic, o instruc]iune de atribuire con]ine cel pu]in un operator de atribuire. 5. Instruc]iunea if. Are dou` forme: Forma 1. if (expresie de tip boolean) instruc]iune1 else instruc]iune2 Principiul de executare este urm`torul: se evalueaz` expresia; dac` valoarea produs` de aceasta este true, se execut` instruc]iune1; dac` valoarea produs` este false se execut` instruc]iune2. Forma 2. if (expresie de tip boolean) instruc]iune Principiul de executare este urm`torul: se evalueaz` expresia; dac` valoarea produs` de aceasta este true, se execut` instruc]iunea subordonat`, altfel se trece la cea urm`toare. Exemple: a) Se afi[eaz` cea mai mare valoare dintre valorile re]inute de variabilele a [i b: if (a>b) System.out.println(a); 34 Bazele programării în Java else System.out.println(b); b) Se rezolv` ecua]ia ax+b=0, unde pentru valorile lui a [i b sunt re]inute variabilele cu acela[i nume. if (a!=0) { x=-b/a; System.out.println(x); } else if (b==0) System.out.println("infinitate de solutii"); else System.out.println("nu are solutie"); 6. Instruc]iunea while. Forma general` este: while (expresie de tip boolean) instruc]iune Principiul de executare este urm`torul: Se evalueaz` expresia; Dac` valoarea produs` de aceasta este true, se execut` instruc]iunea subordonat`, apoi se revine la evaluarea expresiei, altfel se trece la instruc]iunea urm`toare. Exemple: a) Pentru n>0, num`r natural, s` se calculeze suma cifrelor sale (pentru n=213, se va afi[a 6): int n=213,s=0; while (n!=0) { s+=n%10; n/=10; } System.out.println(s); b) Pentru n, num`r natural, s` se afi[eze num`rul ob]inut prin inversarea cifrelor sale (pentru n=213, se va afi[a 312): while (n!=0) { ninv=ninv*10+n%10; n=n/10; } System.out.println(ninv); 7. Instruc]iunea do while. Forma general` a acestei instruc]iuni este urm`toarea: do instruc]iune while(expresie); Principiul de executare este urm`torul: Capitolul 2. Tipuri şi operaţii de date 35 Se execut` instruc]iunea subordonat`; Se evalueaz` expresia. |n cazul \n care valoarea produs` la evaluare este false, execu]ia instruc]iunii do while se termin`, altfel se trece la pasul anterior.. Observa]ie: secven]a se execut` cel pu]in o dat`, dup` care se pune problema dac` s` se repete sau nu (prin evaluarea expresiei logice). Exemple: a) Se d` un num`r natural n, mai mare sau egal cu 1. S` se calculeze suma primelor n numere naturale nenule. int n=10,s=0,i=1; do { s=s+i; i=i+1; } while (i<=n); System.out.println(s); b) Se d` un num`r natural descompun` n \n factori primi. n, mai mare sau egal cu 1. S` se int n=115,i=2,fm; do { fm=0; while (n%i==0) { fm++; n/=i; } if (fm!=0) System.out.println(i+" la puterea "+fm); i++; }while (n!=1); 8. Instruc]iunea for are forma general`: for(expresieini]ializare;expresietest;expresieincrementare) instruc]iune Dup` cum se vede, \ntre paranteze se g`sesc 3 expresii: Expresieinitializare se folose[te de regul` pentru ini]ializarea variabilei de ciclare. Este de remarcat faptul c` \n cadrul acestei expresii (cu rol special) este posibil chiar s` declar`m variabila de ciclare (cu valoare ini]ial`). Expresietest este de tip boolean [i se folose[te pentru a testa dac` se execut` instruc]iunea subordonat` - dac` expresia produce la 36 Bazele programării în Java evaluare true, instruc]iunea subordonat` for se execut`. Expresieincrementare se folose[te pentru incremenatarea variabilei ciclare. de Principiul de executare: P1. Se evalueaz` expresieini]ializare (un caz special este când aceasta con]ine [i declara]ia variabilei de ciclare); P2. Se evalueaz` expresiatest. |n cazul \n care aceasta produce true, se execut` instruc]iunea subordonat` for; apoi se trece la P3, altfel se trece la instruc]iunea urm`toare (se termin` execu]ia instruc]iunii for). P3. Se evalueaz` expresia de incrementare [i se revine la P2. Toate expresiile pot fi vide. |n concluzie, expresiile de mai sus au rolul precizat \n mod normal - dar nu obligatoriu [i nici restrictiv. De exemplu, dac` expresietest este vid`, se execut` un ciclu infinit. for(;;) instruc]iune. Exemple: a) Se afi[eaz` numerele, 10, 9,..1, fiecare pe c@te un r@nd. Observa]i faptul c` variabila i a fost declarat` \n cadrul ciclului for. for (int i=10;i>=1;i--) System.out.println(i); b) Se afi[eaz` alfabetul, de la „a‟ la „z‟ [i pentru fiecare caracter se afi[eaz` [i codul s`u. for (char c='a';c<='z';c++) System.out.println(c+" "+(int)c); c) Se calculeaz` suma S 1 1 2 1 2 3 ... 1 2 ... n int i,s=0,p=1,n=3; for(i=1;i<=n;i++) { p*=i;//p=p*i; s+=p; //s=s+p; } System.out.println(s); 9. Instruc]iunea break. Are rolul de a for]a iesirea dintr-un ciclu. |n cazul \n care exist` cicluri imbricate (un ciclu in interiorul altui ciclu), for]eaz` doar ie[irea din primul ciclu (vezi secven]a urm`toare, unde for-ul dup` j se execut` doar pentru j=1). Se folos[te pentru instruc]iunile for, while, do while [i, \n Capitolul 2. Tipuri şi operaţii de date 37 particular, pentru switch (cazul va fi studiat separat). Analiza]i secven]a de mai jos: for (int i=1;i<=4;i++) Se afi[eaz` for (int j=1;j<=4;j++) if (j==2) break; else System.out.println(i+" "+j); 1 2 3 4 1 1 1 1 10. Instruc]iunea continue; este folosit` \n cazul ciclurilor (for, while, do while) [i are rolul de a determina ca, dup` executarea ei, s` se sar` direct la testul condi]iei de continuare. Astfel, se ignor` instruc]iunile care \i urmeaz` \n secven]a care se repet`. Exemplu: secven]a urm`toare afi[eaz`. 1, 3. 4. Dac` i ia valoarea 2, atunci, se execut` continue [i se sare peste apelul metodei de afi[are. for (int i=1;i<=4;i++) { if (i==2) continue; System.out.println (i);} 11. Instruc]iunea switch are forma particular`: switch (expresie) case exp1: secven]` instruc]iuni1; break; case exp2: secven]` instruc]iuni2; break; ................................. case expn: secven]` instruc]iunin; break; [default: secven]` instruc]iunin+1]; unde: expresie are semnifica]ia: expresie de tip \ntreg (sau char).; expi : sunt expresii constante de tip \ntreg (sau char); instruc]iunii reprezint` o secven]` oarecare de instruc]iuni. Principiul de executare: se evalueaz` expresia; dac` aceasta produce o valoare egal` cu cea produs` de expi, se execut`, \n ordine, instruc]iunii [i se trece la instruc]iunea urm`toare, altfel se execut` numai secven]a instruc]iunin+1. Observa]ie. Alternativa default este facultativ`. |n absen]`, \n cazul \n care nu exist` coinciden]` de valori, se trece la instruc]iunea urm`toare. 38 Bazele programării în Java Exemplu: Secven]a care exemplu se afi[eaz` 1: urmeaz` probeaz` instruc]iunea switch. |n int i =1; switch(i) { case 1: System.out.println(1);break; case 2: System.out.println(2);break; default: System.out.println("altceva"); } Observa]ie. Am prezentat o form` simplificat` a instruc]iunii switch, mai precis, cea corespunz`toare program`rii structurate. |n absen]a instruc]iunii break, \n cazul \n care exist` egalitate \ntre expresie [i expi se execut` secven]a corespunz`toare [i, pe r@nd, toate secven]ele care urmeaz`, [.a.m.d. Exemplu: secven]a care urmeaz` afi[eaz`: 2, altceva. int i =2; switch(i) { case 1: System.out.println(1); case 2: System.out.println(2); default: System.out.println("altceva"); } |n forma general`, instruc]iunea switch are rolul de a stabli mai multe puncte de intrare \ntr-o secven]` de instruc]iuni, \n func]ie de valoarea pe care o re]ine expresie. 12. Instruc]iunea apel metod` (func]ie) va fi tratatat` la momentul potrivit. Pentru moment, putem da ca exemplu de astfel de instruc]iune doar System.out.print() sau System.out.println(). 13. Instruc]iunea de declarare a variabilelor. P@n` \n prezent, am \nt@lnit-o de multe ori. Ea poate fi plasat` oriunde \n corpul unei metode (func]ii). Exemplu: int x=2,y. 2.4. Masive |n Java exist` un mecanism excep]ional de lucru cu masive (vectori, matrice, etc). Din motive didactice, masivelor \n doi pa[i: pentru \nceput, vom prezenta declararea Capitolul 2. Tipuri şi operaţii de date 39 Pasul 1. Se declar` o variabil` care poate re]ine o referin]` (adres`) c`tre vector, matrice, etc. Exemple: a) int[] V; am declarat o variabil` referin]` c`tre un vector cu componente de tip int. O declara]ie echivalent` poate fi f`cut` prin: int V[];. b) int[][] Mat; am declarat o variabil` referin]` c`tre o matrice cu componente de tip int. c) float[] V, V1; am declarat dou` variabile referin]` c`tre vectori, numite V, respectiv V1. Ambii vectori au componente de tip float. d) float Mat[][],Mat1[][]; am declarat dou` variabile de tip referin]` c`tre matrice. Cele dou` variabile se numesc Mat [i Mat1. Pasul 2. Aloc`m spa]iu \n memorie pentru masiv (vector matrice). Adresa vectorului va fi re]inut` \n variabila V. Exemple: a) V=new int[4];. Am alocat spa]iu \n memorie pentru un vector cu 4 componente de tip int (practic am creat vectorul). Referin]a c`tre el va fi re]inut` \n V, [i, pornind de la aceast` variabil` putem accesa V. b) Mat=new int [4][3];. Am alocat spa]iu \n memorie pentru o matrice cu 4 linii [i 3 coloane cu componente de tip int. Prima component` a unui vector are indicele 0, a doua indicele 1 [.a.m.d. Tot a[a, liniile unei matrice se numeroteaz` \ncep@nd cu 0, coloanele unei matrice se numeroteaz` \ncep@nd cu 0. O component` a unui vector se adreseaz` porind de la referin]` [i scriind indicele \ntre paranteze drepte (exemplu V[3]) o component` a unei matrice se adreseaz` pornind de la referin]` si scriind \ntre paranteze p`trate fiecare din cei doi indici (exemplu Mat [2][1]). Exemple: a) |n secven]a urm`toare se creeaz` un vector, se ini]ializeaz` fiecare component` a lui [i se afi[eaz`. int[] V; // sau int V[]; V=new int[4]; int i; for (i=0;i<4;i++) V[i]=i+1; for (i=0;i<4;i++) System.out.println(V[i]); Schema al`turat` reflect` modul \n care arat` vectorul, dup` ce i-am ini]ializat componentele. V referin]a 1 2 3 4 0 1 2 3 40 Bazele programării în Java Vectorii se pot declara [i a[a cum se vede mai jos, gata ini]ializa]i. |n urma unei astfel de declara]ii se poate lucra direct cu ei, exact ca anterior. int[] V={1,2,3,4}; int i; for (i=0;i<4;i++) V[i]=i+1; for (i=0;i<4;i++) System.out.println(V[i]); b) |n secven]a urm`toare se creeaz` o matrice, se ini]ializeaz` fiecare component` a ei [i se afi[eaz`. int[][] Mat; int i,j; Mat=new int [4][3]; for (i=0;i<4;i++) for (j=0;j<3;j++) Mat[i][j]=i+j; for (i=0;i<4;i++) { for (j=0;j<3;j++) System.out.print(Mat[i][j]+" "); System.out.println(); } Ca [i vectorii, matricele se pot declara [i a[a cum se vede mai jos, gata ini]ializate. |n urma unei astfel de declara]ii se poate lucra direct cu ele, exact ca anterior. int[][] Mat={{1,2,3,4},{3,4,5,6}}; int i,j; for (i=0;i<2;i++) { for (j=0;j<3;j++) System.out.print(Mat[i][j]+" "); System.out.println(); } Declararea unui masiv se poate face [i \ntr-un singur pas, ca mai jos: float[] V=new float[4]; De vreme ce numele masivului (V, Mat, \n exemplele date) re]ine o referin]` c`tre masiv, \nseamn` c` unei astfel de variabile i se poate atribui o referin]` c`tre alt masiv, ceea ce este echivalent cu faptul c` atribuirea “func]ioneaz`” \n cazul masivelor ca \n cazul variabilelor de unul din tipurile de date primitive. Totu[i, exist` o diferen]` esen]ial`: se atribuie doar referin]a, nu con]inutul masivului, care r`m@ne nemodificat. Masivul care nu mai este referit va fi [ters, automat (f`r` ca, \n acest scop, s` fie scris` o secven]` special`). Capitolul 2. Tipuri şi operaţii de date 41 Exemplu: Avem doi vectori, V [i V1. Cei doi vectori sunt crea]i [i ini]ializa]i. Dup` aceasta, se interschimb` referin]ele c`tre cei doi vectori [i, \n vederea prob`rii opera]iilor efectuate se afi[eaz`. float[] V=new float[4], V1=new float[3], Man; int i; for (i=0;i<4;i++) V[i]=i+1; for (i=0;i<3;i++) V1[i]=9; Man=V1; V1=V; V=Man; for (i=0;i<4;i++) System.out.println(V1[i]); for (i=0;i<3;i++) System.out.println(V[i]); Grafic, interschimbarea de mai sus se poate prezenta astfel: Dup` crearea [i ini]ializarea celor doi vectori: V 1 0 2 1 3 2 9 0 9 1 9 2 V 1 0 2 1 3 2 V1 11 1 Man 9 0 9 1 9 2 V 1 0 2 1 3 2 V1 11 1 Man 9 0 9 1 9 2 V 1 0 2 1 3 2 V1 11 1 9 0 9 1 9 2 V1 11 1 Man=V1; 4 3 4 3 V1=V; 4 3 V=Man; 4 3 42 Bazele programării în Java O alt` utilizare de excep]ie a acestui mecanism este aceea prin care se declar` un masiv exact cu num`rul de componente dorit [i nu un num`r de componente mare, care se presupune c` indiferent de intrare, nu poate fi dep`[it (ca \n Pascal, C/C++). Aceasta conduce la economie de memorie. int n; // se citeste n; V=new int [n]; De[i din punct de vedere teoretic nu se poate explica \n acest moment, num`rul de componente ale unui vector (masiv unidimensional) este returnat de data membru (vom \nv`]a despre date membru) length, apelat` ca mai jos. |n urma execut`rii acestei secven]e se afi[eaz` 10. int[] vector=new int[10]; System.out.println(vector.length); O matrice poate fi privit` ([i, de fapt asta [i este) ca un vector de vectori. Fie declara]ia int Mat[][]=new int [4][5]. Putem spune c` avem un vector cu 4 componente. Fiecare component` este la r@ndul ei, un vector cu 5 componente. Atunci, length, aplicat` matricei, re]ine 4, [i aplicat`, de exemplu, componentei de indice 2 returneaz` 5. La executarea secven]ei de mai jos se afi[eaz` 4 [i 5. int Mat[][]=new int [4][5]; System.out.println(Mat.length); System.out.println(Mat[2].length); |n cazul matricelor (sau, \n general, masivelor de dimensiune mai mare sau egal` cu 2) exist` posibilitatea ca liniile s` aib` lungime diferit`. Cu alte cuvinte, o component` a vectorului de vectori (matricea) poate avea un num`r de componente, alt` component`, alt num`r de componente. |n secven]a urm`toare am declarat o matrice cu 2 linii. Prima linie are 3 componente, a doua linie are dou` componente. |n final, se afi[eaz` con]inutul unui element al matricei. int Mat[][]=new int [2][]; Mat[0]=new int[3]; Mat[1]=new int[2]; Mat[0][0]=1; Mat[0][1]=2;Mat[1][0]=3; System.out.println(Mat[0][1]); V` da]i seama c@t` economie de memorie se face? Aplica]ie: secven]a urm`toare creeaz`, ini]ializeaz` [i afi[eaz` o matrice triunghiular`. Al`turat pute]i observa rezulatul rul`rii. Este ceva faptul c` pentru a re]ine o matrice triunghiular` se re]ine exact at@t c@t este necesar! int[] vector=new int[10]; int Mat[][]=new int [4][]; int i, j, k=1; for (i=0;i<4;i++) { Mat[i]=new int[i+1]; // declararea este instructiune Capitolul 2. Tipuri şi operaţii de date 43 for (j=0;j<=i;j++)Mat[i][j]=k++; } for (i=0;i<4;i++) { for (j=0;j<Mat[i].length;j++) System.out.print(Mat[i][j]); System.out.println(); } 2.5. Citirea datelor de la tastatură Limbajul Java con]ine o mul]ime de facilit`]i, dar pentru \ncep`tori exist` o real` dificultate \n a citi date de la tastatur`. Pentru aceast` opera]ie este necesar s` cunoa[tem o serie de clase. Ca s` le \n]elegem, sunt necesare cuno[tin]e avansate de Java. {i nu putem a[tepta p@n` atunci, pentru c` este relativ dificil s` prezin]i materia, mai ales la nivel de liceu, f`r` a putea citi ceva de la tastatur`. Pentru a rezolva aceast` problem`, am recurs, ca de altfel [i \n alte cursuri de Java, la prezentarea unei clase prin care s` putem realiza citirea de la tastaur`. Clasa respectiv`, o prezent`m acum [i \n cele ce urmeaz`, nu ne vom referi dec@t la utilizarea ei. Ulterior, vom prezenta modul \n care a fost realizat` clasa precum [i multe alte cuno[tin]e privind opera]iile de intrare/ie[ire. Iat` clasa pe care o vom folosi (se nume[te cin): import java.io.*; import java.util.*; class cin { static InputStreamReader f = new InputStreamReader (System.in); static BufferedReader tamp=new BufferedReader(f); static String linie() { try { return tamp.readLine();} catch (IOException e) {return ("Eroare");} } static String Token(){ StringTokenizer v=new StringTokenizer(linie()); if (v.hasMoreTokens())return v.nextToken(); else return"";} } Textul de mai sus \l vom introducem \n fi[ierul cin.java. Apoi, \l compil`m cu javac cin.java. |n urma compil`rii rezult` fi[ierul cin.class. Acest fi[ier va fi utilizat de orice program care utilizeaz` o metod` din clasa cin. Dac` fi[ierele cin.java [i cin.class se vor g`si \n folder-ul bin, atunci, f`r` nici o problem`, utiliz`m aceste metode ca [i cum ar fi ale limbajului Java (practic, orice program care apeleaz` clasele respective le g`seste \n bin). Metoda linie() are rolul de a citi \ntreaga linie pe care utilizatorul o introduce de la tastatur`. Rezultatul este de tip referin]` la String, adic` referin]` c`tre [irul de caractere citit. 44 Bazele programării în Java Exemplu: programul urm`tor cite[te [i afi[eaz` o linie introdus` de la tastatur`: class prima { public static void main(String[] args) { String l=cin.linie(); System.out.println(l);} } Putem considera c` un [ir de caractere con]ine unul sau mai multe token-uri (unita]i lexicale). De exemplu. [irul “Ionel are 100 de lei noi” con]ine 6 token-uri (“Ionel”, “are”, “100”, “de”, “lei”, “noi”). Dup` cum observa]i, token-urile sunt separate printr-unul sau mai multe spa]ii albe. Metoda Token() cite[te primul token de pe linia introdus` de la tastatur` [i-l returneaz`. Exemplu: \n programul urm`tor se cite[te [i se afi[eaz` un token. Dac` se tasteaz` [irul “Un token”, se afi[eaz` token-ul “Un”. Re]ine]i: metoda returneaz` numai primul token ! class prima { public static void main(String[] args) { String t=cin.Token(); System.out.println(t); } } Dac` dorim s` citim numai un caracter, vom utiliza metoda charAt(nr), care retuneaz` caracterul aflat pe pozi]ia nr a [irului de caractere. Aten]ie: primul caracter al [irului are indicele 0. Exemplu: \n programul urm`tor se cite[te [i se afi[eaz` un caracter. Observa]i modul de de utilizare al metodei charAt(). class prima { public static void main(String[] args) { String l=cin.linie(); char c=l.charAt(0); System.out.println(c); } } Dac` dorim s` citim numere, putem folosi tot metoda Token(). |n acest caz este sarcina noastr` s` convertim rezultatul c`tre tipul dorit. |n acest caz, vom utiliza metode ale unor clase, numite \nf`[ur`toare, clase care vor fi studiate la momentul potrivit. Metoda Integer.parseInt(sir) returneaz` [irul convertit c`tre int. Exemplu: Se citesc dou` numere naturale a [i b [i se afi[eaz` suma lor: class prima { public static void main(String[] args) { Capitolul 2. Tipuri şi operaţii de date 45 System.out.print("a="); int a=Integer.parseInt(cin.Token()); System.out.print("b="); int b=Integer.parseInt(cin.Token()); System.out.println(a+b);} } Metoda Long.parseLong(sir) returneaz` [irul convertit c`tre long. Exemplu: \n secven]a urm`toare, se citesc dou` numere naturale mai mari a [i b [i se afi[eaz` suma lor: long a=Long.parseLong(cin.Token()); long b=Long.parseLong(cin.Token()); System.out.println(a+b); Metoda float. Float.parseFloat(sir) returneaz` [irul convertit c`tre Exemplu: \n secven]a urm`toare, se citesc dou` numere reale a [i b [i se afi[eaz` suma lor: float a=Float.parseFloat(cin.Token()); float b=Float.parseFloat(cin.Token()); System.out.println(a+b); Metoda Double.parseDouble(sir) returneaz` [irul convertit c`tre float. Exemplu: \n secven]a urm`toare, se citesc dou` numere reale a [i b [i se afi[eaz` suma lor: double a=Double.parseDouble(cin.Token()); double b=Double.parseDouble(cin.Token()); System.out.println(a+b); Nu trebuie s` v` \ngrijora]i c` nu a]i \n]eles toate no]iunile prezentate. Pentru moment, lua]i-le ca atare. Toate vor fi studiate \n am`nunt. Pentru moment, s` ne mul]umim cu faptul c` putem citi [i afi[a un [ir de caractere. 2.6. Probleme rezolvate |ntruc@t cunoa[tem deja operatorii [i instruc]iunile [i putem citi date cu ajutorul clasei cin, de acum putem s` scriem mici programe. Toate instruc]iunile se vor g`si \n main(). 1. Se citesc dou` numere reale. Se cere s` se afi[eze num`rul cel mai mare dintre ele (calculul maximului). class prima { 46 Bazele programării în Java public static void main(String[] args) { System.out.print("a="); double a=Double.parseDouble(cin.Token()); System.out.print("b="); double b=Double.parseDouble(cin.Token()); if (a>b)System.out.println(a); else System.out.println(b); } } 2. S` se rezolve ecua]ia ax+b=0 (a,b). Numerele a [i b se citesc de la tastatur`. class prima { public static void main(String[] args) { System.out.print("a="); double a=Double.parseDouble(cin.Token()); System.out.print("b="); double b=Double.parseDouble(cin.Token()); if (a==0) if (b==0) System.out.println("infinitate de solutii"); else System.out.println("nu are solutie"); else System.out.println(-b/a); } } 3. Se cite[te n, num`r natural mai mare dec@t 0. S` se calculeze 1+2+...n. class prima { public static void main(String[] args) { System.out.print("n="); int i,s=0,n=Integer.parseInt(cin.Token()); for (i=1;i<=n;i++) s+=i; System.out.println("Suma este " +s); } } Observa]i modul \n care se afi[eaz`, mai \nt@i, [irul “n=”, si apoi se a[teapt` introducerea lui n. Prin expresia: "Suma este " +s se converte[te mai \nt@i tipul int c`tre String (obiect care re]ine un [ir de caractere), apoi cele dou` se concateneaz`. |n final, se afi[eaz` [irul astfel ob]inut. Aceasta \nseamn` c` pentru a converti o valoare numeric`, a, c`tre [ir, se poate face [irul sum` \ntre [irul vid [i a: “”+a. De re]inut! 4. Se cite[te n, num`r natural. Se cere s` se calculeze suma cifrelor lui. De exemplu, dac` se cite[te 124 se va afi[a 7. De acum, vom scrie numai metoda main(). public static void main(String[] args) { Capitolul 2. Tipuri şi operaţii de date 47 System.out.print("n="); int s=0,n=Integer.parseInt(cin.Token()); while (n!=0) { s+=n%10; n=n/10;} System.out.println("Suma cifrelor este " +s); } 5. Se cite[te n, num`r natural. Se cere s` se afi[eze num`rul ob]inut prin inversarea cifrelor sale. De exemplu, dac` se cite[te 123, se va afi[a 321. public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()), ninv=0; while (n!=0) { ninv=ninv*10+n%10; n=n/10; } System.out.println("Numarul este " +ninv); } 6. Se cite[te n num`r natural. S` se afi[eze descompunerea sa \n factori primi. public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()),i=2, fm; do { fm=0; while (n%i==0) { fm++; n/=i;} if (fm!=0) System.out.println(i+" la puterea "+fm); i++; } while (n!=1); } 7. Se cite[te n [i un vector cu n componente numere \ntregi. S` se afi[eze con]inutul componentelor vectorului. public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()),i; int V[]=new int[n]; for (i=0;i<n;i++) { System.out.print("V["+i+"]="); V[i]=Integer.parseInt(cin.Token()); } for (i=0;i<n;i++) System.out.println(V[i]); } Observa]i faptul c` vectorul are exact n componente [i nu a fost necesar ca acesta s` fie dimensionat de la \nceput cu un num`r de componente presupus maxim. 48 Bazele programării în Java 8. Se cite[te n [i un vector cu n componente numere reale. S` se afi[eze valoarea maxim` con]inut` de vector. public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()),i; double V[]=new double[n]; for (i=0;i<n;i++) { System.out.print("V["+i+"]="); V[i]=Double.parseDouble(cin.Token()); } double max=V[0]; for (i=1;i<n;i++) if (max<V[i]) max=V[i]; System.out.println("Valoarea maxima gasita="+max); } 9. Se cite[te n [i un vector cu n componente numere reale. S` se afi[eze con]inutul componentelor vectorului sortate cresc`tor. Se va utiliza metoda bulelor. public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()),i; double man; boolean gasit; double V[]=new double[n]; for (i=0;i<n;i++) { System.out.print("V["+i+"]="); V[i]=Double.parseDouble(cin.Token());} do { gasit=false; for (i=0;i<n-1;i++) if (V[i]>V[i+1]) { man=V[i]; V[i]=V[i+1]; V[i+1]=man; gasit=true;} } while (gasit==true); for (i=0;i<n;i++) System.out.println(V[i]); } 10. Interclasare. Se citesc m numere reale sortate cresc`tor. De asemenea, se citesc n numere reale sortate cresc`tor. Se cere s` se afi[eze cele m+n valori \n ordine cresc`toare. public static void main(String[] args) { System.out.print("m="); int m=Integer.parseInt(cin.Token()),i,j; double A[]=new double[m]; for (i=0;i<m;i++) { System.out.print("A["+i+"]="); A[i]=Double.parseDouble(cin.Token());} System.out.print("n="); Capitolul 2. Tipuri şi operaţii de date 49 int n=Integer.parseInt(cin.Token()); double B[]=new double[n]; for (j=0;j<n;j++) { System.out.print("B["+j+"]="); B[j]=Double.parseDouble(cin.Token()); } int k=0; double C[]=new double[m+n]; i=j=0; while (i<m && j<n) if (A[i]<B[j]) C[k++]=A[i++]; else C[k++]=B[j++]; if (i<m) for (j=i;j<m;j++) C[k++]=A[j]; else for (i=j;i<n;i++) C[k++]=B[i]; for (i=0;i<k;i++) System.out.println(C[i]); } 11. S` se citeasc` [i s` se afi[eze o matrice cu m linii [i n coloane, unde fiecare element re]ine un num`r \ntreg. public static void main(String[] args) { System.out.print("m="); int m=Integer.parseInt(cin.Token()),i,j; System.out.print("n="); int n=Integer.parseInt(cin.Token()); int A[][]=new int[m][n]; for (i=0;i<m;i++) for (j=0;j<n;j++) { System.out.print("A["+i+","+j+"]="); A[i][j]=Integer.parseInt(cin.Token()); } for (i=0;i<m;i++) { for (j=0;j<n;j++) System.out.print(A[i][j]+" "); System.out.println(); } } 12. Mai jos pute]i observa o secven]` simpl` prin care se pot inversa liniile i [i j ale unei matrice cu n linii [i m coloane (i,j<n). int Man[]; Man=A[i]; A[i]=A[j]; A[j]=Man; 50 Bazele programării în Java Probleme propuse 1. Ce se va afi[a \n urma execut`rii secven]elor urm`toare? 1.1) int x=3; x=~x; System.out.println(x); a) 3; b) 4; c)-3; d)-4. 1.2) int x=5; x=x<<3; System.out.println(x); a) b) c) d) 0; 2; 40; 5. a) b) c) d) 0; 2; 5; 1. 1.3) int x=5; x=x>>1; System.out.println(x); 1.4) System.out.println(7>10); a) b) c) e) eroare de execuţie; 7>10; false; true. 1.5) float x=1/2; System.out.println(x); a) b) c) d) 0; 0.5; Eroare; 1/2. System.out.print(-15/4); System.out.print(“ “); System.out.print(-15%4); a) b) c) d) -3 -3; -4 2; -4 -2; eroare. 1.6) 2. Fie x [i y dou` variabile logice. S` se demonstreze rela]iile de mai jos (de Morgan): a) !(x || y)=!x && !y. b) !(x && y)=!x || !y. 3. Evalua]i expresiile urm`toare, preciz@nd rezultatul: a) x+1.5, unde x este o variabil` \ntreag` ce con]ine num`rul 7; b) x<=4, unde x este o variabil` \ntreag` ce con]ine num`rul 4; c) a+1>3, unde a este o variabil` real` care con]ine num`rul 3; Capitolul 2. Tipuri şi operaţii de date d) e) f) g) 51 6/2; x/y+y/x unde x [i y sunt variabile \ntregi care con]in, 1 respectiv 6; x<3 || x>6 (unde x este o variabil` real` care re]ine 7); x<3 && x>6 (la fel ca mai sus); 4. Fie x o variabil` de tip int. Pentru ce valori ale lui x expresia: x+7==8*x ia valoarea true? 5. La fel ca mai sus, numai c` expresia este: 2*x+3==6. 6. Consider`m long a=3; char b=2; Care este valoarea produs` de expresia a+b, [i care este tipul rezultatului? a) Nu se poate aduna con]inutul unei variabile de tip char cu acela al unei variabile numerice. Compilatorul furnizeaz` eroare de sintax` la compilare; b) Rezultatul este 5 [i este de tip char; c) Rezultatul este 5 [i este de tip long. 7. Consider`m int a=-10,b=3; Care sunt valorile produse de expresiile a/b [i a%b ? a) -3,33333...3 [i 2; b) -3 [i -1; c) -4 [i 2. 8. Consider`m int a=2; Care este valoarea rezultat` \n urma evalu`rii expresiei 1/(2*a)? a) b) c) 0.25; Operatorul "/" ac]ioneaz` numai asupra variabilelor de un tip real. Avem eroare de sintax`. 0. 9. Consider`m int a=2,b=5; evalu`rii expresiei a+3<=b+2? a) b) c) Care este valoarea rezultat` \n urma true; false; Este obligatoriu s` folosim paranteze, pentru c` altfel nu se poate face evaluarea. 10. Consider`m int a=5,b=5; Care este valoarea rezultat` \n urma evalu`rii expresiei a++/++b? a) 1; b) 0,833333; c) 0. 52 Bazele programării în Java 11. Avem int a=5,b=3; Care este valoarea rezultat` \n urma evalu`rii expresiei a&b+a|b+a^b? a) 11; b) nedecidabil; c) 21. 12. Consider`m int a=0,b=3; Care este valoarea rezultat` \n urma evalu`rii expresiei a+=b+1? a) b) c) |n partea st@ng` a unei atribuiri trebuie s` figureze o singur` variabil` [i nu o expresie; 4; c) 3. 13. Consider`m int a=0,b=3; Care este valoarea rezultat` \n urma evalu`rii expresiei a=1=b? a) b) c) Eroare de sintax`; 3; true. 14. Dac` x [i y sunt de tip int, ce valori trebuie s` re]in` pentru ca expresia (x | y)==(x ^ y ) s` produc` valoarea true? a) 3 3; b) 3 5; c) 4 7; d) 4 2. 15. Dac` x este de tip int, care dintre expresiile de mai jos produce valoarea 0, indiferent de con]inutul variabilei x? a) x & x; b) x | x; c) x ^ x; d) x | !x. 16. Dac` x este de tip int, rezolva]i ecua]ia: (x & x)==x. 17. Dac` x este de tip int, rezolva]i ecua]ia: (x ^ x)==x. 18. Dac` x [i y sunt de tip int, rezolva]i ecua]ia: (x ^ x ^ y)==y. 19. Dac` x este de tip int, rezolva]i ecua]ia: (x | ~x)==x. 20. Care este func]ia evaluat` de expresia de mai jos (x este real)? x<2?x-1:x*x 21. Care este valoarea pe care o re]ine variabila rez dup` executarea secven]ei de mai jos? int k,rez; k=4; rez=3+k/5; a) 3; b) secven]a este gre[it`; c) 4. Capitolul 2. Tipuri şi operaţii de date 53 22. Care dintre secven]ele de mai jos este corect` din punct de vedere sintactic? a) k=4; if (k>=0); else; b) k=4; if(k>=0) then; else; c) k=4; if k>=0; else; 23. Care va fi valoarea variabilei s dup` executarea secven]ei? int i,s=0; for (i=1;i<=10;i++) { i=i/10; s+=i;} a) 0; b) 10; c) Secven]a cicleaz`; d) 1. 24. Ce se \nt@mpl` dac` se ruleaz` secven]a urm`toare? int a=1,b=6; while (a!=b) { a++; b--;} System.out.println(a); a) secven]a cicleaz`; b) se afi[eaz` 3; c) secven]a con]ine erori de sintax`; d) nici una din variantele de mai sus nu este adev`rat`. 25. Ce se \nt@mpl` dac` se ruleaz` secven]a urm`toare? int x=3; while (x!=x*x) x=x/2; System.out.println(x); a) secven]a cicleaz`; b) se afi[eaz` 1; c) se afi[eaz` 0; d) nici una dintre variantele de mai sus nu este adev`rat`. Testele de la 26 la 29 se refer` la programul urm`tor: int x=3; do { x--; x*=2;} while (x!=10); 26. De c@te ori se execut` secven]a subordonat` instruc]iunii do? a) o dat` b) de dou` ori c) de trei ori d) secven]a cicleaz` 27. |nlocui]i cele dou` atribuiri subordonate instruc]iunii do cu una singur`, astfel \nc@t programele ob]inute s` fie echivalente. 54 Bazele programării în Java 28. Dac` valoarea ini]ial` a lui x este 5 (x=5), care trebuie s` fie condi]ia de continuare ( while (x=?) ) astfel \nc@t atribuirile subordonate lui do s` se execute exact de 4 ori? a) 10 b) 8 c) 50 d)28 29. Pentru care dintre valorile ini]iale ale lui x (de mai jos) programul nu cicleaz`? a) 0 30. b) 1 c) 2 d) 4 Care dintre atribuirile de mai jos \nlocuieste secven]a celor trei atribuiri: x:=x-1; x:=2*x; x:=x+1; a) x:=2*x-1 b) x:=2*x-3 c) x:=2*x+1 d) x:=2*x 31. S` se scrie un program care rezolv` ecua]ia ax2+bx+c=0, unde: (a,b,c ). 32. S` se calculeze valoarea func]iei F, definit` pe mul]imea numerelor reale, pentru un x citit: 33. Se citesc n numere reale. S` se afi[eze valoarea minim` citit`. 34. Se cite[te un [ir de numere \ntregi p@n` la \nt@lnirea num`rului 0. S` se calculeze media aritmetic` a numerelor din [ir. 35. Citim un [ir de numere \ntregi, la fel ca la problema precedent`. S` se calculeze suma dintre primul num`r, al treilea, al cincilea,... [i produsul dintre al doilea, al patrulea,... etc. 36. Se cite[te n, num`r natural. S` se calculeze expresiile de mai jos (programe separate): 1 1 1 ... 2 ; 2 2 32 n 1 2 n E2 ... ; 23 3 4 ( n 1)( n 2) E1 1 E3 1 1 1 1 ... , unde n! 1 2 ... n. 1! 2! n! 37. Se cite[te o succesiune de cifre 1 [i 0, prima fiind 1. Aceasta are semnifica]ia unui num`r \n baza 2. S` se afi[eze num`rul \n baza 10. Capitolul 2. Tipuri şi operaţii de date 55 38. Se consider` [irul definit astfel (FIBONACCI). 1, dacã n 1 sau n 2 u (n) u ( n 1) u ( n 2), altfel Se cite[te o valoare natural` a>0. S` se calculeze u(a). 39. Se consider` [irul definit la problema anterioar`. S` se afi[eze num`rul de termeni care sunt strict mai mici dec@t o valoare citit`. 40. Se cite[te un num`r natural. C@te cifre con]ine? 41. Se cite[te un num`r natural cu 5 cifre. Afi[a]i num`rul format dup` eliminarea cifrei din mijloc. 42. Un num`r se nume[te perfect dac` este egal cu suma divizorilor s`i (exclusiv el). Exemplu: 6=1+2+3. Afi[a]i toate numerele perfecte mai mici dec@t o valoare dat`. 43. Afi[a]i toate numerele naturale mai mici dec@t o valoare dat`, care sunt egale cu suma p`tratelor cifrelor lor. 44. Afi[a]i primele n perechi de numere prime care sunt consecutive \n mul]imea numerelor impare. Exemplu: (3,5), (5,7). 45. Se cite[te un num`r natural par. S` se descompun` \n sum` de numere prime (conjectura GOLDBACH). 46. Se cite[te un vector cu n componente, numere naturale. S` se afi[eze cel mai mare num`r ra]ional subunitar \n care num`r`torul [i numitorul fac parte din mul]imea valorilor citite. Exemplu: dac` am citit valorile 1 2 3 se afi[eaz` 2/3. 47. Acela[i enun] ca la problema anterioar`, numai c` se cere s` se afi[eze cel mai mic num`r ra]ional supraunitar. 48. Se cite[te un vector cu n componente numere naturale. Se cere s` se ob]in` toate permut`rile circulare la dreapta. Exemplu: dac` n=4, si vectorul este 1 2 3 4, permut`rile circulare sunt: 1 2 3 4, 4 1 2 3, 3 4 1 2, 2 3 4 1. Observa]i faptul c`, de fiecare dat`, ultimul element trece pe prima pozi]ie, iar restul elementelor sunt deplasate la dreapta cu o pozi]ie. 49. Se dau n numere ra]ionale, re]inute \n doi vectori a [i b. Astfel, num`r`torul primului num`r este a[1], numitorul s`u este b[1], etc. Programul va decide dac` numerele date sunt distincte. |n cazul \n care r`spunsul este afirmativ, programul va afi[a DA, altfel va afi[a NU [i o pereche de numere egale. 56 Bazele programării în Java 50. Se numere numere cere s` dau n numere ra]ionale distincte, re]inute \n doi vectori a [i b [i m ra]ionale distincte re]inute \n vectorii c [i d. Se consider` c` cele n alc`tuiesc o mul]ime X [i cele m numere alc`tuiesc o mul]ime Y. Se se afi[eze: a) XY; b) XY; c) X-Y. Observa]ie: pentru fiecare cerin]` se va face un program. Răspunsuri: 1.1 d), 1.2 c), 1.3 b) 1.4 c) 1.5 a) 1.6 a) 4. x=1. 5. x 6. c) 7. b) 8. c) 9. a) 10. c) 11. a) 12. b) 13. a) 14. d) 15. c) 16. Orice num`r care poate fi re]inut de tipul int; 17. x=0; 18. Orice x [i y care pot fi re]inute de tipul int.; 19. x=-1; 20. f(x) x-1 daca x<2, x*x altfel; 21. a) 22. a) 23. c) 24. a) 25. b) 26. c) 27. x=2*(x-1); 28. c); 29. d); 30. a). CAPITOLUL 3 Metode Din cuprins: Generalităţi Structura unei metode şi apelul ei Transmiterea parametrilor Despre variabile Exemple de utilizare ale metodelor Metode recursive - exemple Supraîncărcarea metodelor Probleme propuse 58 Bazele programării în Java 3.1. Generalităţi |n Java se lucreaz` orientat spre obiect (prin programare orientat` pe obiecte). Din ra]iuni didactice, vom \ncerca s` prezent`m lucrurile pornind de la ceea ce [tim deja, dac` am lucrat, c@t de c@t, \ntr-un alt limbaj de programare. Mai precis, vom \nv`]a s` lucr`m cu variabile (date membru) [i func]ii (metode) ata[ate clasei care con]ine main(). Aceasta ne permite s` exers`m utilizarea subprogramelor \n Java, f`r` a ne complica de la \nceput cu mecanismele specifice program`rii pe obiecte. Acest fapt este important pentru c` nu are sens ca absolut orice problem` s` fie rezolvat` prin mecanismele program`rii orierntate pe obiecte. |n Java, exist` posibiltatea de a declara variabile vizibile la nivel de clas`, a[a cum se vede \n programul de mai jos, unde se citesc con]inuturile numerice a dou` astfel de variabile [i se afi[eaz` suma lor. Ca s` respect`m terminologia consacrat`, le vom numi date membru (ale clasei care con]ine main()). Pentru moment, pentru a putea lucra ca acest mod este obligatoriu ca datele membru s` fie precedate de modificatorul static. Justific`rile celor prezentate acum vor fi date ulterior. public class Clasa1 { static int a,b; public static void main(String[] args) { a=Integer.parseInt(cin.Token()); b=Integer.parseInt(cin.Token()); System.out.println(a+b);} } Orice dat` membru (variabil`) a clasei este ini]ializat` automat, la pornirea programului. Astfel, datele numerice sunt ini]ializate cu 0, datele de tip boolean cu false, datele de tip caracter cu caracterul de cod 0, datele de tip referin]` cu null (nu con]in nici o adres`). Cele afirmate pot fi verificate cu programul urm`tor, dar caracterul de cod 0 nu este afi[abil. class prima { static int a; static float b; static char c; static boolean d; public static void main(String[] args) { System.out.println(a+" "+b+" "+c+" "+d);} } |n Java, nu vom mai folosi termenul de func]ie, ci un altul, specific program`rii orientate pe obiecte, numit metod`. Aceasta \nseamn` c` atunci c@nd spunem metod`, vom \n]elege c` vorbim despre o func]ie (subprogram). Justificarea termenului va fi f`cut` \n capitolul urm`tor. Orice metod` ata[at` clasei de baz` va fi precedat` de modificatorul Capitolul 3. Metode 59 static. Deocamdat`, re]inem acest lucru \n mod mecanic. Motiva]ia va fi dat`, ca [i \n cazul precedent, \n capitolul urm`tor. Exemplu de metod`: 1. Metoda test() are rolul de a afi[a un mesaj. Observa]i modul \n care am apelat-o din main(): public class Clasa1 { static void test() { System.out.println("eu sunt o metoda");} public static void main(String[] args) { test(); } } 3.2. Structura unei metode şi apelul ei |n esen]`, o metod` este alc`tuit` din: Antet - acesta con]ine mai multe informa]ii importante necesare compilatorului, numele netodei, lista parametrilor formali, tipul metodei [i, eventual, modificatori. Corpul metodei - acesta cuprinde instruc]iunile metodei. Exemplu: mai jos, pute]i observa metoda suma() ce are rolul de a calcula suma a dou` numere naturale. |n schema ata[at`, pute]i identifica elementele constitutive ale ei: Modificator Corpul metodei Tipul metodei Numele metodei Lista parametrilor formali static int suma(int x, int y) { return x+y; } Numele metodei – se utilizeaz` pentru a o identifica atunci c@nd metoda este apelat`. Lista parametrilor formali - parametrii formali sunt valorile pe care metoda le prime[te la apel. |n exemplu, lista este format` din doi parametri formali, x [i y, ambii de tipul int. 60 Bazele programării în Java Tipul metodei – sau altfel spus, precizeaz` natura rezultatului. |n exemplu, metoda returneaz` o valoare \ntreag` (de tip int), dar pot fi metode de alt tip, cum ar fi float double, etc. Exist` [i metode care nu returneaz` nimic, caz \n care tipul metodei este void. Corpul metodei – este sub forma unei instruc]iuni compuse. |n exemplu, acesta con]ine o singur` instruc]iune, return, prin care se calculeaz` [i se returneaz` suma parametrilor formali. Modificator – static Mai jos pute]i observa modul \n care se apeleaz` metoda suma(): public class Clasa1 { static int suma(int x, int y) {return x+y;} public static void main(String[] args) { System.out.println(suma(2,3)); int x=2, y=5; System.out.println(suma(x,y)); System.out.println(suma(3,y));} } Prin suma(2,3) se apeleaz` metoda suma(), unde x=2, [i y=3. Metoda returneaz` suma parametrilor (5) [i valoarea este afi[at`. Faptul c` apelul metodei este scris direct \n metoda System.out.println(), \nseamn` c` metoda este, \n expresia din System.out.println(), evaluat` ca o valoare (\n exemplu, de tip int). Prin suma(x,y), se apeleaz` metoda suma(), unde parametrii sunt valorile variabilelor x [i y (2 [i 5). Metodele care sunt de orice alt tip \n afara tipului void, trebuie s` returneze o valoare din tipul respectiv. Returnarea valorii se face prin utilizarea instruc]iunii return. |n exemplu, metoda suma() prin return x+y; returneaz` suma celor doi parametrii primi]i. Mai jos pute]i observa modul \n care se apeleaz` o metod` de tip void: public class Clasa1 { static void met() { System.out.println("Eu sunt o metoda de tip void"); } public static void main(String[] args) { met(); } } O metod` se apeleaz` printr-o instruc]iune de apel. Un exemplu de astfel de instruc]iune de apel este apelul de mai sus: met(). Sunt permise [i apeluri de genul suma(x,y), de[i nu \ntotdeauna au sens. De asemenea, se pot utiliza expresii prin care se apeleaz` o metod`: de exemplu, System.out,println(1+suma(2,3)), unde expresia este: 1+suma(2,3). Capitolul 3. Metode 61 Parametrii care figuraz` \n apelul unei metode se numesc parametri efectivi. De exemplu, \n apelul suma(2,3), parametrii efectivi sunt valorile 2 [i 3. |n apelul suma(x,y) parametrii efectivi sunt con]inuturile variabilelor x [i y. Metodele se pot apela una pe alta, indiferent de pozi]ia pe care o ocup` defini]ia lor \n cadrul clasei. |n exemplul de mai jos, metoda met1() apeleaz` metoda met(), de[i aceasta din urm` este definit`, \n cadrul clasei, dup` ea. class prima { static void met1() { System.out.println("Met1"); met();} static void met() { System.out.println("Met");} public static void main(String[] args) { met1();} } 3.3. Transmiterea parametrilor A[a cum am ar`tat, parametrii care se g`sesc \n antetul metodei se numesc parametri formali, iar cei care se g`sesc \n instruc]iunea de apel se numesc parametri efectivi. |ntre parametrii formali [i cei efectivi trebuie s` existe o anumit` concordan]`, care este descris` prin regulile urm`toare: Num`rul parametrilor parametrilor efectivi. Tipul parametrilor formali trebuie s` coincid` cu tipul parametrilor efectivi sau tipul parametrilor efectivi s` poat` fi convertit implicit (ca \n cazul atribuirii) c`tre tipul parametrilor formali la fel ca \n cazul atribuirii. Nu este obligatoriu ca numele parametrilor formali s` coincid` cu numele parametrilor efectivi. formali trebuie s` coincid` cu num`rul Exemple pentru metoda static int suma(int x, int y): a) prin apelul suma(1,2) se apeleaz` metoda suma() cu dou` valori de tip int, 2 [i 3. |n acest caz, num`rul parametrilor formali este 2 [i num`rul parametrilor efectivi este tot 2. b) prin apelul suma('1',3) am apelat metoda suma() cu doi parametri: unul de tip char, altul de tip int. Apelul este corect pentru c` o variabil`, constant`, de tip char poate fi converit` c`tre tipul int (la fel ca la atribuiri). 62 Bazele programării în Java c) dac` x, de exemplu, este tipul long, atunci apelul suma(x,y) nu este un apel corect pentru c` nu sunt permise conversiile de la long la int. La fel, nu este permis apelul de float la int, etc. d) parametrii efectivi pot fi expresii, ca \n apelul suma(2-3,3+4), unde se returneaz` 6. |n exemplu, se apeleaz` suma(-1,7). e) parametrii efectivi pot con]ine [i operatorul de conversie explicit`, ca \n apelul: suma(2,(int)3.7), unde se returneaz` 5. |n Java, parametrii se transmit numai prin valoare. Aceasta \nseamn` c` parametrul efectiv, chiar dac` este variabil`, r@m@ne nemodificat. Privi]i exemplul urm`tor: public class Clasa1 { static void exemplu(double x) { x=3.7; } public static void main(String[] args) { double x=5; exemplu(x); System.out.println(x); } } |n main() avem o variabil` x, de tip double, ini]ializat` cu 5. Apel`m metoda de tip void exemplu(). |n metod`, lui x i se atribuie alt` valoare (3.7). Dup` executarea metodei, se revine \n main() [i se afi[eaz` x. Valoarea afi[at` este cea ini]ial`, 5. Con]inutul variabilei x din main() a r`mas nemodificat. Cum este posibil acest lucru? Pentru fiecare parametru formal, metoda apelat` re]ine \n stiv` (o memorie special`, asupra c`reia vom reveni) un spa]iu. |n mod practic, se creeaz` o variabil` cu numele parametrului formal. Prin urmare, metoda exemplu() a creat \n stiv` o variabil` cu numele x. Acestei variabile i s-a atribuit valoarea 3.7. Variabila x din main() este cu totul alta. Din acest motiv, con]inutul lui x din main() r`m@ne nemodificat. Am ar`tat faptul c` numele unui masiv este o referin]` c`tre masiv ce se g`se[te \n memorie. |n acest caz, transmiterea unei referin]e c`tre un masiv ca parametru al unei metode are ca efect posibilitatea modific`rii con]inuturilor componentelor masivului. |ntruc@t masivele con]in [i data membru length, dac` o metod` prime[te ca parametru o referin]` c`tre masiv , atunci nu mai este necesar ca, \n alte limbaje de programare, s` transmitem [i num`rul de componente ale masivului. Capitolul 3. Metode 63 Exemplu: Metoda exemplu() calculeaz` suma numerelor re]inute de un vector [i face ca fiecare component` a vectorului s` re]in` valoarea 1. |n programul principal se ini]ializeaz` vectorul, apoi se probeaz` efectul metodei. public class Clasa1 { static int exemplu(int[] t ) { int s=0,i; for (i=0;i<t.length;i++) s+=t[i]; for ( i=0;i<t.length;i++) t[i]=1; return s; } public static void main(String[] args) { int[] v=new int [5]; int i; for (i=0;i<5;i++) v[i]=Integer.parseInt(cin.Token()); System.out.println(exemplu(v)); for (i=0;i<v.length;i++) System.out.print(v[i]+" "); } } 3.4. Despre variabile P@n` \n prezent am utilizat trei feluri de variabile: 1. |n corpul metodelor. Aceste variabile se numesc variabile locale. 2. |n antetul metodelor. Si acestea sunt, dup` cum vom vedea, tot variabile [i se numesc parametri. 3. La nivelul clasei. Acestea se numesc, a[a cum am ar`tat date membru. |n cadrul metodelor, parametrii sunt trata]i precum variabilele locale [i pot fi accesa]i din orice punct al metodei. De exemplu, dac` avem metoda static int met(int a) [i o apel`m prin met(2), metoda va avea o variabil` local` a care va fi ini]ializat` cu 2. Dac` avem un parametru cu un anumit nume, atunci nu mai este permis s` declar`m variabile locale cu acest nume. De exemplu, secven]a urm`toare d` eroare de compilare, pentru c` numele variabilei locale coincide cu numele parametrului. static void met(int a) { int a=7; System.out.println(a); } 64 Bazele programării în Java Variabilele locale pot fi accesate din blocul \n care au fost declarate [i, imediat ce au fost executate instruc]iunile din acel bloc, nu vor mai exista. De exemplu, \n metoda de mai jos am declarat dou` variabile locale, ambele cu numele i. Prima este declarat` \n for [i este recunoscut` de blocul (\n exemplu instruc]iunea) subordonat. Dup` \ncheierea execu]iei for-ului, aceast` variabil` nu mai exist`, prin urmare poate fi declarata din nou. static void met() { for (int i=1;i<=3;i++) System.out.println(i); int i=5; System.out.println(i);} |n cazul \n care avem o data membru cu un anumit nume [i dac` \ntr-o metod` declarat` cu modificatorul static ([i p@n` acum am dat numai astfel de exemple) avem o variabil` local` (parametru) cu acela[i nume, atunci din metod` se poate adresa doar varabila local` (parametrul). De exemplu, programul de mai jos afi[eaz` 2, adic` valoarea variabilei locale a [i nu 3, valoarea re]inut` de data membru. public class Clasa1 { static int a=3; public static void main(String[] args) { int a=2; System.out.println(a); } } Parametrii [i variabilele locale sunt memorate \ntr-o structur` special` de date, numit` stiva. Stiva func]ioneaz` pe principiul LIFO (Last In First Out) -"ultimul intrat, primul ie[it". Pentru a \n]elege modul de lucru cu stiva, ne imagin`m un num`r n de farfurii identice, a[ezate una peste alta (o "stiv`" de farfurii). Ad`ugarea sau scoaterea unei farfurii se face cu u[urin]`, numai \n v@rful stivei. Dup` ce am scos toate farfuriile din stiv`, spunem c` aceasta este vid`. Oric@t ar p`rea de simplu principiul stivei, el are consecin]e uria[e \n programare. Vede]i recursivitatea! 3.5. Exemple de utilizare ale metodelor 3.5.1. Exemple elementare 1. Se citesc dou` numere \ntregi m [i n. Se cere s` se tip`reasc` cel mai mare divizor comun [i cel mai mic multiplu comun al lor. Rezolvare. Presupunem cunoscut algoritmul care determin` cel mai mare divizor comun pentru dou` numere. Cel mai mic multiplu comun al dou` Capitolul 3. Metode 65 numere se poate determina \mp`r]ind produsul lor la cel mai mare divizor comun al lor. Prin urmare, scriem o metod` cmmdc cu doi parametri formali m [i n, care \ntoarce o valoare \ntreag` - cel mai mare divizor comun al lor. public class Clasa1 { static int cmmdc(int m, int n) { while (m!=n) if (m>n) m-=n; else n-=m; return m;} public static void main(String[] args) { int m=Integer.parseInt(cin.Token()); int n=Integer.parseInt(cin.Token()); int cm=cmmdc(m,n); System.out.println(cm);} } 2. Se citesc dou` numere naturale m<n. Se cere s` se tip`reasc` toate numerele palindrom aflate \ntre m [i n. Un num`r este palindrom dac` citit direct [i invers rezultatul este acela[i. Exemplu: 121. Rezolvare. S` analiz`m problema. Este necesar s` fie testate toate numerele \ntre m [i n, pentru ca apoi s` fie tip`rite numai cele care \ndeplinesc condi]ia cerut`. Pentru aceasta, vom scrie o metod` numit` palin() care are rolul de a testa dac` num`rul este sau nu palindrom. Evident, metoda trebuie s` fie de tipul boolean. Care este avantajul scrierii metodei? Acesta este dat de faptul c`, atunci c@nd scriem metoda, ne concentr`m exclusiv asupra ei, deci posibilitatea de a gre[i este minim`. Dac` dispunem de metod`, algoritmul este extrem de simplu: for de la m la n. |n plus, este posibil ca aceast` metod` s` poat` fi folosit` [i \n alte cazuri. public class Clasa1 { static boolean palin(int i) { int isalv=i,iinv=0; while (i!=0) { iinv=iinv*10+i%10; i=i/10;} return isalv==iinv; } public static void main(String[] args) { int m=Integer.parseInt(cin.Token()); int n=Integer.parseInt(cin.Token()); for(int i=m;i<n;i++) if (palin(i)) System.out.println(i); } } 66 Bazele programării în Java 3. Superpalindrom. Un num`r natural este palindrom dac` citit de la st@nga la dreapta [i de la dreapta la st@nga r`m@ne nemodificat. De exemplu, num`rul 12321 este palindrom. Un num`r natural este superpalindrom dac` este palindrom at@t el c@t [i p`tratul s`u. Scrie]i un program care listeaz` toate numerele cu aceast` proprietate aflate \ntre doi intregi a [i b . Rezolvare. Modul \n care test`m dac` un num`r este palindrom este acum l`murit. Mai mult, avem [i metoda. Nu trebuie dec@t s` o folosim: public class Clasa1 { static boolean palin(int i) { int isalv=i,iinv=0; while (i!=0) { iinv=iinv*10+i%10; i=i/10;} return isalv==iinv; } public static void main(String[] args) { int m=Integer.parseInt(cin.Token()); int n=Integer.parseInt(cin.Token()); for(int i=m;i<n;i++) if (palin(i)) if (palin(i*i)) System.out.println(i+" "+i*i); } } 4. Numere rotunde. Se cite[te n<10000. Se cere s` se afi[eze num`rul de numere mai mici sau egale cu n care, \n binar, au acela[i num`r de cifre 0 [i 1. De exemplu, 9 este un astfel de num`r 910=10012. Rezolvare. Trebuie testate numerele de la 1 la n. Prin urmare folosim instruc]iunea for cu i de la 1 la n. Acum trebuie testat dac`, \n binar, fiecare i are tot at@tea cifre 0 c@te cifre 1. Pentru asta folosim o metod` boolean`, numit` valabil. public class Clasa1 { static boolean valabil(int nr) { int zero=0,unu=0; while (nr!=0) { if (nr%2!=0) unu++; else zero++; nr=nr / 2; } return zero==unu; } public static void main(String[] args) { int n=Integer.parseInt(cin.Token()),s=0; for(int i=1;i<=n;i++) if( valabil(i))s++; System.out.println(s); } } Capitolul 3. Metode 67 3.5.2. Un exemplu de backtracking în Java Nu prezent`m aici tehnica backtracking. Este totu[i, o carte dedicat` limbajului Java [i spa]iul nu ar permite prezentarea integral` a tehnicilor de programare. Oricum, majoritatea dintre dvs. cunosc deja tehnica, iar dac` nu o cunoste]i, recomand s` o citi]i din manualele de informatic` pentru liceu. Generarea permut`rilor. Se cite[te n, se cere s` se afi[eze toate permut`rile mul]imii {1,2...n}. Observa]i modul de construc]ie [i utilizare a metodelor. public class Clasa1 { static void Init(int k,int[] st) { st[k]=0; } static boolean Am_Succesor (int n, int k,int[] st) { boolean rasp=false; if (st[k]<n) { st[k]++; rasp=true;} return rasp;} static boolean E_Valid(int k,int[] st) { boolean rasp=true; for (int i=1;i<k;i++) if (st[i]==st[k]) rasp=false; return rasp; } static boolean Solutie(int k, int n) { return k==n;} static void Tipar(int n, int[] st) { for (int i=1;i<=n;i++) System.out.print(st[i]); System.out.println();} static void back(int n) { boolean AS; int k=1; int[] st=new int[n+1]; Init(k,st); while (k>0) { do { } while ((AS=Am_Succesor(n,k,st)) && !E_Valid(k,st)); if (AS) if (Solutie(k,n)) Tipar(n,st); else {k++; Init(k,st);} else k--; } } public static void main(String[] args) { int n=Integer.parseInt(cin.Token()); back(n); } } 68 Bazele programării în Java Se puteau folosi date membru pentru n [i st. |n acest caz, am fi avut mai pu]ini parametri... 3.6. Metode recursive |n Java, metodele pot fi recursive. Aceasta \nseamn` c` o metod` se poate autoapela. Exemplul 1. S` se calculeze recursiv n!. Pentru a scrie o metod` recursiv` care efectueaz` acela[i calcul, vom porni de la o defini]ie recursiv` a lui n!. Aceasta este: 1, n! fact(n) n fact(n 1), n0 altfel nN De exemplu, pentru a calcula 3!, proced`m astfel: 3!=fact(3)=3fact(2)=32fact(1)=321fact(0)=3211=6. Metoda recursiv` fact() nu face altceva dec@t s` transcrie defini]ia recursiv` prezentat` anterior: public class Clasa1 { static int fact(int n) { if (n==0) return 1; else return n*fact(n-1); } public static void main(String[] args) { System.out.println(fact(3)); } } Care este mecanismul prin care subprogramele se pot autoapela? S` ne amintim modul \n care subprogramele memoreaz` parametrii transmi[i: Pentru memorarea parametrilor, memorie numit` stiv`. subprogramele folosesc o zon` de Stiva este o structur` de date de tip special. Astfel, ultima dat` introdus` \n stiv` este prima care se poate accesa (scoate din stiva). Apoi, se acceseaz` iar ultima, dar care \n cazul ini]ial era prima [.a.m.d. Memorarea parametrilor transmi[i se face \n ordinea \n care ace[tia figureaz` \n antet: de la st@nga la dreapta. Capitolul 3. Metode 69 |n continuare, prezent`m grafic modul \n care func]ioneaz` recursivitatea \n cazul metodei fact() a programului anterior. Aceast` metod` nu are variabile locale, deci \n stiv` se depune doar parametrul n. n 3 n 2 n 3 n 1 n 2 n 3 n 0 n 1 n 2 n 3 n 1 n 2 n 3 n 2 n 3 n 3 La primul apel al metodei fact() se creeaz` \n stiv` o variabil` numit` n, care re]ine 3 valoarea parametrului formal. Metoda se autoapeleaz`. De aceast` dat`, parametrul n ia valoarea 2. |n stiv` se creeaz` un nou nivel care re]ine n cu valoarea 2. Metoda se autoapeleaz`. De aceast` dat` parametrul n ia valoarea 1. |n stiv` se creeaz` un nou nivel, care re]ine n cu valoarea 1. fact=1 Metoda se autoapeleaz`. Parametrul n ia valoarea 0. |n stiv` se creeaz` un nou nivel, care re]ine n cu valoarea 0. Func]ia ia valoarea 1, autoapelul nu mai are loc. Se revine pe nivelul 3. fact=1 Pe nivelul 3 se efectueaz` calculul 1*1=1. Se revine apoi pe nivelul 2. fact=2 Pe nivelul 2 se efectueaz` calculul 2*1=2. Se revine apoi pe nivelul 1. fact=6 Pe nivelul 1 se efectueaz` calculul 3*2=6. Se revine apoi \n main(). Aici se afi[eaz` 6, adic` s-a calculat 3!. 70 Bazele programării în Java 3.7. Exemple de utilizare a metodelor recursive 3.7.1. Exemple elementare 1. Se cite[te xZ. Se cere programul pentru calculul func]iei: x 12 x 1, F(x) F(F(x 2)), x 12 public class Clasa1 { static int manna (int x) { if (x>=12) return x-1; else return manna(manna(x+2)); } public static void main(String[] args) { int n=Integer.parseInt(cin.Token()); System.out.println(manna(n)); } } 2. Se dau dou` numere naturale, a [i b. Se cere s` se calculeze cel mai mare divizor comun al lor. Pentru rezolvare, utiliz`m o defini]ie recursiv` a celui mai mare divizor comun pentru dou` numere naturale a [i b. ab a, cmmdc(a, b) cmmdc(a b, b),a b cmmdc(a, b a), a b Aceast` defini]ie este transcris` \n metoda recursiv` cmmdc. public class Clasa1 { static int cmmdc (int a,int b) { if (a==b) return a; else if (a>b) return cmmdc(a-b,b); else return cmmdc(a,b-a); } public static void main(String[] args) { int a=Integer.parseInt(cin.Token()); int b=Integer.parseInt(cin.Token()); System.out.println(cmmdc(a,b)); } } Capitolul 3. Metode 71 3. S` se scrie o metod` recursiv` pentru a calcula suma cifrelor unui num`r natural. Ideea: se izoleaz` ultima cifr`, iar lui n i se atribuie c@tul \ntreg dintre vechea valoare [i 10. Aceast` idee folose[te pentru a g`si o rela]ie de recuren]`, necesar` elabor`rii variantei recursive: 0, S(n) n % 10 S(n / 10), n0 altfel Programul de mai jos, calculeaz` suma utiliz@nd rela]ia prezentat`. public class Clasa1 { static int s(int n) { if (n==0) return 0; else return n%10 +s(n/10); } public static void main(String[] args) { int n=Integer.parseInt(cin.Token()); System.out.println(s(n)); } } 4. S` se scrie o metod` recursiv` pentru a transforma un num`r natural n, din baza 10 în baza k (1<k<10). S` ne amintim algoritmul clasic de trecere din baza 10 \n baza k. Num`rul se \mparte la k, se re]ine restul, c@tul se \mparte la k, se re]ine restul ... p@n` c@nd c@tul este mai mic dec@t \mp`r]itorul. Rezultatul se ob]ine prin scrierea \n ordine invers` a resturilor ob]inute. Practic, afi[area restului se face dup` autoapel. public class Clasa1 { static void transform(int n,int b) { int rest=n%b; if (n>=b) transform(n/b,b); System.out.print(rest);} public static void main(String[] args) { int n=Integer.parseInt(cin.Token()); int b=Integer.parseInt(cin.Token()); transform(n,b);} } 3.7.2. Backtracking recursiv 1. Se cite[te n, num`r natural. S` se afi[eze pemut`rile mul]imii {1,2...n}. Se cere s` se aplice un algoritm de generare recursiv. 72 Bazele programării în Java Rezolvare. Vom folosi o metod` standard, recursiv` de generare a permut`rilor. Observa]i faptul c`, de aceast` dat`, st [i n sunt date membru. public class Clasa1 { static int[] st=new int[10]; static int n; static void init(int k) {st[k]=0;} static boolean succesor (int k) { if (st[k]<n) { st[k]++; return true;} else return false; } static boolean valid (int k) { boolean ev=true; for (int i=1;i<=k-1;i++) if (st[k]==st[i]) ev=false; return ev; } static boolean solutie(int k) { return k==n+1;} static void tipar() { for (int i=1;i<=n;i++) System.out.print(st[i]); System.out.println(); } static void back(int k) { if (solutie(k)) tipar(); else { init(k); while(succesor(k)) if (valid(k)) back(k+1); } } public static void main(String[] args) { n=Integer.parseInt(cin.Token()); back(1); } } 2. Se citesc n [i p, numere naturale. S` se afi[eze toate aranjamentele de n luate c@te p. Rezolvare. Singura diferen]` fa]` de algoritmul anterior este c`, de aceast` dat`, o solu]ie are lungimea p. Aceasta atrage modificarea metodelor solutie() [i tipar(). |n plus, va trebui sa-l citim [i pe p. |n rest, programul este acela[i. public class Clasa1 { Capitolul 3. Metode 73 static int[] st=new int[10]; static int n,p; ... static boolean solutie(int k) { return k==p+1;} ... static void tipar() { for (int i=1;i<=p;i++) System.out.print(st[i]); System.out.println(); } ... public static void main(String[] args) { n=Integer.parseInt(cin.Token()); p=Integer.parseInt(cin.Token()); back(1);} } 3. Se citesc n [i p, numere naturale. S` se afi[eze toate combin`rile de n luate c@te p. Rezolvare. Programul este aproape la fel cu programul de generare a aranjamentelor. Practic, elementele se generaz` \n st \n ordine strict cresc`toare. Aceasta elimin` [i posibilitatea de generare dubl` a lor ( de exemplu {2,1}, {1,2}). |n plus, dac` elementele sunt generate \n ordine strict cresc`toare, dispare condi]ia prin care se verific` dac` sunt distincte sau nu. Aceasta \nseamn` c` metoda valid() devine inutil`. |n acest caz, ori determin`m ca metoda valid() s` returneze \ntotdeauna true, p`str@nd structura metodei back() ca mai jos, ori mai eficient, n-o mai apel`m. static void init(int k) { if (k==0) st[k]=0; else st[k]=st[k-1];} static boolean valid (int k) { return true; } 3.8. Supraîncărcarea metodelor |n Java, metodele pot fi supra\nc`rcate. Aceasta \nseamn` c` putem avea dou` sau mai multe metode cu acela[i nume, dar care difer` prin tipul [i/sau num`rul parametrilor. Privi]i programul de mai jos, care con]ine dou` metode cu acela[i nume, cu acela[i num`r de parametri (1), dar de tip diferit (int, respectiv float). public class Clasa1 { static void eu_sunt(int n) { System.out.println("Parametru de tip int "+ n); } static void eu_sunt(double n) { System.out.println("Parametru de tip double "+n ); } 74 Bazele programării în Java public static void main(String[] args) { eu_sunt(3); eu_sunt(-2.7); } } Faptul c` metodele pot fi supra\nc`rcate are consecin]e uria[e \n programare. Dac` \n cazul program`rii clasice (neorientate pe obiecte) se poate tr`i bine [i f`r` aceast` facilitate, \n cazul program`rii orientate pe obiecte, aceast` facilitate devine esen]ial`, a[a cum va rezulta din capitolele urm`toare. Un exemplu este chiar metoda println(), at@t de utilizat` p@n` \n acest moment. Ea afi[eaz` orice i-am transmite ca parametru: o valoare de tip int, o valoare de tip float, un caracter sau un [ir de caractere. De fapt, exist` mai multe metode println() care difer` doar prin tipul parametrului. Probleme propuse 1. "Numai ultima cifr`". Se citesc n, num`r natural <100, [i n numere naturale xi, nenule, mai mici ca 30000. Se cere: ultima cifr` a num`rului x1 x2 .... xn ; ultima cifr` a num`rului x1 2 x x3 ..... xn . Exemplu: n=3; x1=11; x2=4; x3=3. Programul tip`re[te: 8, pentru c` ultima cifr` a sumei 11+4+3 este 8; 1, pentru c` ultima cifra a lui 1112 este 1. 2. S` se citeasc` dou` matrice [i s` se fac` suma lor. Programul se va realiza astfel: se scrie o metod` de citire a unei matrice cu m linii [i n coloane; se scrie o metod` de afi[are a unei matrice cu m linii [i n coloane; se scrie o metod` care adun` dou` matrice; con]inutul metodei main() rezult` din apelul acestor metode. 3. S` se calculeze coeficien]ii polinomului P(x)=(x+a)n, \n dou` variante: a) Programul utilizeaz` o metod` care \nmul]e[te un polinom oarecare de grad k cu polinomul x+a. Capitolul 3. Metode 75 b) Programul utilizeaz` o metod` care calculeaz` coeficien]ii, a[a cum rezult` din formula de mai jos (binomul lui Newton): n ( x a ) n Cnk a k x n k k 0 4. S` se tip`reasc` toate numerele prime aflate \ntre doi \ntregi citi]i. Programul va folosi o metod` care returneaz` 1 sau 0 dac` num`rul este prim sau nu. 5. Scrie]i un program care tip`re[te numerele \ntregi g`site \ntre dou` valori citite care se divid cu suma cifrelor lor. Programul va utiliza o metod` care returneaz` suma cifrelor unui num`r \ntreg primit ca parametru. 6. Pentru fiecare metod` de sortare cunoscut`, scrie]i c@te o metod` care sorteaz` descresc`tor un vector cu componente numere reale. 7. Scrie]i o metod` care interclaseaz` doi vectori sorta]i descresc`tor. 8. Scrie]i o metod` care identific` \ntr-un vector cu numere reale, sortate cresc`tor, dac` o anumit` valoare este sau nu re]inut` de vector. Metoda va utiliza algoritmul de c`utare binar`. 9. Un polinom P(X) de grad n, cu coeficien]ii reali este memorat sub form` de vector (cu n+1) componente. Se cere s` se scrie o metod` care calculeaz` P(a), unde a este un num`r real citit. Indica]ie. Se va utiliza schema lui Horner. Exemplu: P(X)=X2+5X+6 cere P(4). 1 1 5 9 6 42 |n r@ndul 2, 1 este coeficientul polinomului. Apoi: 1*4+5=9; 9*4+6=42. 10. Ce afi[eaz` programul urm`tor? public class Clasa1 { static int f(int x) { return x+1;} static void t(int a) { System.out.println(++a);} public static void main(String[] args) { t(f(f(f(1)))); } } a) b) c) d) 3 4 5 6 a) b) c) d) 233; 23; 32; 232 11. Ce afi[eaz` programul urm`tor? public class Clasa1 { static int a; static int f() { int a=3; return a;} Se 76 Bazele programării în Java static void g() { int a=3; System.out.print(a);} public static void main(String[] args) { a=2; System.out.print(a);; g(); System.out.print(f());} } 12. |n programul de mai jos, \nlocui]i cele trei puncte cu una din secven]ele de mai jos. Pentru care dintre ele programul afi[eaz` produsul celor dou` numere citite. public class Clasa1 { static int a,b,t=0; static void increment () { t++; } public static void main(String[] args) { int i,j; a=Integer.parseInt(cin.Token()); b=Integer.parseInt(cin.Token()); ... increment() System.out.println(t); } } a) b) for (i=1;i<=b;i++) for (j=1;j<=b;j++) for (i=1;i<=a;i++) for (j=1;j<=b-1;j++) c) d) for (i=1;i<=b;i++) for (j=1;j<=a-1;j++) for (i=1;i<=b;i++) for (j=1;j<=a;j++) 13. Care dintre instruc]iunile de mai jos, \nlocuit` \n program (\n locul celor 3 stelu]e) nu calculeaz` a2, pentru un num`r natural, a citit? public class Clasa1 { static int increment (int x) { return x+1; } static int decrement (int x) { return x-1; } public static void main(String[] args) { int a=Integer.parseInt(cin.Token()); ***} } Capitolul 3. Metode 77 a) System.out.println(increment(increment(a)*decrement(a))); b) System.out.println(increment(a)*decrement(a)+1); c) System.out.println(1+increment(a)*decrement(a))); 14. Calcula]i recursiv suma a n numere naturale citite. 15. Calcula]i recursiv expresiile: a) 12+23+...+n(n+1); b) 1+1/2+...+1/n; c) 1/(23)+2/(3*4)+...+n/((n+1)(n+2)); k 16. Se citesc n [i k (numere naturale n>k). Calcula]i, recursiv, Cn , prin k 1 n 1 utilizarea formulei de recuren]`: C C k n C . Este eficient? k n 1 17. Scrie]i un program iterativ care rezolv` problema anterioar` utiliz@nd aceea[i formul`. 18. Calcula]i recursiv, Cnk prin utilizarea formulei: 1, C nk n k 1 k 1 Cn k k 0; altfel. 19. Se cite[te un num`r natural n. Se cere s` se scrie o metod` recursiv` care returneaz` cea mai mic` baz` \n care se poate considera n. 20. Scrie]i o metod` boolean` recursiv` care testeaz` dac` un num`r natural n>1 este prim. 21. Scrie]i o metod` recursiv` care returneaz` suma elementelor pare ale unui vector citit. Exemplu: n=4, V=(2,2,5,6). Se returneaz` 10. 22. Scrie]i o metod` recursiv` boolean` prin care se testeaz` dac` un num`r natural x se reg`se[te \ntre componentele unui vector V cu n numere naturale. 23. Scrie]i o metod` recursiv` care returneaz`, oglinditul unui num`r natural. Exemplu: pentru n=123 se returneaz` 321. 24. Scrie]i o metod` recursiv` care descompune \n toate modurile posibile un num`r natural n \n dou` numere n1 [i n2, n1n2 a c`ror sum` este n. 78 Bazele programării în Java 25. Pentru un vector cu n componente 0 sau 1 care are semnifica]ia de num`r binar, se cere s` se scrie o metod` recursiv` care afi[eaz` num`rul \n baza 10. Exemplu: pentru n=4 [i V=(1011) se va returna 11. 26. Scrie]i o metod` recursiv` care afi[eaz` valoarea unui polinom \n punctul a. Coeficien]ii polinomului sunt da]i \ntr-un vector. Astfel, pentru V=(1,2,3) avem polinomul P=x2+2x+3. 27. Fie func]ia definit` pe N*N* Se citesc n [i k. Se cere s` se scrie o metod` recursiv` care evalueaz` func]ia: 0, S(n, k) 1, S(n 1, k 1) kS(n 1, k) kn k 1, n 1 k n 28. Calcula]i func]ia definit` pe N*N: 0, F(n, k) 1 F(n 1, k 1) nF(n 1, k) k 0 sau k n; k n; 1 k n. 29. Calcula]i iterativ [i recursiv cel mai mare divizor pentru dou` numere naturale m [i n, utiliz@nd algoritmul lui Euclid: cmmdc(n, m mod n), cmmdc(m, n) m, n0 n0 30. Ce se afiseaz` pentru System.out.println(t(12)); ? static int t(int n) { if (n!=0) return 10*t(n/10)+ n%10; else return 0; } a) 12; b) 21; c) eroare; d) 0. 31. Ce calculeaz` metoda urm`toare? static int t(int n) { if (n!=0) return (n%2)*n +t(n-1); else return 0; } a) suma primelor n numere naturale impare; b) suma primelor n numere naturale pare; c) suma numerelor naturale impare strict mai mici dec@t n; d) suma numerelor naturale impare mai mici sau egale cu n. Capitolul 3. Metode 79 32. |n metoda de mai jos \nlocui]i linia ... cu una dintre instruc]iunile urm`toare, astfel \nc@t metoda s`-[i \ncheie execu]ia f`r` eroare pentru orice valoare admisibil` a argumentului: static int x(int n) { if (n!=0) { System.out.println(n); ... } else return 0; } a) return x(n-2); c) return x(n-1); b) return x(n%2); d) return x(n/2); 33. Dac` metoda este apelat` prin an(4), de c@te ori se autoapeleaz`? static int an(int n) { if (n==0) return 1; else return 3*an(n-1)+7; } a) de 4 ori; c) de 5 ori; b) de 3 ori; d) depinde de stiv`. Răspunsuri: 10. c) 11. a) 12. d) 13. c) 30 a) 31. d) 32. d) 33. a) CAPITOLUL 4 Clase - primele noţiuni, exemple Din cuprins: Ce este o clasă ? Constructori Date membru statice şi metode statice Cuvântul cheie this Referinţe către obiecte Masive de obiecte Aplicaţii ale noţiunilor prezentate s Garbage Collector Cum sunt memorate clasele ? Pachete Clase interioare O problemă de terminologie Probleme propuse 81 Bazele programării în Java 4.1. Ce este o clasă ? La matematic` v-a]i \nt@lnit cu numere complexe! Ele sunt de forma: z=x+iy, unde x,y. Prin urmare, pentru fiecare num`r complex ar trebui s` re]inem dou` valori reale, pentru x [i pentru y. Decidem c` \n acest caz, pentru a le re]ine, avem nevoie de dou` variabile de tip double. Privi]i programul de mai jos care con]ine dou` clase: Complex [i test.. class Complex { // date membru double x,y; // metoda void afis() { System.out.println(x+" } "+y); } public class test { public static void main(String[] args) { // declar un numar complex Complex z1; z1= new Complex (); // Complex z1=new Complex(); // Datelor membru li se atribuie valori z1.x=3; z1.y=-4.7; // Afisez datele membru z1.afis(); } } S` analiz`m programul. Clasa Complex: 1. Clasa con]ine dou` date membru, x [i y, ambele de tip double. 2. Clasa con]ine o metod` care convenabil datele membru ale clasei. are rolul de a afi[a \ntr-un mod Clasa test - metoda main() 1. Complex z1;- variabila z1 este de tip Complex. Prin urmare, ea poate re]ine o referin]` (adres`) c`tre un obiect de tip Complex. 2. z1=new Complex(); - se creeaz` un obiect de tip Complex [i referin]a c`tre el este re]inut` de z1. 3. z1.x=3; z1.y=-4.7; - datelor membru x [i y ale obiectului a c`rui referin]` este re]inut` de z1 li se atribuie, respectiv, valorile 3 [i 4.7. 4. z1.afis(); - se afi[eaz` num`rul complex re]inut de obiectul referit de z1. Capitolul 4. Clase – primele noţiuni, exemple 82 Foarte important ! A) La baza program`rii pe obiecte st` no]iunea de clas`. Clasa incorporeaz` at@t date membru, c@t [i metode. A defini o clas` \nseamn` a crea un tip (\n sensul extins). Un obiect rezult` ca instan]iere a unei clase. Obiectul va avea ca tip numele clasei respective. Pentru a putea accesa datele membru [i metodele clasei respective se utilizeaz` variabile de tip referin]` c`tre obiectele clasei respective. B) Odat` definit` clasa, putem crea obiecte de tipul clasei respective. |ntr-o form` simplificat` (mai precis, \n absen]a unui constructor), crearea unui obiect de tipul unei clase se face prin construc]ia de mai jos, unde v este o variabil` referin]` c`tre obiectele clasei respective. Nume_clasa v=new Nume_Clasa() C) Un constructor al unei clase este o metod` special` a clasei respective care are rolul de a aloca \n memorie spa]iul necesar obiectului dar [i de a ini]ializa datele membru ale acestuia. Orice clas` are un constructor implicit (adic` o metod` pe care nu a scris-o cel care a creat clasa). D) Operatorul new are dublu rol: - apeleaz` contructorul clasei respective; - returneaz` referin]a (adresa) la care a fost creat obiectul respectiv. Exemplu: Complex z=new Complex(); - z re]ine o referin]` c`tre obiectul creat prin new. z 1 x y E) Accesul la variabilele interne ale obiectului se realizeaz` prin numele obiectului, urmat de operatorul „.‟ [i numele variabilei. |n exemplu, Z va re]ine num`rul x+2i, iar aceste valori vor fi afi[ate, z1.x=1; z1.y=2; System.out.println(z1.x); System.out.println(z2.y); F) O clas` poate con]ine una sau mai multe metode. Apelul unei metode de acest tip se face prin numele variabilei care re]ine referin]a c`tre obiect, urmat de „.‟ [i de numele metodei. Exemplu: z1.afis(); G) Datele membru ale unei clase sunt ini]ializate implicit cu valoarea 0, dac` sunt de un tip numeric, sau caracterul de cod 0, dac` sunt de tip char, sau cu null dac` sunt de tip referin]`. 83 Bazele programării în Java 4.2. Constructori A[a cum am ar`tat, este de a aloca spa]iu \n de operatorul new. Acesta obiect, referin]` care este obiect. orice clas` are un constructor implicit. Rolul lui memorie pentru obiect. Constructorul este apelat din urm` are [i rolul de a returna referin]a c`tre memorat` de o variabil` de tip referin]` c`tre Unei clase i se pot crea proprii constructori, a[a cum rezult` din exemplul urm`tor, unde clasei prezentate \n paragraful precedent i s-au ad`ugat doi constructori: class Complex { // date membru double x,y; // Constructor 1 Complex (double x1) { x=x1; } // Constructor 2 Complex (double x1, double y1) { x=x1; y=y1;} // metoda void afis() { System.out.println(x+" "+y);} } public class test { public static void main(String[] args) { Complex z1 = new Complex (2,3),z2 =new Complex (1); z1.afis(); z2.afis(); } } Primul constructor are un singur parametru [i se folose[te pentru declara]ii de numere complexe care au partea imaginar` 0. Al doilea constructor se utilizeaz` pentru a declara numere complexe cu parte real` [i parte imaginar`. |n ambele cazuri nu mai este nevoie ca datele membru s` fie ini]ializate. De re]inut: A) Un constructor nu are tip; B) Un constructor are \ntotdeauna numele clasei c`reia \i apar]ine; C) Dac` unei clase i se ata[eaz` un constructor, altul dec@t cel implicit, atunci nu se mai poate instan]ia un obiect prin utilizarea constructorului implicit. De exemplu, pentru clasa definit` \n acest paragraf o instruc]iune de genul Complex z=new Complex() d` eroare de sintax`. Capitolul 4. Clase – primele noţiuni, exemple 84 D) Unei clase i se pot ata[a mai mul]i constructori, dup` cum a]i v`zut [i \n exemplu. Ei trebuie s` difere prin num`rul parametrilor [i /sau tipul parametrilor, cu alte cuvinte, ca [i metodele, acestia sunt supra\nc`rca]i. E) Constructorul implicit este apelat \n mod transparent (f`r` a scrie o secven]` special`) de c`tre constructorul propriu. 4.3. Date membru statice şi metode statice At@t datele membru c@t [i metodele unei clase pot fi statice. Aceasta \nseamn` c` datele [i metodele declarate statice pot fi apelate, a[a cum suntem deja obi[nui]i, pornind de la un obiect al clasei respective, dar [i pornind de la numele clasei, a[a cum observa]i \n exemplul urm`tor. Clasa Matematica con]ine o dat` membru ini]ializat` (Pi). De asemenea, ea mai con]ine dou` metode: Patrat() [i Cub() prin care se calculeaz` x2 [i x3. |n exemplu se calculeaz` [i afi[eaz` aria unui cerc \n dou` feluri: apel@nd data membru [i metoda pornind de la numele clasei (Matematica); apel@nd data membru [i metoda pornind de la numele unui obiect al clasei Matematica. class Matematica { static double Pi=3.1415; static double Patrat (double x) { return x*x; } static double Cub (double x) { return x*x*x; } } public class Clasa1 { public static void main(String[] args) { int Raza=3; double Aria=Matematica.Pi*Matematica.Patrat(Raza); System.out.println(Aria); //altfel Matematica ob=new Matematica(); Aria=ob.Pi*ob.Patrat(Raza); System.out.println(Aria); } } Foarte important ! A) Datele membru statice [i metodele statice nu sunt memorate de fiecare obiect al clasei respective. Ele sunt memorate o singur` dat`, \n cadrul clasei respective. 85 Bazele programării în Java B) Sunt clase care au date membru [i/sau metode statice [i nestatice. O clas` indispensabil`, este clasa Math, care este prezentat` \n aceast` carte. Ea con]ine o mul]ime de metode “matematice” care se utilizeaz` mult \n orice limbaj de programare. Clasa Matematica, din exemplu, este construit` pe acelea[i principii ca [i clasa Math. 4.4. Cuvântul cheie this |n interiorul claselor se poate utiliza cuv@ntul cheie this. Semnifica]ia sa este: referin]` c`tre obiectul curent. Iat` una dintre aplica]iile sale: Aplica]ie. Dac` o metod` (sau un constructor) are o variabil` cu un anumit nume, de exemplu x, [i dac`, clasa are o dat` membru cu acela[i nume, pentru exemplul nostru tot x, atunci pentru a nu se crea confuzie, data membru va fi adresat` prin this.x, iar variabila din metod` (sau constructor) prin x. Exemplu: pentru clasa Complex constructori ar putea fi scri[i [i a[a: din paragraful precedent, cei doi Complex (double x) { this.x=x; } Complex (double x, double y) { this.x=x; this.y=y;} Alte aplica]ii ale cuv@ntului cheie this vor fi prezentate la momentul potrivit. 4.5. Referinţe către obiecte Metodele pot avea parametri de tip referin]` la obiecte [i pot returna referin]e c`tre obiecte. Evident, referin]ele sunt transmise prin valoare. Dar, pornind de la ele, se poate accesa obiectul ca [i c@nd ar fi transmis prin referin]`. Exemplu: ad`ug`m clasei Complex metoda Complex adun(Complex z); Metoda returneaz` o referin]` c`tre un obiect de tip Complex care re]ine num`rul complex rezultat ca sum` \ntre num`rul re]inut de obiectul curent [i num`rul complex transmis ca parametru. class Complex { double x,y; Complex (double x) { this.x=x; } Complex (double x, double y) { this.x=x; this.y=y;} Capitolul 4. Clase – primele noţiuni, exemple void afis() { System.out.println(x+" 86 "+y);} Complex adun(Complex z) { return new Complex (x+z.x,y+z.y);} } public class test { public static void main(String[] args) { Complex z1 = new Complex (2,3); Complex z2 =new Complex(3,4); Complex z=z1.adun(z2); z.afis();} } Programul afi[eaz` suma numerelor complexe re]inute z1 [i z2 adic` num`rul complex z=5+7i, afi[at ca: 5 7. Observa]i faptul c` variabila care re]ine referin]a c`tre obiectul sum` a fost ini]ializat` cu ajutorul metodei adun() a obiectului z1. Clasele pot con]ine variabile de tip referin]` la propriile obiecte (sau la obiectele altei clase). Exemplu (lista liniar` simplu \nl`n]uit`): pornind de la aceast` observa]ie, construim o list` liniar` simplu \nl`n]uit`. Privi]i programul urm`tor care creeaz` [i afi[eaz` o list` liniar` simplu \nl`n]uit`: class Nod { int info; Nod adr_urm; } public class Lista { static Nod v=null; // nu este obligatotrie ini]ilizarea static void adaug(int nr) { Nod c=new Nod(); c.info=nr; c.adr_urm=v; v=c;} static void afis() { Nod c=v; while (c!=null) { System.out.println(c.info); c=c.adr_urm;} } public static void main(String[] args) { for (int i=1;i<=9;i++) adaug(i); afis(); } } Un nod re]ine o informa]ie oarecare, s-o numim info [i s` presupunem c` este de tip int [i o referin]` c`tre nodul urm`tor (adr_urm). Evident, referin]a este c`tre obiecte ale acelea[i clase. Clasa respectiv` am numit-o Nod. 87 Bazele programării în Java Clasa care construie[te lista (Lista) con]ine o dat` membru de tip static de tip referin]` c`tre un obiect al clasei Nod. De asemenea, clasa con]ine [i dou` metode adaug() [i afis(). Metoda adaug() are rolul de a ad`uga un nod listei liniare. Ea prime[te ca argument num`rul care trebuie re]inut de info. Observa]i cum s-a procedat: s-a creat un nou obiect al clasei Nod, iar referin]a c`tre el este re]inut` de c. Data membru a acestui obiect, info, este ini]ializat` cu valoarea primit` ca parametru de metod`, iar adr_urm cu referin]a c`tre nodul anterior, re]inut` de v. |n final, v re]ine referin]a c`tre ultimul nod creat. |n acest fel, lista va re]ine nodurile \n ordinea invers` cre`rii lor. Am preferat acest algoritm pentru simplitatea lui. Metoda afis() listeaz` valorile re]inute de data membru info a fiec`rui nod. 4.6. Masive de obiecte |ntrebarea este: se pot crea masive care re]in obiecte? De exemplu, putem s` cre`m un vector care re]ine obiecte de tipul Complex? R`spunsul este afirmativ! Elementele unui masiv pot re]ine referin]e c`tre obiecte. Exemplu: \n programul urm`tor se creeaz` [i se afi[eaz` un vector cu componente de tip Complex. class Complex { double x,y; Complex (double x) { this.x=x; } Complex (double x, double y) { this.x=x; this.y=y;} void afis() { System.out.println(x+" "+y);} Complex adun(Complex z) { return new Complex (x+z.x,y+z.y);} } public class test { public static void main(String[] args) { Complex[] V=new Complex[3]; for (int i=0;i<3;i++) V[i]=new Complex(i+1,i+2); for (int i=0;i<3;i++) V[i].afis(); } } Pentru a \n]elege modul \n care a fost construit vectorul de obiecte rezultate ca instan]e ale clasei Complex, analiza]i figura urm`toare: Capitolul 4. Clase – primele noţiuni, exemple 88 V V[0] 1 2 x y afis() 2 3 x y V[1] afis() V[2] 3 4 x y afis() Alte exemple: 1) |n secven]a urm`toare, V1 re]ine o referin]` c`tre un vector cu 10 componente care pot re]ine referin]e c`tre obiecte ale clasei Complex. Se instan]iaz` un obiect al clasei Complex [i referin]a sa este atribuit` lui V1[2]. Ultimele 3 instruc]iuni au rolul de a proba cele prezentate. Complex[] V1 =new Complex[10]; V1[2]=new Complex(10,11); V1[2].afis(); 2) |n secven]a urm`toare, V1 re]ine o referin]` c`tre o matrice cu 8 linii [i 5 coloane. Fiecare component` a matricei poate re]ine o referin]` c`tre un obiect al clasei Complex. Se instan]iaz` un obiect al clasei Complex [i referin]a sa este atribuit` lui V1[2][3]. Complex[][] V1 =new Complex[8][5]; V1[2][3]=new Complex(10,11); V1[2][3].afis(); 3) V1 re]ine o referin]` c`tre o matrice cu 5 linii [i un num`r neprecizat de coloane. Un element al matricei va re]ine o referin]` c`tre un obiect al clasei Complex. Linia de indice 3, va avea 6 elemente. Elementul aflat \n linia de indice 3 [i coloana de indice 4 va re]ine o referin]` c`tre un obiect al clasei Complex. Apoi, se probeaz`... Complex[][] V1=new Complex[5][]; V1[3]=new Complex[6]; V1[3][4]=new Complex(100,200); V1[3][4].afis(); 4.7. Aplicaţii ale noţiunilor prezentate Este momentul s` \nv`]`m s` cre`m clase [i apoi s` le utiliz`m.. |nainte de a prezenta aplica]iile preciz`m c`, dac` lucr`m \n folder-ul bin, a[a cum am lucrat p@n` acum, putem compila o clas` oarecare f`r` ca ea s` con]in` metoda main(). Fi[ierul ob]inut (are extensia .class) se va g`si \n bin. (dac` cel cu extensia .java este tot acolo). Orice alt` clas` care con]ine 89 Bazele programării în Java main() din bin, poate folosi clasa compilat`, f`r` a o mai declara \ntr-un fel. De altfel, aceast` problem` va fi tratat` pe larg \n acest capitol. 4.7.1. Lucrul cu numere raţionale S` se creeze o clas` cu ajutorul c`reia s` se poat` lucra u[or cu numere ra]ionale. Un num`r ra]ional q este de forma m/n cu m [i n numere \ntregi [i n diferit de 0. Clasa va avea dou` date membru, m [i n, ambele tip int. Constructorul clasei este Rational (int m, int n). Obiectul este creat numai dac` n0. Datorit` faptului c` un num`r ra]ional poate fi re]inut \n mai multe feluri (de exemplu 2/3=4/6=8/12=) se va re]ine num`rul simplificat (pentru exemplul dat, m=2 [i n=3, chiar dac` introducem 8 [i 12). Pentru a putea realiza simplificarea frac]iei, m [i n se \mpart la cel mai mare divizor comun al lor. Clasa va dispune de o metod`, static int cmmdc(int m, int n), apelat` de constructor, prin care se calculeaz` cel mai mare divizor comun al valorilor re]inute de datele membru m [i n. Metoda Rational add(Rational r) creeaz` un obiect al clasei Rational care este rezultatul adun`rii dintre obiectul curent [i obiectul a c`rui referin]` a fost primit` ca parametru [i returneaz` referin]a c`tre el. Faptul c` a fost apelat constructorul cu datele membru ale obiectului sum`, are ca efect faptul c` obiectul care re]ine suma este deja simplificat (m [i n au fost \mp`r]ite la cmmdc al lor). Metoda Rational sub(Rational r) creeaz` un obiect al clasei Rational care este rezultatul sc`deriii dintre obiectul curent [i obiectul a c`rui referin]` a fost primit` ca parametru [i returneaz` referin]a c`tre el. Metoda Rational mul(Rational r) creeaz` un obiect al clasei Rational care este rezultatul \nmul]irii dintre obiectul curent [i obiectul a c`rui referin]` a fost primit` ca parametru [i returneaz` referin]a c`tre el. Metoda Rational div(Rational r) creeaz` un obiect al clasei Rational care este rezultatul \mp`r]irii dintre obiectul curent [i obiectul a c`rui referin]` a fost primit` ca parametru [i returneaz` referin]a c`tre el. Metoda boolean maiMare (Ratioanal r) compar` obiectul curent cu obiectul a c`rui referin]` a fost primit` ca parametru [i returneaz` true dac` obiectul curent este strict mai mare dec@t cel a c`rui referin]` a fost transmis` ca parametru [i false \n caz contrar. Capitolul 4. Clase – primele noţiuni, exemple 90 Metoda boolean maiMic (Ratioanal r) compar` obiectul curent cu obiectul a c`rui referin]` a fost primit` ca parametru [i returneaz` true dac` obiectul curent este strict mai mic dec@t cel a c`rui referin]` a fost transmis` ca parametru [i false \n caz contrar. Metoda boolean egal (Ratioanal r) compar` obiectul curent cu obiectul a c`rui referin]` a fost primit` ca parametru [i returneaz` true dac` obiectul curent este egal cu cel a c`rui referin]` a fost transmis` ca parametru [i false \n caz contrar. Mai jos pute]i observa modul \n care arat` clasa Rational: class Rational { int m,n; static int cmmdc(int m, int n) { if (n!=0) return cmmdc(n, m%n); else return m;} Rational (int m, int n) { if (n!=0) { int d=cmmdc(m,n); this.m=m/d; this.n=n/d;} else System.out.println("Numitorul este nul");} Rational add(Rational r) { return new Rational (m*r.n+r.m*n, n*r.n); } Rational sub(Rational r) { return new Rational (m*r.n-r.m*n, n*r.n); } Rational mul(Rational r) { return new Rational (m*r.m,n*r.n); } Rational div(Rational r) { if (r.m!=0) return new Rational (m*r.n,n*r.m); else return new Rational (0,1);} boolean maiMare(Rational r) { return (double) m/n > (double)r.m/r.n; } boolean maiMic(Rational r) { return (double) m/n < (double)r.m/r.n; } boolean egal(Rational r) { return (double) m/n == (double)r.m/r.n; } } |n continuare, ne propunem s` rezolv`m c@teva aplica]ii \n care intervin numere ra]ionale: 1. Se citesc dou` numere ra]ionale q1 [i q2 (0). Se cere s` se afi[eze q1+q2, q1-q2, q1*q2, q1/q2. Rezultatele vor fi tot dou` numere ra]ionale. Rezolvare. Varialbila q3 este de tip referin]` c`tre un obiect al clasei Rational. Dup` fiecare opera]ie, ea va re]ine referin]a c`tre obiectul rezultat \n urma opera]iei. 91 Bazele programării în Java class I { public static void main(String[] args) { int m=Integer.parseInt(cin.Token()); int n=Integer.parseInt(cin.Token()); Rational q1=new Rational (m,n); m=Integer.parseInt(cin.Token()); n=Integer.parseInt(cin.Token()); Rational q2=new Rational (m,n); Rational q3=q1.add(q2); System.out.println("Suma="+q3.m+"/"+q3.n ); q3=q1.sub(q2); System.out.println("Diferenta="+q3.m+"/"+q3.n ); q3=q1.mul(q2); System.out.println("Produsul="+q3.m+"/"+q3.n ); q3=q1.div(q2); System.out.println("Catul="+q3.m+"/"+q3.n ); } } 2. Se citesc k numere ra]ionale. Se cere s` se afi[eze suma lor sub form` de num`r ra]ional. Rezolvare. Obiectul s, va re]ine ini]ial o referin]` c`tre un num`r ra]ional nul (m=0, n=1). Se citesc, pe r@nd, cele k numere ra]ionale. Pentru fiecare num`r ra]ional citit, se construie[te obiectul suma \ntre s [i obiectul care re]ine num`rul ra]ional, iar referin]a c`tre el este atribuit` lui s. |n final se afi[eaz` datele mebru ale obiectului s. class I { public static void main(String[] args) { System.out.print("k="); int k=Integer.parseInt(cin.Token()); Rational s=new Rational(0,1); for (int i=0;i<k;i++) { System.out.print("m="); int m=Integer.parseInt(cin.Token()); System.out.print("n="); int n=Integer.parseInt(cin.Token()); Rational q=new Rational (m,n); s=s.add(q); } System.out.println("Suma="+s.m+"/"+s.n ); } } 3. Se cite[te un vector cu k componente numere ra]ionale (obiecte ale clasei Rational). Se cere s` se afi[eze vectorul sortat cresc`tor Rezolvare. Dup` citirea vectorului vom utiliza metoda de sortare interschimbare. Pentru comparare se utilizeaz` metoda maiMare(). prin Capitolul 4. Clase – primele noţiuni, exemple 92 class I { public static void main(String[] args) { System.out.print("k="); int k=Integer.parseInt(cin.Token()); Rational [] V=new Rational [k]; for (int i=0;i<k;i++) { System.out.print("V["+i+"].m="); int m=Integer.parseInt(cin.Token()); System.out.print("V["+i+"].n="); int n=Integer.parseInt(cin.Token()); V[i]=new Rational(m,n); } boolean gasit; Rational man; do { gasit=false; for (int i=0;i<k-1;i++ ) if (V[i].maiMare(V[i+1])) { man=V[i]; V[i]=V[i+1]; V[i+1]=man; gasit=true; } } while (gasit); for (int i=0;i<k;i++) System.out.println("V["+i+"].m="+V[i].m+" V["+i+"].n="+V[i].n); } } 4.7.2. Lucrul cu mulţimi de numere naturale S` se creeze o clas` numit` Multime, care s` ne faciliteze lucrul cu mul]imi de numere naturale. Numerele naturale care pot fi elemente ale mul]imilor sunt din intervalul [0,999], adic` cel mult 1000 de numere. De exemplu, o astfel de mul]ime ar fi {1,3,5}. O mul]ime se re]ine prin vectorul caracteristic. Dac` un num`r apar]ine mul]imii, componenta respectiv` va re]ine 1, altfel componenta va re]ine 0. De exemplu, pentru mul]imea dat` ca exemplu, vectorul caracteristic va fi: 0 1 0 1 0 1 0 0 0 1 2 3 4 5 6 999 |n continuare, prezent`m componentele care alc`tuiesc clasa respectiv`: caract – referin]` c`tre un vectorul caracteristic. int card() – metod` care returneaz` num`rul de elemente al mul]imii (cardinalul). caracteristic. Practic, num`r` componentele nenule din vectorul 93 Bazele programării în Java boolean Multime reun(int k) – metod` care returneaz` o referin]` la mul]imea ap(int k) – metod` care testeaz` apartenen]a lui k la mul]ime. Practic, se verific` dac` caract[k] re]ine 1. |n caz de apartenen]`, metoda returneaz` true, altfel returneaz` false. ob]inut` din reuniunea mul]imii asociate obiectului curent cu elementul k. Multime reun(Multime T) – metod` care returneaz` o referin]` la mul]imea ob]inut` din reuniunea mul]imii asociate obiectului curent cu mul]imea asociat` obiectului a c`rui referin]` este transmis` ca parametru. Dup` cum observa]i, avem de fapt, dou` metode cu acela[i nume (am folosit supra\nc`rcarea metodelor). Multime inters(Multime T) – metod` care returneaz` o referin]` la mul]imea ob]inut` din intersec]ia mul]imii asociate obiectului curent cu mul]imea asociat` obiectului a c`rui referin]` este transmis` ca parametru. Multime Multime boolean inclus(Multime T) – metod` care returneaz` dif(Multime T) – metod` care returneaz` o referin]` la mul]imea ob]inut` din diferen]a \ntre mul]imea asociat` obiectului curent [i mul]imea asociat` obiectului a c`rui referin]` este transmis` ca parametru. dif(Multime T) – metod` care returneaz` o referin]` la mul]imea ob]inut` din diferen]a dintre mul]imea asociat` obiectului curent [i mul]imea alc`tuit` dintr-un singur element, adic` elementul k transmis ca parametru. true dac` mu]imea asociat` obiectului curent este inclus` \n mul]imea a c`rei referin]` a fost transmis` ca parametru [i false \n caz contrar. Analiza]i clasa Multime: class Multime { byte[] caract=new byte[1000]; int card() { int s=0; for (int i=0;i<1000;i++) if (caract[i]==1) s++; return s;} boolean ap(int k) { if (caract[k]==1) return true; else return false;} Multime reun (int k) { caract[k]=1; return this;} Capitolul 4. Clase – primele noţiuni, exemple 94 Multime reun (Multime T) { Multime man=new Multime(); for (int i=0;i<1000;i++) if (caract[i]==1 || T.caract[i]==1) return man; } man.caract[i]=1; Multime inters (Multime T) { Multime man=new Multime(); for (int i=0;i<1000;i++) if (caract[i]==1 && T.caract[i]==1) return man; } man.caract[i]=1; Multime dif (Multime T) { Multime man=new Multime(); for (int i=0;i<1000;i++) if (caract[i]==1 && T.caract[i]==0) return man; } man.caract[i]=1; Multime dif (int k) { caract[k]=0; return this; } boolean inclus(Multime T) { boolean inclus=true; for (int i=0;i<1000;i++) if (caract[i]==1 && T.caract[i]==0) return inclus; } } inclus=false; Exerci]ii de utilizare a clasei Multimi: 1. Se citesc n numere naturale mai mici dec@t 1000. Se cere s` se afi[eze num`rul numerelor distincte [i numerele propriu-zise. De exemplu, dac` n=4 [i numerele sunt 5, 6, 5, 6 se va afi[a 2 [i 5, 6. Rezolvare. Numerele citite sunt ad`ugate (reunite) la o mul]ime ini]ial vide. Evident, dac` un num`r apare de mai multe ori, el se va g`si \n mul]ime o singur` dat`. Num`rul de numere distincte va fi dat de num`rul de elemente al mul]imii (cardinalul ei), iar numerele distincte sunt cele care se reg`sesc \n mul]ime. class I { public static void main(String[] args) { Multime A= new Multime(); System.out.print("n="); int n=Integer.parseInt(cin.Token()); for (int i=0;i<n;i++) A=A.reun(Integer.parseInt(cin.Token())); System.out.println("Numere distincte "+A.card()); for (int i=0;i<1000;i++) if (A.ap(i)) System.out.println(i); } } 95 Bazele programării în Java 2. Se citesc dou` mul]imi de numere naturale A [i B. Se cere s` se afi[eze dac` cele dou` mul]imi sunt egale sau nu. Rezolvare. O metod` de verificare a egalit`]ii a dou` mul]imi, A [i B, este de a verifica dac` AB [i BA. Desigur, s-ar putea proceda si altfel, prin a verifica dac` cei doi vectori caracteristici sunt identici. class I { public static void main(String[] args) { Multime A= new Multime(); System.out.print("n="); int n=Integer.parseInt(cin.Token()); for (int i=0;i<n;i++) A=A.reun(Integer.parseInt(cin.Token())); Multime B=new Multime(); System.out.print("m="); int m=Integer.parseInt(cin.Token()); for (int i=0;i<m;i++) B=B.reun(Integer.parseInt(cin.Token())); if (A.inclus(B) && B.inclus(A) ) System.out.println("Egale"); else System.out.println("Diferite"); } } 3. Se citesc dou` mul]imi de numere naturale A [i B. Se cere s` se afi[eze dac` cele dou` mul]imi sunt disjuncte (nu au elemente comune) sau nu. Rezolvare. Dou` mul]imi sunt disjuncte dac` intersec]ia lor este vid`. Programul este asem`n`tor programului precedent, dar secven]a prin care se testeaz` dac` mul]imile sunt disjuncte este cea de mai jos. if (A.inters(B).card()==0) System.out.println("Disjucte"); else System.out.println("Nedisj"); 4. Se citesc n mul]imi de numere naturale mai mici dec@t 1000. S` se memoreze mul]imile \ntr-un vector de mul]imi [i s` se calculeze [i afi[eze mul]imea care rezult` din reuniunea celor n mul]imi. Rezolvare. Se creeaz` un vector de mul]imi. class I { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Multime [] V= new Multime[n]; for (int i=0;i<n;i++) { V[i]=new Multime(); System.out.print("Multime["+i+"] "+ "nr elem="); int m=Integer.parseInt(cin.Token()); for (int j=0;j<m;j++) V[i]=V[i].reun(Integer.parseInt(cin.Token())); } Multime R= new Multime(); Capitolul 4. Clase – primele noţiuni, exemple 96 for (int i=0;i<n;i++) R=R.reun(V[i]); for (int i=0;i<1000;i++) if (R.ap(i))System.out.print (i+" ") ; } } 4.8. Garbage Collector Modul \n care se aloc` obiectele a fost prezentat \n acest capitol. Pe parcursul rul`rii unui program se pot aloca multe obiecte, iar altele devin inutile, adic` nu mai exist` referin]` c`tre ele. Dac` num`rul obiectelor alocate este foarte mare, este posibil ca programul s` nu mai dispun` de suficient` memorie [i, prin urmare, executarea sa s` nu mai poat` continua. Pentru a rezolva aceast` problem`, programele java con]in o secven]` (fir de executare), numit` Garbage Collector, care intervine automat (f`r` ca programul nostru s` con]in` instruc]iuni scrise special \n acest scop) si elibereaz` memoria ocupat` de obiectele nereferite. Aceasta poate duce, uneori, la o \ncetinire a execut`rii programelor. Momentul \n care intervine Garbage Collector nu este stabilit de programator. 4.9. Cum sunt memorate clasele ? P@n` \n prezent am utilizat, de regul`, programe scrise con]inute \ntrun singur fi[ier text surs`, cu extensia .java. [i care se afl` \n subfolderul bin al folder-ului Java Un astfel de text include toate clasele create de noi. Cunoa[em faptul c` numele unui astfel de fi[ier trebuie s` coincid` cu numele clasei care con]ine metoda main(). Fie programul de mai jos, care se g`se[te exmp.java. Textul con]ine 3 clase A, B, [i exmp. class A { void tip() { System.out.println("clasa A"); } } class B { void tip() { System.out.println("clasa B"); } } public class exmp { public static void main(String[] args) { A x=new A(); x.tip(); B y=new B(); y.tip(); } } \n fi[ierul surs` 97 Bazele programării în Java |n urma compil`rii, fiec`rei clase inclus` \n fi[ierul text corespunde un fi[ier cu numele clasei respective [i extensia class. \i va Compil`m exmp prin javac exmp.java. Analiza]i folder-ul bin. |n urma compil`rii, el va con]ine trei fi[iere A.class, B.class, exmp.class. Pentru rularea programului vom da comanda java exmp. |n acest fel, comunic`m programului java faptul c` fi[ierul care con]ine clasa exmp con]ine [i metoda main(). Aceasta \nseamn` c` se [tie de unde trebuie s` \nceap` rularea (care este clasa care con]ine metoda main()). Mai mult, programul va identifica automat celelalte clase de care are nevoie (A.class [i B.class) \n folder-ul bin. Modul \n care se re]in clasele are drept compilat` o clas`, ea se va g`si \n utilizat` [i de alte programe, care nu respectiv` (pe acest principiu am utilizat V` da]i seama c` o astfel de modalitate de lucru \n care toate fi[ierele text, cu extensie java, toate clasele compilate se g`sesc \n acela[i folder (bin) creeaz` numeroase dezavantaje \n practic`, acolo unde trebuie s` avem programele memorate separat. Din acest motiv, trebuie s` prezent`m modul \n care putem memora clasele separat. consecin]` [i faptul c`, odat` folder-ul bin [i va putea fi con]in \n textul surs` clasa clasa cin). Revenim la programul aflat \n fi[ierul text exmp.java. Obseva]i faptul c` acest program nu utilizeaz` clase definite \n alt` parte. Vom crea un folder, sa-l numim sursa, \n care am mutat fi[ierul exmp.java (a fost [ters din bin).. De asemenea, vom mai crea un folder, numit sursac \n care dorim s` avem programul compilat. Ambele folder-e se g`sesc \n r`d`cin` (c:\). Pentru a compila fi[ierul exmp.java aflat \n folder-ul sursa [i pentru ca rezultatul s` se g`seasc` \n folder-ul sursac, vom apela javac astfel: javac –d c:\sursac c:\sursa\exmp.java –d c:\sursac – specific` folder-ul \n care se va g`si programul compilat; c:\sursa\exmp.java – fi[ierul care con]ine sursa java, dar aici, cuprinde [i calea c`tre el (este pe c:\, \n folder-ul sursa [i se nume[te exmp.java). Dac` am fi apelat javac prin javac c:\sursa\exmp.java, atunci programul compilat s-ar g`si acolo unde este [i fi[ierul text care con]ine programul surs` (adic` \n folder-ul sursa). Capitolul 4. Clase – primele noţiuni, exemple 98 Pentru a rula programul care se g`se[te compilat \n folder-ul sursac, se apeleaz` java astfel: java –classpath c:\sursac exmp –classpath c:\sursac programul compilat; exmp – numele clasei care con]ine main(). specific` folder-ul unde se g`se[te Nu uita]i, pute]i folosi variabila de sistem CLASSPATH (vezi cap. 1) ! 4.10. Pachete Un pachet este alc`tuit dintr-una sau mai multe clase si eventual, unul sau mai multe subpachete. Perntru moment, vom neglija subpachetele [i vom considera pachetul alc`tuit exclusiv din clase. Ideea de baz`, care a stat la elaborarea unui set de reguli de creare [i exploatare a pachetelor, este de a permite celor ce scriu programe s` utilizeze clasele respective sau numai unele metode con]inute de aceste clase. Acum, ne propunem s` \nv`]`m s` cre`m [i s` utiliz`m pachete. Clasele care alc`tuiesc pachetul respectiv se pot g`si \ntr-unul sau mai multe fi[iere surs`. Vom porni de la un exemplu, \n care avem dou` clase A [i B. Fiecare clas` con]ine c@te o metod`. Pasul 1. Stabilim numele pachetului, |n exemplul nostru, acesta se nume[te primulPachet. Pasul 2. Cre`m un folder care va re]ine fi[ierele compilate. |n exemplu, acesta va fi pe C:\ [i se nume[te Pachete. Pasul 3. Fi[ierele surs` (cu extensia .java) se grupeaz` \ntr-un folder oarecare. |n exemplu acesta se va numi Surse [i se va afla pe c:\. Pentru a preciza c` o anumit` clas` apar]ine unui pachet, prima linie a sursei trebuie s` fie package nume_pachet; Pentru a avea acces la o clas` din afara ei, trebuie ca respectiva clas` s` fie public`. Aceasta \nseamn` c` \naintea cuv@ntului cheie class trebuie s` se g`seasc` modificatorul public. Pentru a avea acces la o anumit` metod` a clasei respective, trebuie ca metoda s` fie public`. |n concluzie [i metodele con]inute \n clasele respective vor fi precedate de modificatorul public. |n concluzie, \n C:\Surse vom avea fi[ierele A.java [i B.java de mai jos: 99 Bazele programării în Java A.java: package primulPachet; public class A { public void tip() { System.out.println(“clasa A”); } } B.java: package primulPachet; public class B { public void tip() { System.out.println(“clasa B"); } } Pasul 4. Compil`m pe r@nd cele dou` clase (-d precizeaz` unde se vor g`si fi[ierele compilate): javac -d c:\pachete c:\surse\a.java javac -d c:\pachete c:\surse\b.java S` observ`m c`, \n folder-ul pachete s-a creat automat un subfolder care are numele pachetului (primulPachet Cu asta pachetul este creat. Urmeaz` s` scriem un program care utilizeaz` clasele pachetului creat. Fie programul de mai jos, a c`rui surs` se g`se[te \n folder-ul C:\Prog. Dorim ca programul compilat s` se reg`seasc` \n acela[i folder. Dup` cum stim, este obligatoriu ca numele fi[ierului s` coincid` cu numele clasei care con]ine main(), dar s` aib` extensia .java. De asemenea, pentru a preciza c` acest program utilizeaz` pachetul numit primulPachet, prima linie a proiectului va con]ine clauza import primulPachet.*;. Iat` programul: import primulPachet.*; public class exmp { public static void main(String[] args) { System.out.println("Utilizarea primului pachet"); A x=new A(); x.tip(); B y=new B(); y.tip();} } Pasul . Compil`m programul, av@nd grij` s` specific`m locul unde g`sesc clasele. |ntruc@t se dore[te ca programul compilat s` se g`seasc` \n acela[i loc cu sursa, parametrul -d lipse[te. javac -classpath c:\pachete C:\prog\exmp.java Pasul . Comand`m executarea programului. Trebuie s` preciz`m folder-ele care con]in clasele: c:\prog (pentru exmp.class) [i c:\pachete (A.class, B.class). C`ile se scriu separate prin ;, f`r` spa]iu \ntre ele. java -classpath c:\prog;c:\pachete exmp Capitolul 4. Clase – primele noţiuni, exemple 100 Important ! 1. Clasele care alc`tuiesc pachetul trebuie s` fie publice. De asemenra, metodele lor, care pot fi apelate de utilizatorii pachetelor trebuie s` fie publice. 2. Fiecare clas` a pachetului trebuie s` se g`seasc` \ntr-un fi[ier text cu extensia .java [i numele clasei respective. Rezult` de aici c` o clas` trebuie s` fie singura din fi[ierul respectiv. S` recapitul`m: am creat un pachet care se nume[te primulPachet. El se g`se[te \n folder-ul Pachete. Am ar`tat faptul c` un pachet poate con]ine, pe l@ng` clase [i unul sau mai multe subpachete. Subpachetele sunt, la r@ndul lor pachete, dar sunt incluse \ntr-un pachet din considerente de ordonare logic` a claselor. Pentru a \n]elege modul \n care se creeaz` [i exploateaz` un subpachet, vom ad`uga pachetului primulPachet un subpachet numit pachetel, care contine o singur` clas`, C, aflat` \n fi[ierul C.java din bin. package primulPachet.pachetel; //numele subpachetului public class C { public void tip() { System.out.println("clasa din structuri.pachetel");} } Compil`m clasa cu: javac -d C:\Pachete C.java Automat, \n folder-ul primulPachet, pe ling` fi[ierele A.class, B.class va ap`rea subfolder-ul pachetel care con]ine fi[ierul C.class. Programul urm`tor, aflat \n fi[ierul Inv.java din bin va utiliza subclasa C din pachetel. import primulPachet.pachetel.*; class Inv { public static void main(String[] args) { C x=new C(); x.tip(); } } Compil`m programul prin: javac -classpath C:\Pachete Inv.java Dup` aceast` comand` \n bin avem fi[ierul Inv.class (a fost necesar s` se cunoasc` locul unde este clasa C. Lansarea \n executare se face cu comanda java -classpath C:\Pachete;C:\j2sdk1.4.2_04\bin Inv. A doua cale din classpath este c`tre folder-ul bin (acolo am pe calculatorul meu instalat mediul Java). Fiecare trece calea pentru locul unde are instalat pe propriul calculator mediul Java. 101 Bazele programării în Java Foarte important ! 1. Prin import primulPachet.pachetel.*; -solicit`m s` avem acces la toate clasele din subpachetul pachetel. Cum acest subpachet nu con]ine dec@t o clas` (C), am putea scrie: import primulPachet.pachetel.C; 2. |n acest caz, nu se poate solicita accesul la clasa subpachetului prin import primulPachet.*;, pentru c` o astfel de solicitare asigur` accesul la toate clasele pachetului primulPachet, nu [i la toate clasele subpachetelor sale. 4.11. Clase interioare |n Java exist` posibilitatea ca o clas` s` includ` una sau mai multe clase. Ca [i datele membru sau metodele unei clase, clasele interne pot fi statice sau nestatice. A) Clase nestatice. Acestea se includ \n structura de clas`. Pentru fi activate, clasa “mam`” va con]ine o referin]` c`tre un obiect al clasei interne. Prin intermediul acestei referin]e se pot accesa datele membru [i metodele clasei interne. Vezi exemplul de mai jos, unde referin]a c`tre obiectul clasei interne este ref. |n acest caz, obiectul clasei “mam`” con]ine o referin]` c`tre obiectul clasei interne. |n exemplu, se apeleaz` metoda M1() a clasei “mama” [i metoda M2() a clasei interne. De asemenea, se afi[eaz` data membru a clasei interne, numit` b. class A { I ref=new I(); int a=1; void M1() { System.out.println("a="+a);} class I { int b=2; void M2() { System.out.println("Metoda din clasa inclusa");} } } public class C { public static void main(String[] args) { A x=new A(); x.M1(); x.ref.M2(); System.out.println(x.ref.b); } } Capitolul 4. Clase – primele noţiuni, exemple 102 B) Clase statice. Mai jos, ave]i un astfel de exemplu. Observa]i modul de apel al metodelor [i datelor membru: class A { int a=1; void M1() { System.out.println("a="+a);} static class I { static int b=2; static void M2() { System.out.println("Metoda din clasa inclusa");} } } public class C { public static void main(String[] args) { A x=new A(); x.M1(); A.I.M2(); System.out.println(A.I.b);} } Observa]ii: 1. Dac` o clas` con]ine o clas` interioar`, atunci dup` compilare se ob]in dou` clase (dou` fi[iere cu extensia .class). Prima cu numele clasei (\n exemplul dat, A.class), a doua cu numele clasei care include o alt` clas`, urmat de caracterul “$” [i de numele clasei incluse (\n exemplu A$I.class). 2. Pentru clasele interioare nestatice, datele membru [i metodele claselor interioare se pot accesa [i f`r` a utiliza acea referin]` c`tre clasa interioar`, ca \n exemplul urm`tor, referitor la programul prezentat la \nceputul acestui paragraf. A x=new A(); A.I y= x.new I(); y.M2(); 3. Dintr-o clas` interioar` se pot accesa datele membru ale clasei care o con]ine. Testa]i! 4.12. O problemă de terminologie Am v`zut c` metodele pot \ntoarce referin]e c`tre obiecte. De asemenea, parametrii metodelor pot fi de tip referin]` c`tre obiecte. Prin abuz de limbaj, pentru a nu complica exprimarea, vom spune, uneori, c` metodele \ntorc obiecte, vom vorbi despre obiectul (obiectele) primite ca parametru de o metod`. |ns`, acestea trebuie \n]elese ca referin]e c`tre obiecte. 103 Bazele programării în Java Probleme propuse Exerci]iile 1. [i 2. se refer` la clasa de mai jos, care se g`se[te deja compilat` \n bin: class a { int a=1; int a() { int a=2; return a;} } 1. Care dintre programele de mai jos este corect din punct de vedere sintactic? a) class ex { public static void main(String[] args) { a a=new a();} } b) class ex { public static void main(String[] args) { a x=new a;} } c) class ex { public static void main(String[] args) { x a=new a();} } d) class ex { public static void main(String[] args) { a x=new ();} } 2. Fiind dat` x, o variabil` care re]ine o referin]` c`tre un obiect al clasei a, care dintre instruc]iunile de mai jos afi[eaz` valoarea 2? a) System.out.println(x.a); b) System.out.println(x.a.a); c) System.out.println(x.a()); d) Nici una dintre instruc]iunile de mai sus nu afi[eaz` valoarea 2. 3. Fiind dat` clasa de mai jos, ce afi[eaz` instruc]iunea aflat` \n main(): A.M(3.5)? class A static static static static } a) 1; { void M(int x) {System.out.println(1);} void M(float x) {System.out.println(2);} void M(double x) {System.out.println(3);} void M(char x) {System.out.println(4);} b) 2; c) 3; d) 4. Capitolul 4. Clase – primele noţiuni, exemple 104 4. Ce afi[eaz` programul urm`tor? class A { int a,b; A(int a, int b) { this.a=a; this.b=b;} A (int x) {b=x;} void Afis() {System.out.print (a+" "+b);} } class ex { public static void A x=new A(3); x.Afis(); } } a) Eroare; main(String[] args) { b) 3 0; c) 0 0; d) 0 3. 5. Crea]i o clas` numit` Lista, care opereaz` cu liste liniare simplu \nl`n]uite. Un element al listei liniare simplu \nl`n]uite este descris de clasa Nod: class Nod { Nod adr_urm; int nr; } Clasa Lista va con]ine: Data membru v - adresa primului nod al listei. |n cazul \n care lista este nul`, v re]ine null. Metoda void adaug (int nr) - adaug` la sf@r[itul listei un nod care va re]ine valoarea numeric` nr, primit` de metod` ca parametru. Metoda void afis() - care afi[eaz` valorile re]inute de noduri. 6. Ad`uga]i clasei Lista o metod` void stergP() care permite [tergerea primului nod introdus. 7. Ad`uga]i clasei Lista o metod` void stergU() care permite [tergerea ultimului nod introdus. 8. Ad`uga]i clasei Lista o metod` void adaugI(int nr) care permite ca la \nceputul listei s` se adauge un nod care s` con]in` valoarea nr, primit` de metod` ca parametru. 9. Scrie]i un program care creeaz` o list` liniar` simplu \nl`n]uit`. Programul va utiliza clasa Lista, creat` anterior. Numerele se citesc de la tastatur` [i se vor g`si \n list` \n ordinea \n care au fost introduse. {irul de numere se consider` \ncheiat atunci c@nd se cite[te num`rul 0 (acesta nu este introdus \n list`). 105 Bazele programării în Java 10. La fel ca la problema 9, numai c` elementele se vor g`si \n list` \n ordinea invers` introducerii lor. 11. Ad`uga]i clasei Lista o metod` void concat(Lista) care s` concateneze lista curent` cu o alt` list`. Scrie]i un program care o testeaz`. 12. Realiza]i o clas` numit` Stiva, care opereaz` cu stive alocate ca liste liniare simplu \nl`n]uite. Un element al listei este descris de clasa Nod: class Nod { Nod adr_prec; int nr; } Clasa Stiva va con]ine urm`toarele: Data membru varf - re]ine adresa ultimului nod introdus \n stiv`. Metoda void push(int nr) - adaug` un nod stivei [i acesta va re]ine valoarea numeric` nr, primit` de metod` ca parametru. Metoda int pop() - extrage un nod din stiv` [i returneaz` valoarea pe care acesta o re]inea. Dac` stiva este vid`, returneaz` -1. 13. Crea]i un folder numit Pac pe c:\. Acest folder va con]ine pachetul citiri, care include clasa cin.java (cea pe care am utilizat-o de at@tea ori pentru citirea datelor). 14. Scrie]i un program care cite[te [i afi[eaz` o variabil` \ntreag`. Programul va utiliza pachetul citiri. 15. Realiza]i un pachet care con]ine clasele Nod [i Stiva, create la exerci]iul anterior. Pachetul se va numi structuri [i se va g`si \n folder-ul Pac, creat \n C:\. 16. Prin utilizarea clasei Stiva, scrie]i un program care cite[te n numere naturale [i le afi[eaz` \n ordinea invers` citirii. 17. Crea]i o clas` numit` Coada, care implementeaz` structura de tip coad`. Fiecare element al cozii va fi de tip Complex (deci va re]ine un num`r \ntreg). . 18. Ad`uga]i pachetului structuri (vezi problema 15) clasa Coada. 19. Scrie]i un program care utilizeaz` clasa Coada din pachetul structuri. 20. Realiza]i un program care creeaz` [i parcurge \n preordine, inordine [i postordine un arbore binar. Fiecare nod al arborelui re]ine un num`r real. Datele se citesc de la tastatur`. 21. Crea]i un pachet care con]ine clasele pe care le-a]i utilizat \n programul precedent. Capitolul 4. Clase – primele noţiuni, exemple 106 Răspunsuri: 1. a) 2. c) 3. c) o constant` real` care nu se termin` cu f, este considerat` automat ca fiind de tipul double. Prin urmare, este apelat` automat metoda cu parametru de tip double. 4. d) Clasa este \nzestrat` cu doi constructori (supra\nc`rca]i). Este apelat constructorul cu un singur parametru. Data membru a este ini]ializat` implicit cu 0. 5. class Lista { Nod v; void adaug(int nr) { // daca lista este vida if (v==null) { v=new Nod(); v.nr=nr; v.adr_urm=null;} else // daca lista este nevida, aceasta este parcursa mai // intai, dupa care se adauga nodul { Nod c=v; while (c.adr_urm!=null) c=c.adr_urm; c.adr_urm=new Nod(); c.adr_urm.nr=nr; c.adr_urm.adr_urm=null;} } } 6. Nu este nevoie ca memoria ocupat` de nodul [ters s` fie eliberat`. De aceasta se ocupa Garbage Collector. void stergP() { if (v!=null) v=v.adr_urm; } 7. La fel ca mai sus, nu este nevoie ca memoria ocupat` de nodul [ters s` fie eliberat`. void stergU() { Nod c=v; while (c.adr_urm.adr_urm!=null) c=c.adr_urm; c.adr_urm=null;} 8. void adaugI(int nr) { Nod c=new Nod(); c.nr=nr; c.adr_urm=v; v=c; } 107 Bazele programării în Java 9. class ex { public static void main(String[] args) { Lista l1=new Lista(); int Numar_citit; do { System.out.print("numar_citit="); Numar_citit=Integer.parseInt(cin.Token()); if (Numar_citit!=0) l1.adaug(Numar_citit); } while (Numar_citit!=0); l1.afis(); } } 10. Identic, numai c`, \n loc de if (Numar_citit!=0) l1.adaug(Numar_citit); va fi if (Numar_citit!=0) l1.adaugI(Numar_citit);. 11. void concat(Lista varf) { Nod c=v; while (c.adr_urm!=null) c=c.adr_urm; c.adr_urm=varf.v; } 12. class Stiva { Nod varf; void push(int nr) { Nod c=new Nod(); c.nr=nr; c.adr_prec=varf; varf=c; } int pop() { if (varf!=null) { int x=varf.nr; varf=varf.adr_prec; return x; } else return -1; } } 13. Cre`m folder-ul Pac. Fi[ierul cin.java se g`se[te \n bin. |l modific`m astfel: - prima linie va con]ine package citiri; - clasa devine public` [i fiecare metod` a ei tot public`. Capitolul 4. Clase – primele noţiuni, exemple 108 package citiri; import java.io.*; import java.util.*; public class cin { ... public static String linie() { ... public static String Token(){ ... } Compil`m fi[ierul: javac -d c:\Pac cin.java. Automat, Pac va avea subfolder-ul citiri, care con]ine cin.class. 14. Programul este cel de mai jos, iar fi[ierul gr.java este \n bin: import citiri.*; class gr { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); System.out.println(n);} } Apoi: javac -classpath c:\Pac gr.java (am precizat unde este pachetul care con]ine cin.class). java -classpath C:\Pac;C:\j2sdk1.4.2_04\bin gr (trebuie precizat locul unde se g`sesc clasele, iar pe calculatorul la care lucrez mediul Java este pe C:\j2sdk1.4.2_04) 15. Cele dou` clase trebuie s` fie publice (inclusiv trebuie s` fie publice metodele push() [i pop(). Pentru aceasta, fiecare clas` trebuie s` se g`seasc` \ntr-un fi[ier cu extensia .java [i care are numele clasei respective. Astfel, \n bin avem: Fi[ierul Nod.java: package structuri; public class Nod { Nod adr_prec; int nr; } Fi[ierul Stiva.java: package structuri; public class Stiva { Nod varf; public void push(int nr) { ... public int pop() { ... } 109 Bazele programării în Java Urmeaz` s` compil`m cele dou` fi[iere: javac -d c:\Pac Nod.java javac -d c:\Pac -classpath c:\Pac Stiva.java (clasa Stiva utilizeaz` clasa Nod [i este necesar s` se [tie folder-ul unde o g`se[te, motiv pentru care avem [i clauza -classpath). Automat, folder-ul Pac va avea ca subfolder, folder-ul structuri. 16. Programul este cel de mai jos, iar fi[ierul Inv.doc este \n bin: import structuri.*; import citiri.*; class Inv { public static void main(String[] args) { Stiva st=new Stiva(); System.out.print("n="); int n=Integer.parseInt(cin.Token()); int nr; for (int i=0;i<n;i++) { System.out.print("nr="); st.push(Integer.parseInt(cin.Token())); } do { nr=st.pop(); if (nr!=-1) System.out.println(nr); }while (nr!=-1); } } Se dau comenzile: javac -classpath c:\Pac Inv.java java -classpath C:\Pac;C:\j2sdk1.4.2_04\bin gr CAPITOLUL 5 Studiul unor clase ale limbajului Java Din cuprins: Clasa Math Clasa String Clasa StringTokenizer Clase înfăşurătoare Lucrul cu numere mari Probleme propuse Capitolul 5. Studiul unor clase ale limbajului Java 111 P@n` \n prezent am \nv`]at s` construim [i s` utiliz`m clasele. Desigur, a fost doar un \nceput, \ntruc@t studiul claselor va continua [i \n capitolul urm`tor. Totu[i, este foarte important s` cunoa[tem [i s` folosim clasele mai importante cu care limbajul Java este \nzestrat. Pachetul java.lang con]ine mai multe clase care alc`tuiesc nucleul aplica]iilor Java. Din acest motiv, pentru utilizarea lor nu mai este necesar` folosirea directivei import. 5.1. Clasa Math Clasa Math face parte din pachetul java.lang [i con]ine mai multe metode statice prin care se calculeaz` valorile mai multor func]ii clasice din matematic` (logaritmice, exponen]iale, trigonometrice, etc). Metoda long abs(long x) double abs(double x) int abs(int x) float abs(float x) int abs(int x) double acos(double x) double asin(double x) double ceil(double x) double floor(double x) double cos(double x) double sin(double x) double tan(double x) double pow(double a, double b) double sqrt(double x) long round(double x) int round (float x) double random() double max(double x, double y) float max(float x, float y) int max(int x, int y) long max(long x, long y) double min(double x, double y) float min(float x, float y) long min(long x, long y) int min(int x, int y) double exp(double x) Ce calculeaz` ? modul din x (|x|) ... ... ... ... arccos(x) arcsin(x) cel mai mic \ntreg mai mare sau egal cu x. cel mai mare \ntreg mai mic sau egal cu x ([x], parte \ntreag` din x) cos(x) sin(x) tg(x) ab radical(x) cel mai apropiat \ntreg de x. ... num`r aleator (\nt@mpl`tor) \n [0,1) max{x,y} ... ... ... min{x,y} ... ... ... ex 112 Bazele programării în Java double log (double x) double E double PI logaritm natural (ln(x)) constanta e constanta Exemple: Math.ceil(2.35) returneaz` 3; Math.ceil(-2.35) returneaz` -2; Math.floor(2.35) returneaz` 2; Math.floor(-2.35) returneaz` -3. Math.round(2.35) returneaz` 2. Math.round(-2.35) returneaz` -2. Math.round(2.55) returneaz` 3. Math.round(-2.55) returneaz` -3. Math.round(-2.5) returneaz` -2. Math.round(2.5) returneaz` 3. Exemplu: programul de mai jos, afi[eaz` o valoare natural` aleatoare \n intervalul [1.101]. Math.random() returneaz` o valoare aleatoare \n intervalul [0,1), Math.random()*100) returneaz` o valoare real` \n intervalul [0,100), Math.ceil(Math.random()*100) returneaz` o valoare \ntreag` \n intervalul [0,100], 1+Math.ceil(Math.random()*100) returneaz` o valoare natural` \n intervalul [1,101]. public static void main(String[] args) { System.out.println(1+Math.ceil(Math.random()*100)); } 5.2. Clasa String 5.2.1. Constructorii şi lungimea unui şir de caractere Un obiect al clasei String re]ine un [ir de caractere. P@n` acum am lucrat cu obiecte ale clasei String, dar acum este momentul ca aceast` clas` s` fie prezentat` \n mod sistematic. Clasa este \nzestrat` cu doi constructori: String(); - ini]ializeaz` un obiect String care re]ine [irul vid. Exemplu: secven]a afi[eaz` “un sir”. String s =new String (); s="Un sir"; System.out.println(s); String (String s); - ini]ializeaz` un obiect String care re]ine un [ir de caractere dat. Exemplu: secven]a afi[eaz` “un sir”. String s =new String ("Un sir"); System.out.println(s); Capitolul 5. Studiul unor clase ale limbajului Java 113 int length() - \ntoarce num`rul de caractere din [ir. Exemplu: secven]a de mai jos afi[eaz` 6. String s =new String ("Un sir"); System.out.println(s.length()); |n Java nu este permis` adresarea unui caracter al [irului prin indice, pentru exemplul precedent, s[k]. |n schimb, avem metoda de mai jos, unde primul caracter al [irului are indicele 0, al doilea are indicele 1, [.a.m.d. char charAt(int i) returneaz` caracterul de pe pozi]ia i. Exemplu: pentru [irul s, din exemplul precedent, instruc]iunea afi[eaz` „n‟. System.out.println(s.charAt(1)); 5.2.2. Compararea şirurilor de caractere {irurile de caractere re]inute de obiectele clasei String pot fi comparate din punct de vedere lexicografic (ordinea din dic]ionar). Pentru aceasta, clasa String con]ine mai multe metode. int compareTo (String s) compar` [irul de caractere re]inut de obiectul curent cu [irul de caractere re]inut s. Metoda returneaz`: o valoare negativ`, dac` [irul re]inut de obiectul curent este situat, \n ordine lexicografic`, \naintea [irului re]inut de obiectul s. 0, dac` [irurile re]inute de cele dou` obiecte coincid. o valoare pozitiv`, dac` [irul re]inut de obiectul curent este situat, \n ordine lexicografic`, dup` [irul re]inut de obiectul s. Exemple: secven]a afi[eaz` -2, 0, 2. String s =new String ("abc"); String s1=new String("cd"); System.out.println(s.compareTo(s1)+ " " +s.compareTo(s)+" "+s1.compareTo(s)); int compareToIgnoreCase(String s) – la fel precum compareTo(), numai c` nu se face diferen]a \ntre literele mari [i cele mici. Exemplu: secven]a de mai jos afi[eaz` 0. String s =new String ("AB"); String s1=new String("ab"); System.out.println(s.compareToIgnoreCase("ab")); equals(String s) – returneaz` true dac` [irurile de caractere re]inute de obiectul curent [i cel transmis ca parametru sunt identice. boolean 114 Bazele programării în Java boolean equalsIgnoreCase(String s) – la fel ca mai sus numai c` nu se face distinc]ie \ntre literele mari [i cele mici. 5.2.3. Subşiruri Vom \n]elege prin sub[ir al un [ir de caractere, mai multe caractere consecutive ale acestuia. De exemplu, “text” are ca sub[ir “ex”. boolean startsWith(String s) – returneaz` true dac` [irul re]inut de s precede [irul re]inut de obiectul curent. boolean endsWith(String s) – returneaz` true dac` [irul re]inut s se afl` la sf@r[itul [irului re]inut de obiectul curent. Exemple pentru startsWidth() [i endsWith(). Secven]a de mai jos afi[eaz` de dou` ori true: String s =new String ("123"); String s1=new String("12"); String s3=new String("23"); System.out.println(s.startsWith(s1)); System.out.println(s.endsWith(s3)); boolean regionMatches(int i1, String s, int i2, int l) compar` dou` sub[iruri de lungime l. Primul sub[ir este al obiectului curent [i \ncepe de pe pozi]ia i1, al doilea sub[ir este al [irului s [i \ncepe pe pozi]ia i2. |n caz de egalitate, metoda returneaz` true, contrar returneaz` false. Exemplu: secven]a de mai jos afi[eaz` [irul 567 coincid: if (s.regionMatches(4, s1, 2, 3)) System.out.println("567 coincid"); String substring (int index) – metoda returneaz` sub[irul [irului curent care este \ntre pozi]ia index [i sf@r[itul [irului. Exemplu: secven]a de mai jos afi[eaz` 456789: String s =new String ("123456789"); System.out.println(s.substring(3)); String substring (int index, int sf ) – metoda returneaz` sub[irul [irului curent care este \ntre pozi]ia index [i sf-1. Exemplu: secven]a de mai jos afi[eaz` 45: String s =new String ("123456789"); System.out.println(s.substring(3,5)); Capitolul 5. Studiul unor clase ale limbajului Java 115 String replace (char c1, char c2) – metoda returneaz` [irul ob]inut dac` se \nlocuiesc \n [irul re]inut de obiectul curent toate apari]iile caracterului c1 cu caracterul c2. Exemplu: secven]a de mai jos afi[eaz` tata: String s =new String ("mama"); System.out.println(s.replace('m','t')); String replaceAll (String s1, String s2) – metoda returneaz` [irul ob]inut dac` se \nlocuiesc \n [irul re]inut de obiectul curent toate apari]iile sub[irului s1 cu sub[irul s2. Exemplu: secven]a de mai jos afi[eaz` *** doi *** doi trei: String s =new String ("unu doi unu doi trei"); System.out.println(s.replaceAll("unu","***" )); String replaceFirst (String s1, String s2) – la fel ca mai sus, doar c` se \nlocuie[te numai prima apari]ie a sub[irului. Exemplu: secven]a de mai jos afi[eaz` *** doi unu doi trei: String s =new String ("unu doi unu doi trei"); System.out.println(s.replaceFirst("unu","***" )); String int indexOf (String s) returneaz` indicele primei apari]ii a sub[irului s \n [irul re]inut de obiectul curent. |n cazul \n care s nu este g`sit ca sub[ir al [irului referit de obiectul curent, metoda returneaz` -1. trim() \ntoarce sub[irul [irului re]inut de obiectul curent, sub[ir ob]inut prin eliminarea spa]iilor (blank-urilor de la \nceput [i de la sf@r[it). Exemplu: secven]a de mai jos afi[eaz` 4: String s1=new String("un exemplu"); String s2=new String("xe"); System.out.println(s1.indexOf(s2)); 5.2.4. Concatenarea şirurilor de caractere A[a cum deja [tim, \n Java [irurile de caractere pot fi concatenate cu ajutorul operatorului +. Exemple: 1. Secven]a urm`toare afi[eaz` Un sir Alt sir: String s =new String ("Un sir" ); String s1 = new String(" Alt sir"); 116 Bazele programării în Java s=s+s1; System.out.println(s); 2. Acela[i lucru este afi[at [i de secven]a de mai jos: String s =new String ("Un sir "+"Alt sir" ); System.out.println(s); Dup` cum observa]i, concatenarea [irurilor nu este comutativ`. Aceasta \nseamn` c` prezint` importan]` ordinea \n care [irurile sunt puse \n expresie. Metoda String concat(String s) returneaz` [irul concatenarea [irului re]inut de obiectul curent cu s. ob]inut prin Exemplu: secven]a urm`toare afi[eaz` Un sir Alt sir: String s =new String ("Un sir "); String s1 =new String ("Alt sir" ); System.out.println(s.concat(s1)); 5.2.5. Parametrii metodei main() Acum suntem \n m`sur` s` analiz`m parametrii metodei main(): public static void main(String[] args). Antetul con]ine un vector cu elemente de tip String vectorului este args. |n exemplu, numele 1. C@te elemente are vectorul? Acest num`r se poate afla u[or, ca la orice vector: args.length. 2. Unde se introduc [irurile de caractere primite ca parametri de c`tre main()? Aceste [iruri se introduc pe linia de comand` a programului Java [i sunt separate prin spa]ii. Exerci]iu: programul de mai jos calculeaz` suma valorilor introduse ca parametri. Evident, mai \nt@i acestea sunt convertite c`tre int. Exemple de utilizare: a) Dac` apelul este b) Dac` apelul este java t 3 4 se va afi[a 7. java t 1 2 3 4 se va afi[a 10. class t { public static void main(String[] args) { int s=0; for (int i=0;i<args.length;i++) s+=Integer.parseInt(args[i]); System.out.println("suma argumentelor este ="+s);} } Capitolul 5. Studiul unor clase ale limbajului Java 117 5.2.6. Aplicaţii 1. S` se citeasc` de la tastatur` un [ir de caractere, apoi s` se afi[eze. Rezolvare. Vom utiliza clasa cin (cea pe care am folosit-o [i p@n` acum). De altfel, clasa cin o vom utiliza pentru toate exerci]iile din acest paragraf. public static void main(String[] args) { String s =new String (); s=cin.linie(); System.out.println(s); } 2. Se citesc dou` [iruri de caractere. S` se listeze indicele fiec`rei apari]ii a primului [ir citit ca sub[ir al celui de-al doilea [ir citit. Iat` cum arat` execu]ia programului: Rezolvare: Ideea este urm`toarea: dup` ce sub[irul a fost identificat, se afi[eaz` pozi]ia de \nceput, apoi se extrage din [ir sub[irul de \nceput ce con]ine inclusiv prima apari]ie a sub[irului, dup` care procedeul se repet` p@n` c@nd sub[irul c`utat nu mai este g`sit. O problem` aparte este dat` de faptul c` trebuie, de fiecare dat`, s` afi[`m pozi]ia de \nceput a sub[irului \n [irul ini]ial [i nu \n [irul r`mas. Din acest motiv, utiliz`m mai multe variabile: poz - pozi]ia de \nceput a sub[irului \n [irul r`mas; ind - suma lungimilor [irurilor extrase. De fiecare dat` se va afi[a ca indice de apari]ie a sub[irului, ind+poz. public static void main(String[] args) { String subsir =new String (cin.linie()); String sir =new String (cin.linie()); int poz=0, ind=0, lsubs=subsir.length(); while (poz!=-1) { poz=sir.indexOf(subsir); if (poz!=-1) { System.out.println(ind+poz); ind+=poz+lsubs; sir=sir.substring(poz+lsubs);} } } 3. Se citesc dou` [iruri de caractere. S` se afi[eze [irul format din cel de-al doilea [ir din care au fost extrase toate apari]iile primului [ir citit. Al`turat observa]i un exemplu de execu]ie: Rezolvare: Se identific` prima apari]ie a sub[irului, apoi, prin extragerea sub[irului, se ob]ine un nou [ir, iar se idendific` prima apari]ie a sub[irului [.a.m.d. {irul astfel ob]inut se afi[eaz` atunci c@nd nu se mai con]ine nici o apari]ie a sub[irului citit. 118 Bazele programării în Java public static void main(String[] args) { String subsir =new String (cin.linie()); String sir =new String (cin.linie()); int poz=0, ind=0, lsubs=subsir.length(); while (poz!=-1) { poz=sir.indexOf(subsir); if (poz!=-1) sir=sir.substring(0,poz)+sir.substring(poz+lsubs); } System.out.println(sir); } 4. Se cite[te un [ir de caractere. {irul con]ine mai multe cuvinte separate de unul sau mai multe blank-uri. Se cere s` se elimine blank-urile de la \nceputul [i sf@r[itul [irului. De asemenea, se cere ca, \n noul [ir, cuvintele s` fie separate obligatoriu printr-un singur blank. Rezolvare. Dup` eliminarea blank-urilor de \nceput [i de sf@r[it sub un for se identific` primele dou` blank-uri consecutive, unde primul blank are indicele i. Se elimin` primul dintre ele, apoi valoarea lui i scade cu 1, pentru ca \n [irul nou format s` se reia c`utarea de la primul blank, cel neeliminat (nu uita]i, la testul urm`tor valoarea lui i cre[te cu 1, pentru c` totul se execut` sub for). public static void main(String[] args) { String sir =new String (cin.linie()); sir=sir.trim(); for (int i=1;i<=sir.length()-2;i++) if (sir.charAt(i)==' ' && sir.charAt(i+1)==' ') { sir=sir.substring(0,i)+sir.substring(i+1); i--; } System.out.println(sir); } 5. Se citesc n cuvinte, c@te unul pe linie. Se cere s` se afi[eze cuvintele \n ordine lexicografic` (ordinea alfabetic`, \nt@lnit` \n dic]ionar). R`spuns. Vom utiliza un vector de obiecte de tip String. |n rest, este o sortare obi[nuit`... public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); String [] V=new String [n]; for (int i=0;i<n;i++) { System.out.print("Cuvantul["+i+"]="); V[i]=cin.linie(); } boolean gasit; String man; Capitolul 5. Studiul unor clase ale limbajului Java 119 do { gasit=false; for (int i=0;i<n-1;i++) if (V[i].compareTo (V[i+1])>0) { man=V[i]; V[i]=V[i+1]; V[i+1]=man; gasit=true; } } while (gasit); for (int i=0;i<n;i++) System.out.println(V[i]); } 5.3. Clasa StringTokenizer Clasa StringTokenizer se g`se[te \n pachetul java.util (vezi import) [i con]ine c@teva metode care permit extragerea unit`]ilor lexicale (token-uri) din care este alc`tuit un [ir de caractere. Implicit, acestea se consider` separate prin caracterele albe ( „ „, „\n‟, „\t‟, „\r‟ „\f‟). Iat` cele mai importante metode: StringTokenizer (String s) – constructor, creeaz` obiectul care trateaz` [irul de caractere referit de s. StringTokenizer (String s, String delim) – constructor, creeaz` obiectul care trateaz` [irul de caractere referit de s., dar token-urile sunt separate de caracterele care alc`tuiesc delim. boolean hasMoreTokens() – returneaz` true con]ine token-uri necitite [i false \n caz contrar. String nextToken() - returneaz` [irul de caractere care alc`tuiesc urm`torul token (cite[te un token). int countTokens(); - returneaz` num`rul de token-uri r`mase necitite dac` [irul mai (cu nextToken()). Exemplu: programul urm`tor cite[te o linie introdus` de la tastatur` (vezi clasa cin) [i afi[eaz` token-urile \nt@lnite. De exemplu dac` linia introdus` de la tastatur` este: mama are 350000 lei, se afi[eaz`: import java.util.*; class t { public static void main(String[] args) { String s=new String (cin.linie()); StringTokenizer t=new StringTokenizer(s); while (t.hasMoreTokens()) System.out.println(t.nextToken()); } } mama are 350000 lei 120 Bazele programării în Java 5.4. Clase înfăşurătoare Pentru fiecare tip primitiv s-a construit c@te o clas` \nf`[ur`toare. Un obiect al clasei \nf`[ur`toare poate re]ine o valoare a tipului primitiv. Al`turat, pute]i observa coresponden]a \ntre numele tipurilor primitive [i numele claselor \nf`[ur`toare. int – Integer short - Short long – Long byte – Byte char – Character float – Float double – Double boolean – Boolean Fiecare clas` \nf`[ur`toare este \nzestrat` cu o metod` constructor. Exemple: int n=4; Integer nr=new Integer(n); Double x=new Double (-12.34); Character c=new Character ('e'); Boolean este=new Boolean(true); Constructorii acestor clase sunt supra\nc`rca]i, \n sensul c` exist` [i constructori care au ca parametru de intrare referin]e c`tre obiecte de tip String. Exemple: Integer nr=new Integer("10"); Double x=new Double ("-12.34"); Boolean este=new Boolean("true"); Fiecare clas` \nf`[ur`toare con]ine o metod` care returneaz` valoarea re]inut` de obiectul instan]iat de ea. Exemple: se extrag valorile re]inute de obiectele create \n primele exemple: int n1=nr.intValue(); double x1=x.doubleValue(); char c1=c.charValue(); boolean este1=este.booleanValue(); a) Fiecare clas` care re]ine o valoare numeric` con]ine c@te o metod` static` (aten]ie la apel!) pentru conversia c`tre un tip primitiv a unui obiect de tip String. Astfel avem: int parseInt(String s); // in Integer Exemplu: int t=Integer.parseInt("10"); b) parseFloat(String S); // in Float Exemplu: float b=Float.parseFloat("-12.34"); c) double parseDouble (String s) // in Double Exemplu: double b=Double.parseDouble("-12.34"); Capitolul 5. Studiul unor clase ale limbajului Java d) 121 parseLong(String s); // in Long Exemplu: long t=Long.parseLong("1000"); e) parseByte(String s) // in Byte Exemplu: byte x=Byte.parseByte("12"); Dac` [irul de caractere nu poate fi convertit c`tre valoarea numeric` de tipul dorit, se genereaz` o excep]ie \n urma c`reia executarea programului se \ntrerupe. Conversia invers`, de la un tip primitiv c`tre un [ir se poate realiza u[or, a[a cum am mai \nt@lnit de multe ori concaten@nd un [ir (eventual vid) cu o valoare numeric`. Exemplu: secven]a urm`toare afi[eaz` [irul 10: int i=10; String s=new String(i+""); System.out.println(s); Clasele \nf`[ur`toare con]in constantele MIN_VALUE [i MAX_VALUE care re]in cea mai mic` [i cea mai mare valoare a tipului respectiv. |n cazul variabilelor de un tip real (float, double) MIN_VALUE are semnifica]ia de cea mai mic` valoare pozitiv` care poate fi re]inut` de tipul respectiv. System.out.println(Integer.MIN_VALUE); System.out.println(Integer.MAX_VALUE); System.out.println(Double.MIN_VALUE); System.out.println(Double.MAX_VALUE); Clasele \nf`[ur`toare ale tipurilor reale (double, float) con]in constanta NaN (Not a Number). Valoarea NaN se ob]ine dac`, \ntr-o expresie de tip real, se \mparte 0 la 0, sau se extrage radical (indice 2) dintr-o valoare negativ`, sau se aplic` logaritmul unui num`r negativ etc. Exemple: 1. Secven]a de mai jos afi[eaz` NaN: double x=0,y=0,z; z=x/y; System.out.println(z); 2. Secven]a de mai jos afi[eaz` NaN: int x=-2; System.out.println(Math.sqrt(x)); 122 Bazele programării în Java Clasele \nf`[ur`toare ale tipurilor reale (double, float) con]in metodele boolean isNaN (double e), respectiv boolean isNaN (float e). Cele dou` metode returneaz` true dac` se ob]ine NaN. Exemple: 1. Secven]a de mai jos afi[eaz`: Ambii operanzi sunt 0: int x=0; double y=0; if (Double.isNaN(x/y)) System.out.println("Ambii operanzi sunt 0"); 2. Secven]a de mai jos afi[eaz`: Radical dintr-un numar negativ: if (Double.isNaN(Math.sqrt(x))) System.out.println("Radical dintr-un numar negativ"); Compar`rile precum cele de mai jos nu au efect. De exemplu, secven]a de mai jos nu afi[eaz` nici un mesaj: if (Math.sqrt(x)==Double.NaN) System.out.println("Radical din numar negativ"); Clasele \nf`[ur`toare ale tipurilor reale (double, float) con]in constantele POSITIVE_INFINITY, NEGATIVE_INFINITY. Constanta POSITIVE_INFINITY se ob]ine dac`, \ntr-o expresie de tip real, se \mparte o valoare pozitiv` la 0, iar constanta NEGATIVE_INFINITY se ob]ine dac`, \ntr-o expresie de tip real, se \mparte la 0 o valoare negativ`. double x=2; System.out.println(x/0); x=-2; System.out.println(x/0); Dac` expresia este de tip \ntreg, atunci se genereaz` o excep]ie (excep]iile vor fi studiate separat), iar programul este \ntrerupt, ca \n secven]a de mai jos. int x=2; System.out.println(x/0); Clasele \nf`[ur`toare ale tipurilor reale (double, float) con]in metoda boolean` boolean isInfinite (double) (sau float) prin care se testeaz` dac` s-a ob]inut una din constantele de mai sus. Exemplu: secven]a de mai jos afi[eaz` Impartire la 0. double x=2; if (Double.isInfinite(x/0)) System.out.println("Impartire la 0"); Capitolul 5. Studiul unor clase ale limbajului Java 123 5.5. Lucrul cu numere mari Prin numere mari vom \n]elege acele valori numerice care dep`[esc limitele de memorare ale tipurilor primitive. Opera]iile cu astfel de numere sunt anevoioase prin faptul c` num`rul trebuie memorat pe cifre (\ntr-un vector). |n Java exist` dou` clase care permit lucrul cu numere mari: clasa BigInteger [i clasa BigDecimal. A) Clasa BigInteger importante metode sunt: lucreaz` cu numere \ntregi mari. Cele mai BigInteger(String s) - constructor. Are rolul de a crea un obiect de tip BigInteger pornind de la un obiect de tip String. Exemplu: BigInteger n2=new BigInteger("-2"); String toString(); - are rolul de a converti num`rul re]inut de obiectul curent c`tre un [ir de caractere. BigInteger add (Biginteger n); - adun` la num`rul re]inut de obiectul curent num`rul re]inut de obiectul transmis ca parametru. BigInteger subtract (Biginteger n); - scade din num`rul re]inut de obiectul curent num`rul re]inut de obiectul transmis ca parametru. BigInteger multiply (Biginteger n); - \nmul]e[te num`rul re]inut de obiectul curent cu num`rul re]inut de obiectul transmis ca parametru. BigInteger divide (Biginteger n); - \mp`r]ire \ntreag` \ntre num`rul re]inut de obiectul curent [i num`rul re]inut de obiectul a c`rui referin]` este re]inut` de n. BigInteger remainder (Biginteger n); - returneaz` un obiect care re]ine restul \mp`r]irii num`rului re]inut de obiectul curent la num`rul obiectului transmis ca parametru. BigInteger pow (BigInteger n); - dac` obiectul curent re]ine m [i obiectul transmis ca parametru valoarea n, atunci metoda returneaz` obiectul care re]ine mn. BigInteger negate(); - dac` obiectul curent re]ine m atunci metoda returneaz` obiectul care re]ine -m. int signum(); - dac` obiectul curent re]ine m se returneaz` obiectul care re]ine sgn(m), adic`: -1 dac` m<0, 0 dac` m=0 sau 1 dac` m>0. 124 Bazele programării în Java int CompareTo(BigInteger n); - dac` obiectul curent re]ine m, iar obiectul referit re]ine n, atunci metoda returneaz` -1 dac` m<n, 0 dac` m=n, 1, dac` m>n. Exemplu: se cere s` se calculeze 21000. Num`rul dep`[e[te cu mult capacitatea de memorare a tipului long. Prin urmare, vom utiliza clasa BigInteger: import java.math.*; class t { public static void main(String[] args) { BigInteger n1=new BigInteger("1"); BigInteger n2=new BigInteger("2"); for (int i=1;i<=1000;i++) n1=n1.multiply(n2); System.out.println(n1.toString());} } B) Clasa BigDecimal - cele mai importante metode sunt: BigDecimal(String s) – constructor. Are rolul de a crea un obiect de tip BigDecimal pornind de la [irul s. BigDecimal(BigInteger val) - constructor, pornind de la un altul de tip BigInteger; BigDecimal(double val) – constructor, creeaz` un obiect pornind de la o valoare de tip double. BigDecimal abs() – returneaz` num`rului re]inut de obiectul curent. String toString() – convertit c`tre String. BigDecimal add(BigDecimal n) - returneaz` obiectul care re]ine suma numerelor re]inute de obiectul curent [i cel transmis ca parametru. Rezultatul va avea num`rul maxim de zecimale pe care le au cei doi operanzi. BigDecimal subtract(BigDecimal n) – returneaz` obiectul care re]ine valoarea rezultat` din sc`derea numerelor re]inute de cei doi operanzi (obiectul curent, desc`zut [i obiectul transmis ca parametru, sc`z`tor). Num`rul de zecimale al rezultatului se ob]ine ca la add. BigDecimal multiply(BigDecimal n) – obiectul care re]ine produsul numerelor re]inute de cei doi operanzi. Num`rul de zecimale al rezultatului este dat suma numerelor de zecimale ale operanzilor. BigDecimal divide(BigDecimal val, int rotunjire) - \mparte cei doi operanzi. Num`rul de zecimale al rezultatului este egal cu num`rul de zecimale al de\mp`r]itului. obiectul creeaz` care un re]ine obiect modulul returneaz` num`rul re]inut de obiectul curent Capitolul 5. Studiul unor clase ale limbajului Java 125 Exemplu: fie obiectele de mai jos: BigDecimal n1=new BigDecimal("1.000"); BigDecimal n2=new BigDecimal("3.000000"); n1=n1.divide(n2,0); -n1 re]ine 0.334 n1=n1.divide(n2,1); -n1 re]ine 0.333 int scale() - returneaz` num`rul zecimalelor ale num`rului re]inut de obiectul curent. BigDecimal setScale(int nrzec) - returneaz` un obiect care memoreaz` num`rul re]inut de obiectul curent cu nrzec zecimale. BigDecimal negate() – returneaz` un obiect care re]ine num`rul memorat de obiectul curent, dar care a fost negativat. int signum() - returneaz` sgn(x) vezi metoda similar` de la BIgInteger; BigDecimal abs() - returneaz` num`rului memorat de obiectul curent. int compareTo(BigDecimal val) – compar` numerele re]inute de cei doi operanzi. Vezi metoda similar` de la BigInteger. obiectul care re]ine modulul Probleme propuse 1. Scrie]i un program care s` citeasc` 0<a<b, numere naturale [i s` afi[eze un num`r aleator \n intervalul [a,b]. 2. Scrie]i un program care cite[te x, num`r real, [i n>0, num`r natural [i calculeaz` P=sin(x)*sin(2x)*...sin(n*x). Se presupune c` x reprezint` o valoare exprimat` \n radiani. 3. Se cite[te de la tastatur` un [ir de caractere. {irul con]ine cel pu]in 10 caractere. Se cere s` se afi[eze numai primele 10 caractere din [ir. 4. Se cite[te de la tastatur` un [ir de caractere. Dac` [irul are mai mult de 4 caractere s` se afi[eze numai primele 4, altfel se va afi[a [irul citit. 5. Scrie]i o clas`, numit` Afis, care con]ine metoda String aNum(int lung, String s) metod` ce are rolul de a \ntoarce sirul re]inut de s, pe lungimea lung). Dac` num`rul de caractere ale [irului este mai mare dec@t lung, se \ntoarce sub[irul format din primele lung caractere ale [irului, altfel se \ntoarce un [ir pe lungimea lung. [ir alc`tuit din caracterele [irului ini]ial la care se adaug` de un num`r corespunz`tor de blank-uri. Exemple pentru lung=5: {irul: citit “Mihai” - se returneaz` “Mihai”. 126 Bazele programării în Java {irul: “tastatura” {irul: “aer” - se returneaz` “tasta”. - se returneaz` “aer ”. O astfel de metod` este util` pentru afisarea unui [ir de caractere pe o anumit` lungime. 6. Scrie]i un program care cite[te n, num`r natural [i n [iruri de caractere. Programul va afi[a pe c@te o linie, primele 5 caractere ale fiec`rui [ir citit. Dac` [irul are mai pu]in de 5 caractere, se va afi[a [irul, urmat de un num`r de blank-uri astfel \nc@t lungimea total` afi[at` s` fie de 5 caractere. 7. Ad`uga]i clasei Afis metoda String num(int lung, int v) care are rolul de a returna [irul de lungime lung, alc`tuit din [irul ob]inut din convertirea \ntregului v \n [ir [i, \n cazul \n care acest [ir are lungimea mai mic` dec@t lung, el va fi precedat de un num`r corespunz`tor de blank-uri. |n situa]ia \n care lungimea [irului ob]inut din conversia num`rului este mai mare dec@t lung, metoda va returna un mesaj de eroare. Exemple pentru lung=3. Num`rul 125 Num`rul 1 Sirul: “3152” - se returneaz` “125”. - se returneaz` “ 1”. - se returneaz` "Numarul nu poate fi afisat"; 8. Scrie]i un program care cite[te n, num`r natural [i n numere naturale. Programul va afi[a, pe c@te o linie, fiecare dintre cele n numere naturale citite. Numerele se vor afi[a pe 5 caractere [i vor fi aliniate la dreapta. Exemplu: n=3, numerele citite sunt: 12234, 45, 4. Se va afi[a: 12234 45 4 |n practic`, [irurile alc`tuite din caractere se afi[eaz` aliniate la st@nga, iar valorile numerice se afi[eaz` aliniate la dreapta. 9. Ad`uga]i clasei Afis metoda String num(int lung, int zec, double v) care returneaz` [irul rezultat din conversia unui num`r real (indiferent de num`rul de zecimale). {irul are lungimea lung, num`rul este afi[at aliniat la dreapta [i va avea zec zecimale. |n ipoteza \n care num`rul nu poate fi afi[at prin utilizarea a lung caractere, se va returna un mesaj de eroare. Num(5,2,23.3456) returneaz` “23.34”; Num(5,2,3.3456) returneaz` “ 3.34”; Num(5,2,-9) returneaz` “-9.00”; Num(5,2,123) returneaz` “Numarul nu poate fi afisat”. Capitolul 5. Studiul unor clase ale limbajului Java 127 10. Scrie]i un program care cite[te n, num`r natural [i n numere reale. Programul va afi[a pe c@te o linie fiecare num`r citit. Numerele se vor afi[a pe 8 caractere, vor fi aliniate la dreapta [i vor avea obligatoriu dou` zecimale (indiferent de num`rul de zecimale pe care \l au). 11. S` se creeze o clas` numit` Elev. Un obiect al clasei respective con]ine numele elevului, nota la matematic`, nota la informatic` [i nota la englez`. Clasa va con]ine un constructor care cite[te de la tastatur` valorile respective [i o medod` void afisez(), care afi[eaz` toate datele pe o linie astfel: nume elev pe 20 de caractere, aliniat la st@nga; nota la matematic` pe 5 caractere, aliniat` la dreapta; nota la informatic` pe 5 caractere, aliniat` la dreapta; nota la englez` pe 5 caractere, aliniat` la dreapta; media general`, pe 8 caractere, cu dou` zecimale, aliniat` la dreapta. 12. Scrie]i un program care, prin utilizarea clasei Elev, cite[te numele [i notele pentru n elevi [i le afi[eaz` aliniat, \mpreun` cu media general`. 13. Scrie]i un program care cite[te un [ir introdus de la tastatur`. Cuvintele din [ir sunt separate printr-unul sau mai multe spa]ii. Se cere s` se afi[eze [irul ob]inut din cuvintele din [irul ini]ial, dar care, de aceast` dat`, sunt separate printr-un singur spa]iu. Exemplu: se cite[te: mama merge la plimbare se afi[eaz`: mama merge la plimbare 14. Calcula]i n! pentru 1n1000. 15. Rezolva]i ecua]ia de gradul 1 ax+b=0, unde a si b sunt numere reale atât de mari c` nu pot fi re]inute de variabile de tip double. 16. Scrie]i un program care calculeaz` ez, cu k zecimale exacte (k se cite[te de la tastatur`). Calculul se va face prin utilizarea formulelor de mai jos: ex 1 x x 2 x3 xn ... Rn ( x) 2! 3! n! Rn ( x ) e x x n 1 ( n 1)! Dac`, de exemplu k=30, atunci se va efectua calculul pentru n determinat astfel \nc@t: Rn ( x ) 1 10 30 128 Bazele programării în Java 17. Afla]i prin metoda \njum`t`]irii intervalului r`d`cina real` a ecua]iei x3+x+1=0. Se cere ca r`d`cina s` fie afi[at` cu primele 50 de zecimale exacte. Indicaţii / rezolvări: 1. class prima { public static void main(String[] args) { System.out.print("a="); int a=Integer.parseInt(cin.Token()); System.out.print("b="); int b=Integer.parseInt(cin.Token()); System.out.println(a+Math.floor(Math.random()*(b-a+1))); } } 3. class prima { public static void main(String[] args) { String afis=new String(cin.linie()); System.out.println(afis.substring(0,10));} } 4. Dac` \ncerca]i programul precedent, pentru un [ir de caractere mai mic de 10 caractere ve]i primi eroare! class prima { public static void main(String[] args) { String afis=new String(cin.linie()); if (afis.length()>4) System.out.println(afis.substring(0,4)); else System.out.println(sir);} } 5. class Afis { String aNum(int lung, String sir) { if (sir.length()>lung) return sir.substring(0,lung); else { String blank=""; for (int i=1;i<=lung-sir.length();i++) blank=blank+" "; return sir+blank; } } } 6. class prima { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); String[] t=new String [n]; for(int i=0;i<n;i++) t[i]=cin.linie(); Afis comanda=new Afis(); for(int i=0;i<n;i++) System.out.println(" "+comanda.aNum(5,t[i])); } } Capitolul 5. Studiul unor clase ale limbajului Java 7. String num(int lung, int v) { String sir=new String (""+v); if (sir.length()>lung) return "Numarul nu poate fi afisat"; else { while (sir.length()!=lung) sir=" "+sir; return sir;} } 8. class prima { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Afis comanda=new Afis(); int[] t=new int [n]; for(int i=0;i<n;i++) t[i]=Integer.parseInt(cin.Token()); for(int i=0;i<n;i++) System.out.println(comanda.num(5,t[i])); } } 9. String num(int lung, int zec, double v) { String sir=new String (""+v); int indice=sir.indexOf("."); if (sir.length()-indice-1<zec) while (sir.length()-indice-1!=zec) sir=sir+"0"; else sir=sir.substring(0,indice+zec+1); if (sir.length()>lung) return "Numarul nu poate fi afisat"; else { while (sir.length()!=lung) sir=" "+sir; return sir; } } 10. class prima { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Afis comanda=new Afis(); double[] t=new double [n]; for(int i=0;i<n;i++) t[i]=Double.parseDouble(cin.Token()); for(int i=0;i<n;i++) System.out.println(comanda.Num(8,2,t[i])); } } 11. class Elev { String Nume; int nota_mate,nota_info,nota_engl; Elev() { System.out.println("Introduceti datele"); System.out.print("Numele elev=");Nume=cin.linie(); 129 130 Bazele programării în Java System.out.print("Nota mate="); nota_mate=Integer.parseInt(cin.Token()); System.out.print("Nota info="); nota_info=Integer.parseInt(cin.Token()); System.out.print("Nota engl="); nota_engl=Integer.parseInt(cin.Token()); } void afisez() { Afis elv=new Afis(); System.out.print(elv.aNum(20,Nume)); System.out.print(elv.num(5,nota_mate)); System.out.print(elv.num(5,nota_info)); System.out.print(elv.num(5,nota_engl)); double med=(double)(nota_mate+nota_info+nota_engl)/3; System.out.println(elv.num(8,2,med));} } 12. class prima { public static void main(String[] args) { System.out.print("n=");int n=Integer.parseInt(cin.Token()); Elev[] tabel=new Elev[n]; for (int i=0;i<n;i++) tabel[i]=new Elev(); for (int i=0;i<n;i++) tabel[i].afisez();} } 13. import java.util.*; class t { public static void main(String[] args) { String s=new String (cin.linie()); StringTokenizer t=new StringTokenizer(s); String sir_corect= new String(); while (t.hasMoreTokens()) sir_corect=sir_corect+t.nextToken()+" "; sir_corect=sir_corect.trim(); System.out.println(sir_corect);} } 14. import java.math.*; class t { public static void main(String[] args) { System.out.print("n=");int n=Integer.parseInt(cin.Token()); BigInteger P=new BigInteger("1"),I=new BigInteger("1"),incr=new BigInteger("1"); for(int i=1;i<=n;i++) { P=P.multiply(I); I=I.add(incr);} System.out.println(P.toString());} } 17. Dac` not`m cu f(x)=x3+x+1, avem f(-1)=-1, f(0)=1. Cum f‟(X)=3x2+1, f este strict cresc`toare [i are o unic` r`d`cin` \n intervalul (-1,0). Lugimea intervalului este 1. De acum putem aplica metoda \njum`t`]irii intervalului. CAPITOLUL 6 Extinderea claselor Din cuprins: Un exemplu de extindere al unei clase O modalitate de simulare a extinderii multiple Referinţe către obiectele superclaselor, referinţe către obiectele subclaselor Probleme propuse 132 Bazele programării în Java 6.1. Noţiuni generale 1. Pornind de la o clas` dat` se poate crea o alt` clas`, care o extinde (mo[tene[te) pe aceasta. Noua clas` va avea toate datele membru [i toate metodele clasei de la care s-a pornit, c`rora li se pot ad`uga noi date membru [i/sau noi metode. |n Java, clasa care este extins` se nume[te superclas`, iar noua clas` se nume[te subclas`. Analiza]i exemplul de mai jos: class C1 { int x,y; } class C2 extends C1 { int z; void afis() { System.out.println(x+" "+ y+" "+z); } } public class C { public static void main(String[] args) { C2 ref= new C2(); ref.x=3; ref.y=4; ref.z=5; ref.afis(); } } Aici s-a extins clasa C1. Ea con]ine dou` date membru x [i y, ambele de tip int. |n exemplul dat, C1 este superclas`. Noua clas`, C2, va con]ine datele membru ale clasei C1 (\n exemplu x [i y) dar [i o nou` dat` membru (z, de tip int). De asemenea, clasa C2 con]ine [i metoda afis(), care are rolul de a afi[a con]inutul datelor membru ale unui obiect. |n exemplu, clasa c2 este subclas`. Programul creeaz` un obiect al clasei C2, numit ref, \i ini]ializeaz` datele membru [i le afi[eaz`. 2. Pentru a marca faptul c` o clas` extinde o alt` clas` se folose[te cuv@ntul extends (\n exemplu class C2 extends C1 ). 3. Ini]ializarea unui obiect al subclasei are ca efect apelul, \n aceast` ordine, al constructorului superclasei [i apelul constructorului subclasei. Este normal s` fie a[a, pentru c` subclasa include datele membru [i metodele superclasei. Exemplu: analiza]i programul de mai jos, \n care fiecare clas` con]ine c@te un constructor. Programul afi[eaz`: Constructor 1 Constructor 2 Capitolul 6. Extinderea claselor 133 class Unu{ Unu (){ System.out.println("Constructor 1"); } } class Doi extends Unu { Doi() { System.out.println("Constructor 2"); }; } public class C { public static void main(String[] args) { Doi x=new Doi(); } } 4. Exist` posibilitatea ca anumite date membru sau metode s` aib` acela[i nume at@t \n superclas` c@t [i \n subclas`. |n astfel de cazuri, implicit, la \nt@lnirea numelui datei membru (sau metodei) se apeleaz` data membru (metoda) a subclasei. |n cazul \n care se dore[te ca s` fie apelat` data membru (metoda) a superclasei, se utilizeaz` cuv@ntul cheie super. El are semnifica]ia de obiect curent al superclasei. |n exemplul de mai jos, x este dat` membru at@t a superclasei c@t [i a subclasei. Exemplu: programul urm`tor va afi[a 1 2 3. class C1 { int x=1,y; } class C2 extends C1 { int x; void afis() { System.out.println(super.x+" "+ y+" "+x); } } class C{ public static void main(String[] args) { C2 pt= new C2(); pt.x=3; pt.y=2; pt.afis(); } } super nu poate fi folosit \n afara clasei. 5. |n cazul \n care superclasa este \nzestrat` cu un constructor care prime[te parametri, atunci este obligatoriu ca acesta s` fie apelat de constructorul subclasei. De ce? A[a cum am ar`tat, constructorul subclasei apeleaz` automat constructorul superclasei. |n cazul \n care apelul nu este explicit, este apelat constructorul implicit (f`r` parametri) al superclasei. Or, am \nv`]at faptul c`, \n condi]iile existen]ei unui constructor cu parametri, nu mai este posibil s` apel`m constructorul implicit, pentru c` apare eroare. Mai mult, prima instruc]iune a constructorului subclasei trebuie s` fie apelul constructorului superclasei. Apelul constructorului superclasei se face prin: super (lista_parametri). 134 Bazele programării în Java Exemplu: Analiza]i programul urm`tor, \n care clasa Elev con]ine numele [i prenumele unui elev, iar clasa Olimpic extinde clasa Elev [i con]ine \n plus o dat` membru, materia la care elevul este olimpic [i o metod` prin care se afi[eaz` numele, prenumele elevului [i materia respectiv`. class Elev { String nume, prenume; Elev (String nume, String prenume) { this.nume=new String(nume); this.prenume=new String(prenume); } } class Olimpic extends Elev { String materia; Olimpic(String nume, String prenume, String materia) { super(nume,prenume); // apel constructor al superclasei this.materia=new String(materia);} void afis() { System.out.println(nume+" "+prenume+" "+materia); } } public class test { public static void main(String[] args) { //primul mod de creare a unui obiect olimpic Olimpic A=new Olimpic("Pascu", "Marius", "informatica"); //al doilea mod de creare a unui obiect olimpic String n=new String("Grosu"); String p=new String("Bogdan"); String mat=new String("matematica"); Olimpic B=new Olimpic(n,p,mat); A.afis(); B.afis(); } } 6. |n Java, o clas` poate extinde (mo[teni) o singur` superclas` . Nu exist` un mecanism de mo[tenire multipl`, a[a precum exist` \n alte limbaje. Din acest motiv, ierarhia claselor are o structur` arborescent` . 6.2. Un exemplu de extindere al unei clase Fie clasa Complex, de mai jos. Ea are dou` date membru, x [i y, care re]in partea real` [i partea imaginar` a unui num`r complex. De asemenea, clasa este \nzestrat` cu un constructor [i metoda afis(), care afi[eaz` num`rul complex re]inut de obiect. class Complex { double x,y; Complex (double x, double y) { this.x=x; this.y=y;} void afis() {System.out.println(x+" "+y);} } Capitolul 6. Extinderea claselor 135 Clasa este extins` la o alta, Complex_op, care con]ine [i metode prin care se efectueaz` opera]iile de mai jos cu numere complexe: z1 z 2 x 1 i y1 x 2 i y 2 x 1 x 2 i (y1 y 2 ). z1 z 2 x 1 i y1 x 2 i y 2 x 1 x 2 i (y1 y 2 ). z1 z 2 x 1 i y1 x 2 i y 2 x 1 x 2 y1 y 2 i (x 1 y 2 x2 y1 ). x i y1 x 2 i y 2 x1 x 2 y 1 y 2 i x 2 y1 x1 y 2 z1 x i y1 1 1 z 2 x2 i y 2 x2 i y 2 x2 i y 2 x 22 y 22 Iat` ce con]ine, \n plus, clasa Complex_op: Doi constructori. Primul dintre ei accept` partea real` [i partea imaginar` a unui num`r complex. Al doilea, accept` numai partea real` (num`r real inclus, evident, \n mul]imea numerelor complexe). Metodele add, sub, mul, div - efectueaz` opera]iile de adunare, respectiv sc`dere, \nmul]ire, \mp`r]ire a dou` numere complexe. Ele returneaz` num`rul complex rezultat \n urma opera]iei. class Complex_op extends Complex { Complex_op (double x, double y) { super(x,y); } Complex_op (double x) { super(x,0); } Complex_op add(Complex_op z) { Complex_op t=new Complex_op (x+z.x,y+z.y); return t; } Complex_op sub(Complex_op z) { Complex_op t=new Complex_op (x-z.x,y-z.y); return t; } Complex_op mul(Complex_op z) { Complex_op t=new Complex_op (x*z.x-y*z.y, x*z.y+z.x*y); return t; } Complex_op div(Complex_op z) { double num=z.x*z.x+z.y*z.y; Complex_op t; if (num!=0) t=new Complex_op ((x*z.x+y*z.y)/num, (z.x*y-x*z.y)/num); else t=new Complex_op(0,0); return t; } } 136 Bazele programării în Java Exerciţii rezolvate 1. S` se creeze dou` obiecte de tip Complex_op [i s` se afi[eze suma, diferen]a, produsul [i c@tul lor. public class test { public static void main(String[] args) { // instantiez z si il afisez Complex_op z=new Complex_op(2,3); z.afis(); // instantiez z1 si il afisez Complex_op z1= new Complex_op(10); z1.afis(); // Afisez suma dintre z si z1 z.add(z1).afis(); // Afisez diferenta dintre z si z1 z.sub(z1).afis(); // Afisez produsul dintre z si z1 z.mul(z1).afis(); // Afisez catul dintre z si z1 z.div(z1).afis(); } } 2. Se citesc a [i b dou` numere reale care reprezint` partea real` [i partea complex` a num`rului z=a+b*i [i n, un num`r natural mai mare sau egal cu 1. Se cere s` se afi[eze zn. public class test { public static void main(String[] args) { System.out.print("a="); double a=Double.parseDouble(cin.Token()); System.out.print("b="); double b=Double.parseDouble(cin.Token()); Complex_op z= new Complex_op(a,b); z.afis(); // initializez produsul cu 1; Complex_op P= new Complex_op(1); System.out.print("n="); int n=Integer.parseInt(cin.Token()); for (int i=0;i<n;i++) P=P.mul(z); P.afis(); } } 3. S` se extind` clasa Complex_op, la o alta, numit` Cmpl, care s` con]in`, \n plus, o metod` prin care returneaz` modulul num`rului complex [i o alt` metod` boolean` care returneaz` true, \n cazul \n care num`rul este real (y are valoarea 0). Rezolvare. |ntruc@t constructorii nu se mo[tenesc, a fost necesar` rescrierea lor: Capitolul 6. Extinderea claselor 137 class Cmpl extends Complex_op { Cmpl (double x, double y) { super(x,y); } Cmpl (double x) { super(x,0); } double modul() { return Math.sqrt(x*x+y*y);} boolean real() { return y==0; } } 4. Se cite[te un vector de numere complexe. Se cere s` se sorteze cresc`tor elementele vectorului \n func]ie de modulul lor. Rezolvare: datorit` faptului c` avem nevoie de modulul numerelor complexe, vom apela la ultima clas` creat`: Cmpl. Observa]i ierarhia acestor clase: la baz` este Complex, apoi Complex_op, iar ultima este Cmpl. Programul utilizeaz` [i metoda Afis(), care apar]ine clasei complex. public class test { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Cmpl[] V=new Cmpl[n]; for (int i=0;i<n;i++) { System.out.print("V["+i+"].x="); double x=Double.parseDouble(cin.Token()); System.out.print ("V["+i+"].y="); double y=Double.parseDouble(cin.Token()); V[i]=new Cmpl(x,y); } boolean gasit; Cmpl man; do { gasit=false; for (int i=0;i<n-1;i++) if (V[i].modul()>V[i+1].modul()) { man=V[i]; V[i]=V[i+1]; V[i+1]=man; gasit=true; } } while (gasit); for (int i=0;i<n;i++) V[i].afis(); } } 138 Bazele programării în Java 6.3. O modalitate de simulare a extinderii multiple A[a cum deja [ti]i, \n Java o clas` poate extinde (mo[teni) o singur` clas`. Se poate totu[i, simula mo[tenirea multipl`. Privi]i exemplul urm`tor, \n care clasa Mosten extinde dou` clase A [i B. Ea va avea datele membru [i metodele celor dou` clase. Ideea e foarte simpl`: 1. Clasa va re]ine referin]e c`tre obiecte ale claselor pe care le extinde; 2. Pornind de la aceste referin]e se pot accesa datele membru [i metodele claselor care sunt extinse, dup` cum se poate observa \n exemplu: class A { int a=1; void m1() { System.out.println("a="+a);} } class B { int b=2; void m2() { System.out.println("b="+b);} } class Mosten { A x=new A(); void m1() { x.m1(); } B y=new B(); public void m2() { y.m2(); } } public class test { public static void main(String[] args) { Mosten t=new Mosten(); t.m1(); System.out.println(t.x.a); t.m2(); System.out.println(t.y.b); } } Observa]ii: 1. |n fapt, se instan]eaz` 3 obiecte: primul este al clasei A, al doilea este al clasei B [i al treilea este al clasei Mosten. Accesul la datele membru [i metodele obiectelor de tip A [i B se face prin referin]ele c`tre acestea, referin]e con]inute de obiectul de tip Mosten. 2. Accesul la datele membru ale claselor extinse se face pu]in mai greu (vede]i exemplul de mai sus). Cu toate acestea, problema nu este at@t de grav`. |n practica OOP, se obi[nuie[te ca datele membru s` fie accesate numai prin metodele clasei respective. Dezavantajul acestui procedeu este dat de faptul c`, \n cazul unor clase cu zeci de metode care urmeaz` a fi “mo[tenite”, trebuie avut` mult` r`bdare pentru a implementa, ca mai sus, toate metodele. Capitolul 6. Extinderea claselor 139 6.4. Referinţe către obiectele superclaselor şi referinţe către obiectele subclaselor Fie clasele de mai jos, unde clasa Y, extinde clasa X: class X { int k=1; void met() {System.out.println("Metoda x"); } } class Y extends X { int v=2; void metoda() {System.out.println("Metoda y"); } } 1. O variabil` de tip referin]` c`tre un obiect al superclasei poate re]ine o referin]` c`tre un obiect al subclasei. |n acest caz, pornind de la referin]`, se pot accesa numai datele membru [i metodele superclasei, care sunt, evident, [i ale subclasei. Exemplu: programul urm`tor afi[eaz` 1 [i Metoda x: public class test { public static void main(String[] args) { X ref=new Y(); System.out.println(ref.k); ref.met(); } } |n aceste condi]ii, fiecare dintre instruc]iunile urm`toare ar produce eroare: System.out.println(ref.v); ref.metoda(); 2. Totu[i, exist` posibilitatea ca, \n cazul \n care o variabil` de tip referin]` c`tre superclas` con]ine o referin]` c`tre un obiect al subclasei, pornind de la ea, cu ajutorul operatorului de conversie explicit`, s` putem accesa datele membru [i metodele acelui obiect. Vede]i exemplul de mai jos, unde se afi[eaz` 2 [i Metoda y: public class test { public static void main(String[] args) { X ref=new Y(); Y ref1=(Y)ref; System.out.println(ref1.v); ref1.metoda(); } } 140 Bazele programării în Java Observa]ie foarte important`: \n cazul \n care o metod`, nu [i o dat` membru, a superclasei este redefinit` \n subclas`, adic` a fost scris` o alta cu acela[i nume, atunci este posibil ca prin procedeul de mai sus, f`r` a utiliza operatorul de conversie explicit`, s` apel`m metoda subclasei. Acest caz este tratat separat. Vede]i polimorfismul. 3. O variabil` de tip referin]` c`tre un obiect al subclasei, nu poate re]ine o referin]` c`tre superclas`. Exemplu: dac` \n program am avea instruc]iunea: Y ref=new X();, ea ar produce eroare la compilare. V` pute]i \ntreba, la ce folose[te faptul c` o variabil` de tip referin]` c`tre un obiect al superclasei poate re]ine [i o referin]` c`tre un obiect al subclasei? Ideea de baz` este urm`toarea: se poate crea o clas`, care poate fi extins` de mai multe clase. Aceasta \nseamn` c` o structur` oarecare (vector, matrice, stiv`, coad`, list` liniar`, etc) cu elemente de tip referin]` c`tre obiectele superclasei, poate lucra cu referin]e c`tre obiectele subclaselor. Sau, altfel spus, prin acest procedeu se poate asigura independen]a structurii fa]` de datele propriu-zise. Ideea este fundamental` \n OOP. Exemplu: dorim s` cre`m o structur` de tip stiv` care s` lucreze cu orice fel de date, dar structura s` r`m@n` aceea[i. |n acest exemplu, nodurile con]in fie numere \ntregi, fie numere reale. Rezolvare: Pentru a putea implementa aceast` cerin]` vom considera o clas`, s-o numim Baza, care are o singur` dat` membru: o variabil` care poate re]ine referin]e c`tre propriile obiecte. Clasa Int extinde clasa Baza. Ea are [i data membru x, care re]ine un \ntreg, precum [i un constructor. Clasa Real extinde [i ea clasa Baza. Ea are [i data membru x, care re]ine un num`r real, precum [i un constructor. class Baza { Baza adr_prec; } class Int extends Baza { int x; Int(int x) { this.x=x;} } class Real extends Baza { double x; Real(double x) { this.x=x;} } Observa]ii: 1. Evident c` obiectele clasei Int, precum [i obiectele clasei Real au [i data membru adr_prec, care este mo[tenit`. Capitolul 6. Extinderea claselor 141 2. Practic, prin extinderea clasei Baza putem ob]ine orice alte clase ale c`ror obiecte s` poat` fi memorate de stiv`. Clasa Stiva con]ine: variabila varf - care poate re]ine o referin]` c`tre un obiect al clasei Baza. Rolul ei este de a memora adresa ultimului nod introdus \n stiv`. metoda void push(Baza Nod) - introduce un nod \n stiv`; metoda Baza pop() - are rolul de a extrage un nod din stiv` [i de a-l returna. class Stiva { Baza varf; void push(Baza Nod) { Nod.adr_prec=varf; varf=Nod;} Baza pop() { if (varf!=null) { Baza x=varf; varf=varf.adr_prec; return x; } else return null; } } |n programul urm`tor se introduc \n stiv` 3 numere \ntregi, dup` care se extrag [i se afi[eaz`: class test { public static void main(String[] args) { Stiva st=new Stiva(); st.push(new Int(3)); st.push(new Int(5)); st.push(new Int(6)); Int N; while ((N=(Int)st.pop())!=null) System.out.println(N.x); } } |n programul urm`tor se introduc \n stiv` 3 numere reale, dup` care se extrag [i se afi[eaz`: class test { public static void main(String[] args) { Stiva st=new Stiva(); st.push(new Real(3.2)); st.push(new Real(5.5)); st.push(new Real(6.3)); Real N; while ( (N=(Real)st.pop())!=null ) System.out.println(N.x); } } 142 Bazele programării în Java Probleme propuse 1. S` se extind` clasa cin. Noua clas` se va numi Cit [i va con]ine metodele: static int Intreg() // cite[te [i returneaz` un num`r \ntreg; static double Real() // cite[te [i returneaz` un num`r real; static char Caracter() // cite[te [i returneaz` un caracter; static String Sir() // cite[te [i returneaz` un [ir de caractere. 2. Utiliza]i noua clas` \ntr-un program care cite[te [i afi[eaz` un num`r \ntreg, unul real [i un caracter. |ntreb`rile de la 3 la 7 se refer` la cele dou` clase: class Unu { int A=1;} class Doi extends Unu {int A=2;} 3. Ce se afi[eaz` \n urma execut`rii secven]ei urm`toare? Doi x=new Doi(); System.out.println(x.A); a) 1; b) 2; c) Eroare. 4. Ce se afi[eaz` \n urma execut`rii secven]ei urm`toare? Unu x=new Doi(); System.out.println(x.A); a) 1; b) 2; c) Eroare. 5. Ce se afi[eaz` \n urma execut`rii secven]ei urm`toare? Doi x=new Unu(); System.out.println(x.A); a) 1; b) 2; c) Eroare. 6. Ce se afi[eaz` \n urma execut`rii secven]ei urm`toare? Doi x=new doi(); System.out.println(x.super.A); a) 1; b) 2; c) Eroare. Capitolul 6. Extinderea claselor 143 7. Scrie]i o secven]` \n main(), care afi[eaz` valorile re]inute de data membru A a clasei Unu [i data membru A a clasei Doi. Cerin]` suplimentar`: se va utiliza o singur` dat` operatorul new. 8. Fiind date clasele de mai jos, care este corpul corect al constructorului clasei Doi? class Unu { int A; Unu (int A) {this.A=A; } } class Doi extends Unu { int B,C; Doi (int A, int B, int C) { ... } void afis() { System.out.println(A+" "+B+" "+C);} } a) this.B=B; this.C=C; super(A); b) super(A); this.B=B; this.C=C; c) this.A=A; this.B=B; this.C=C; d) Nici unul nu este corect 9. Fiind dat` clasa de mai jos (Baza), scrie]i o clas` (Lista) care creeaz` o list` liniar` simplu \nl`n]uit` \n care elementele sunt obiectele clasei Baza. Evident, elementele acestei liste nu au nici o alt` informa]ie, \n afara celei de adres`. class Baza { Baza adr_urm;} Lista va con]ine: Baza v; - data membru; re]ine v@rful listei; Baza varf() - returneaz` v@rful listei liniare (adresa primului element); void adaug (Baza Nod) - adaug` la sf@r[itul listei un element. 10. Crea]i clasa Int, care s` extind` clasa Baza [i s` con]in` \n plus: int val; - dat` membru; Int (int val) - constructor; int valoare() - returneaz` valoarea re]inut` de val. 11. Scrie]i un program care creeaz` o list` liniar` simplu \nl`n]uit` cu n elemente (n citit de la tastatur`) de tip Int. Valorile re]inute de obiectele de tip Int sunt, de asemenea, citite de la tastatur`. Lista va fi construit` cu ajutorul clasei Lista. 144 Bazele programării în Java 12. Scrie]i un program care creeaz` o list` liniar` simplu \nl`n]uit` cu n elemente (n citit de la tastatur`) de tip String. {irurile de caractere re]inute de obiectele de tip Sir sunt, de asemenea, citite de la tastatur`. Lista va fi construit` cu ajutorul clasei Lista. 13. Scrie]i un program care creeaz` o list` liniar` simplu \nl`n]uit` cu n elemente (n citit de la tastatur`), obiecte de tip Persoana. Clasa Persoana va fi construit` de dvs. [i va con]ine numele [i vârsta persoanei. Lista va fi construit` cu ajutorul clasei Lista. Indicaţii / răspunsuri: 1. class Cit extends cin { static int Intreg() { return Integer.parseInt(Token());} static double Real() { return Double.parseDouble(Token());} static char Caracter() { return linie().charAt(0);} static String Sir() {return linie();} } 2. class t { public static void main(String[] args) { System.out.print("n=");int n=Cit.Intreg(); System.out.println(n); System.out.print("x=");double x=Cit.Real(); System.out.println(x); System.out.print("ch=");char ch=Cit.Caracter(); System.out.print(ch);} } 3. b) 4. a) 5. c) 6. c) 7. Doi x=new Doi(); Unu y=x; System.out.println(y.A+" "+x.A); 8. b) 9. class Lista { Baza v; Baza varf() { return v;} void adaug (Baza Nod) { Baza c=v; if (c!=null) { while (c.adr_urm!=null) c=c.adr_urm; c.adr_urm=Nod; } else v=Nod; } } Capitolul 6. Extinderea claselor 10. class Int extends Baza { int val; int (int val) { this.val=val;} int valoare() { return val;} } 11. public class C { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Lista l= new Lista(); for (int i=0;i<n;i++) { System.out.print("val="); int val=Integer.parseInt(cin.Token()); Int Nod=new Int(val); l.adaug(Nod);} Baza varf=l.varf(); Int Nod=(Int)varf; while (Nod!=null) { System.out.println(Nod.valoare()); Nod=(Int)Nod.adr_urm;} } } 12. Rezolv`m problema \n doi pa[i: a) Construim clasa Sir, care extinde clasa Baza: class Sir extends Baza { String sir; Sir (String sir) { this.sir=sir; } String valoare() { return sir; } } b) Scriem programul propriu-zis: public class C { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Lista l= new Lista(); for (int i=0;i<n;i++) { System.out.print("val="); String val=cin.linie(); Sir Nod=new Sir(val); l.adaug(Nod);} Baza varf=l.varf(); Sir Nod=(Sir)varf; while (Nod!=null) { System.out.println(Nod.valoare()); Nod=(Sir)Nod.adr_urm; } } } 145 146 Bazele programării în Java 13. class Persoana extends Baza { String nume; int varsta; Persoana () { System.out.println("Nume="); nume=cin.linie(); System.out.println("varsta="); varsta=Integer.parseInt(cin.Token()); } String nume() { return nume; } int varsta() { return varsta; } } public class C { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Lista l= new Lista(); for (int i=0;i<n;i++) { Persoana Nod=new Persoana(); l.adaug(Nod); } Baza varf=l.varf(); Persoana Nod=(Persoana)varf; while (Nod!=null) { System.out.println(Nod.nume() +" "+Nod.varsta()); Nod=(Persoana)Nod.adr_urm; } } } CAPITOLUL 7 Noţiuni avansate de programare orientată pe obiecte Din cuprins: Polimorfism. Exemple Clase abstracte. Exemple Interfeţe. Aplicaţii Modificatori. Exemple Probleme propuse 148 Bazele programării în Java 7.1. Polimorfism Prin polimorfism vom \n]elege posibilitatea ca at@t superclasa, c@t [i subclasa s` aib` metode cu acela[i nume (metodele pot fi redefinite). De[i, \n aparen]`, \n]elegerea polimorfismului nu este dificil`, \n realitate, apar anumite probleme pe care ne propunem s` le rezolv`m \n acest paragraf. Mai mult, polimorfismul reprezint` unul din punctele cheie ale program`rii orientate pe obiecte [i este un instrument puternic de programare. Fie B o clas` care extinde o clas` A. Prin urmare, toate datele membru [i metodele clasei A se reg`sesc [i \n clasa B. Am mai \nv`]at faptul c` o metod` a clasei A poate fi redefinit`, adic`, \n clasa B scriem o metod` cu acela[i nume (\n exemplu, void tip()). Vom trata dou` cazuri, cazul \n care metodele sunt nestatice [i cazul \n care metodele sunt statice. Metodele [i datele membru sunt nestatice. I) Fie O un obiect al clasei A [i O1 un obiect al clasei B. Vede]i exemplul urm`tor, al c`rui rezultat \l pute]i observa al`turat. class A { int i=1; void tip() { System.out.println("clasa A"); } } class B extends A { void tip() { System.out.println("clasa B"); } } public class test { public static void main(String[] args) { // Cazul 1 A O=new A(); O.tip(); // Cazul 2 B O1=new B(); O1.tip(); // Cazul 3 A O2=new B(); O2.tip(); } } |n cazul 1 se apeleaz` metoda tip() a clasei A. Se va afi[a clasa A [i valoarea 1 (pentru i). Este normal s` fie a[a, obiectul este al clasei A, referin]a este c`tre un obiect al clasei A. |n cazul 2 se apeleaz` metoda tip() a clasei B. Se va afi[a clasa B [i valoarea 2 (pentru i). Este normal s` fie a[a, obiectul este al clasei B, referin]a este c`tre un obiect al clasei B. Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 149 |n cazul 3, [i acesta este cazul interesant pe care-l studiem \n acest moment, se va apela metoda tip() a clasei B, prin urmare se va afi[a clasa B [i valoarea 1 (pentru i). S` observ`m c` obiectul este al clasei B, dar variabila care re]ine referin]a c`tre el este o referin]` c`tre obiecte ale clasei A. Cu toate c` a fost apelat` metoda clasei B, a fost afi[at con]inutul variabilei i a clasei A Foarte important: \n cazul unei metode a superclasei, redefinit` \n subclas`, dou` elemente prezint` importan]`: tipul variabilei referin]` (c`tre obiecte ale superclasei sau c`tre obiecte ale subclasei) [i tipul obiectului creat (al superclasei sau al subclasei). Se disting, astfel dou` cazuri: A) tipul referin]ei [i tipul obiectului creat coincid (sunt fie ale superclasei, fie ale subclasei). |n acest caz este apelat` metoda care este din tipul comun. De asemenea, se afi[eaz` variabila care apar]ine obiectului de tip comun. Vezi, mai sus, cazurile 1 [i 2. B) tipul referin]ei este al superclasei, iar tipul obiectului creat este al subclasei (invers nu este posibil, a[a cum am ar`tat). |n acest caz, dac` metoda redefinit` este nestatic`, Java ia \n considerare tipul obiectului creat [i deci, va fi apelat` metoda subclasei. Vezi, mai sus, cazul 3. |n schimb, se ob]ine accesul la data membru a superclasei. II) Metodele [i datele membru sunt statice. Relu`m problema pentru acest caz. Vede]i programul de mai jos, iar rezultatul afi[at de el, al`turat. |n cazurile 1 [i 2 comportamentul este acela[i, dar \n cazul 3 este apelat` metoda superclasei, deci se afi[eaz` clasa A. Observa]i faptul c`, \n acest caz, comportamentul este diferit. class A { static int i=1; static void tip() { System.out.println("clasa A"); } } class B extends A { static int i=2; static void tip() { System.out.println("clasa B"); } } public class test { public static void main(String[] args) { // Cazul 1 System.out.println("Cazul 1"); A O=new A(); O.tip(); System.out.println(O.i); // Cazul 2 System.out.println("Cazul 2"); B O1=new B(); O1.tip(); System.out.println(O1.i); 150 Bazele programării în Java // Cazul 3 System.out.println("Cazul 3"); A O2=new B(); O2.tip(); System.out.println(O2.i); } } |n terminologia program`rii orientate pe obiecte ve]i \nt@lni termenul de legare (static`, dinamic`). Care este semnifica]ia lui? Pornind de la referin]a c`tre obiect, se apeleaz` o metod` redefinit`. Am v`zut c`, \n unele cazuri se apeleaz` metoda superclasei, \n altele, se apeleaz` metoda subclasei. Cu alte cuvinte, se apeleaz` (leag`) o metod` sau alta. Aceasta este semnifica]ia termenului de legare (adic` apel al unei metode sau alta). Legarea este static` dac` \nainte de executarea programului se poate [ti care metod` este apelat` [i este dinamic` dac` numai \n momentul execut`rii se decide metoda care va fi apelat`. |n Java este permis` [i legarea dinamic`. Privi]i exemplul de mai jos, \n care legarea dinamic` este evident`. Dac` se introduce 0 se afi[eaz` clasa A, iar dac` se introduce o valoare diferit` de 0 se afi[eaz` clasa B. class A { int i=1; void tip() { System.out.println("clasa A"); } } class B extends A { void tip() { System.out.println("clasa B"); } } public class Clasa1 { public static void main(String[] args) { A x; int n=Integer.parseInt(cin.Token()); if (n==0) x=new A(); else x=new B(); x.tip(); } } 7.2. Un exemplu de polimorfism S` se creeze o clas` numit` Muncitor. Clasa va con]ine data membru ore_lucrate [i un constructor prin care acesteia i se atribuie o valoare. De asemenea, clasa con]ine o metod` nestatic` salariu() prin care se calculeaz` suma c@[tigat` de acesta (se ob]ine ca produs \ntre num`rul orelor lucrate [i suma \ncasat` pentru o or` lucrat`, \n exemplu 20000 lei). Dintre muncitori, se selecteaz` [eful de echip`, care are \n Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 151 subordine mai mul]i muncitori. Se [tie c` [eful de echip` prime[te mai mult pentru o or` lucrat` (\n exemplu 50.000). Se construie[te clasa Sef_echipa, care este subclas` a clasei Muncitor. Metoda salariu() este redefinit`. Dintre [efii de echip`, unii sunt selecta]i pentru a urma o [coal` de mai[tri. Dup` ce devin mai[tri [i au \n subordine mai mul]i [efi de echip`. S` se construiasc` clasa Maistru, care are ca superclas` clasa Sef_echipa. Un maistru prime[te pe or` mai mult dec@t un [ef de echip` (\n exemplu 100000 lei), deci metoda salariu() este redefinit`. Se cere s` se scrie un program care cite[te un num`r natural n \ntre 1 [i 3. Dac` n este 1 se construie[te un obiect al clasei muncitor, dac` n este 2 se construie[te un obiect al clasei sef_echipa, iar dac` n este 3 se construie[te un obiect al clasei Maistru. De asemenea, se cite[te num`rul de ore lucrat de persoana respectiv`. |n final, se va afi[a salariul \ncasat de persoana citit`. class Muncitor { int ore_lucrate; Muncitor(int ore_lucrate) { this.ore_lucrate=ore_lucrate;} double salariu() { return ore_lucrate*20000;} } class Sef_echipa extends Muncitor { Sef_echipa(int ore_lucrate) { super(ore_lucrate); } double salariu() { return ore_lucrate*50000;} } class Maistru extends Sef_echipa { Maistru(int ore_lucrate) { super(ore_lucrate);} double salariu() { return ore_lucrate * 100000;} } public class test { public static void main(String[] args) { Muncitor x=null; int tip=Integer.parseInt(cin.Token()); int ore=Integer.parseInt(cin.Token()); switch (tip) { case 1: x=new Muncitor(ore); break; case 2: x=new Sef_echipa(ore); break; case 3: x=new Maistru(ore); break; } System.out.println(x.salariu()); } } 152 Bazele programării în Java Observaţii: Exemplul dat se refer` la polimorfism [i la legarea dinamic`. Metoda salariu este prezent` \n toate cazurile. Este rulat` o metod` sau alta \n func]ie de valoarea citit`, prin urmare avem legare dinamic`. Exist` multe alte metode de rezolvare ale acestei probleme. Judec@nd dup` problema \n sine, ar rezulta c` utilizarea polimorfismului poate fi evitat`. A[a este, dar \n cazul programelor complexe (de exemplu \n programarea vizual`), utilizarea lui se dovede[te extrem de util`. 7.3. Clase abstracte Limbajul Java pune la dispozi]ia programatorilor un mecanism care se dovede[te uneori extrem de eficient [i anume clasele abstracte. O clas` abstract` con]ine date membru (nu \n mod obligatoriu) [i mai multe metode, dar unele pot fi, la r@ndul lor abstracte. Pentru o metod` abstract`, \n clas` se trece doar prin antetul ei. Metodele abstracte urmeaz` s` fie redefinite \n subclase. Orice clas` abstract` trebuie s` fie precedat` de cuv@ntul cheie abstract [i orice metod` abstract` din cadrul ei trebuie [i ea s` fie precedat` de acela[i cuv@nt cheie. Clasele abstracte nu se folosesc direct, adic` nu se instan]iaz` obiecte ale lor, ci se utilizeaz` doar pentru a fi extinse (sunt prin defini]ie superclase). Exemplu. |n programul de mai jos clasa Ex este abstract`. Ea con]ine dou` metode abstracte, afis1() [i afis2(), dar [i o metod` decid(), care \n func]ie de un parametru apeleaz` una dintre cele dou` metode abstracte. Pentru a putea folosi clasa Ex, o extindem ob]in@nd astfel clasa Ex1. |n clasa Ex1, redefinim cele dou` metode. Totu[i, clasa Ex1 nu redefine[te metoda decid(), deci orice obiect al ei va folosi metoda din clasa abstract`. Acest mecanism, permite ca \n clasa abstract` s` existe un anumit “motor” (metod`) care apeleaz` alte metode care urmeaz` a fi redefinite. Programul de mai jos apeleaz` mai \nt@i Afis 1 [i apoi Afis 2: abstract class Ex { abstract void afis1(); abstract void afis2(); void decid(int b) { if (b>0) afis1(); else afis2(); } } class Ex1 extends Ex { void afis1() { System.out.println("Afis 1");} void afis2() { System.out.println("Afis 2");} } Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 153 public class test { public static void main(String[] args) { Ex1 a=new Ex1(); a.decid(1); a.decid(-1); } } 7.4. Un exemplu de clasă abstractă Cei care au studiat backtracking \n variant` iterativ`, standardizat`, au v`zut fapul c` exist` o unic` metod` care apeleaz` mai multe metode care au acela[i nume, parametri [i acela[i rol. A rezolva o problem` sau alta \nseamn` a rescrie metodele specifice (init(), succesor(), [.a.m.d.) dar motorul (metoda back()) r`m@ne aceea[i. De aici [i ideea: o clas` abstract` (Bkt) va re]ine metoda back(), care nu este abstract`, iar celelalte metode sunt abstracte. A rezolva o problem` \nseamn` a crea o subclas` \n care redefinim metodele care o rezolv` (init(), succesor(), valid(),...) conform cerin]elor problemei. Programul de mai jos, utilizeaz` clasa bkt, pentru a o extinde \n vederea rezolv`rii problemei particulare de generare a tuturor permut`rilor mul]imii {1,2..n}, pentru n citit. abstract class Bkt { int[] st; int n; abstract void init(int k); abstract boolean am_Succesor (int k); abstract boolean e_Valid(int k); abstract boolean solutie(int k); abstract void tipar(); void back() { boolean AS; int k=1; st=new int[n+1]; init(k); while (k>0) { do { } while ((AS=am_Succesor(k)) && !e_Valid(k)); if (AS) if (solutie(k)) tipar(); else {k++;init(k);} else k--; } } } class Permut extends Bkt { Permut (int n) { this.n=n;} void init(int k) { st[k]=0; } 154 Bazele programării în Java boolean am_Succesor (int k) { boolean rasp=false; if (st[k]<n) { st[k]++; rasp=true;} return rasp;} boolean e_Valid(int k) { boolean rasp=true; for (int i=1;i<k;i++) if (st[i]==st[k]) rasp=false; return rasp; } boolean solutie(int k) { return k==n;} void tipar() { for (int i=1;i<=n;i++) System.out.print(st[i]); System.out.println();} } public class test { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Permut x=new Permut(n); x.back(); } } Exerci]iu: se cere s` se rezolve problema celor n dame. Folosind clasele anterioare [i polimorfismul, problema devine foarte u[oar`. Ob]inem clasa Dame care extinde clasa Permut. O singur` metod` trebuie redefinit`, metoda boolean e_Valid(int k). class Dame extends Permut { Dame (int n) { super(n); } boolean e_Valid(int k) { boolean rasp=true; for (int i=1;i<k;i++) if ((st[i]==st[k]) || (Math.abs(st[k]-st[i])==Math.abs(k-i)) rasp=false; return rasp; } } Iar programul este asem`n`tor celui anterior: public class test { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Bkt x=new Dame(n); x.back(); } } ) Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 155 7.5. Interfeţe Prin interfa]` vom \n]elege un proiect de clas`. O interfa]` poate con]ine doar constante [i antete de metode. Ele sunt acceptate de limbaj [i se presupune c`, ulterior, interfe]ele vor fi implementate de una sau mai multe clase. O interfa]` arat` ca o clas`, numai c`, \n locul cuv@ntului class, se folose[te cuv@ntul interface. Atunci c@nd scriem o clas` care implementeaz` o anumit` interfa]`, se folose[te cuv@ntul cheie implements, ca \n exemplul de mai jos. O interfa]` poate fi implementat` de una sau mai multe clase. Exemplu: Mai jos, avem o interfa]` numit` InterfA. Interfa]a este implementat` de dou` clase, A [i B. |n main() prob`m toate acestea prin crearea a dou` obiecte, unul care instan]iaz` clasa A, altul care instan]iaz` clasa B. Programul afi[eaz`: Afis din clasa A=6 5 Afis din clasa B=7 5 iar codul este: interface InterfA { int i=5; void afis(); } class A implements InterfA{ int i=6; public void afis() { System.out.println("Afis din clasa A="+i+" "+InterfA.i);} } class B implements InterfA { int i=7; public void afis() { System.out.println("Afis din clasa B="+i+" "+InterfA.i);} } public class test { public static void main(String[] args) { A x=new A(); x.afis(); B y=new B(); y.afis(); } } Mai observ`m c`: Constantele declarate \n interfa]` (\n exemplu constanta i, cu valoarea 5) se apeleaz` prin numele interfe]ei, urmat de „.‟ [i de numele constantei. Constantele pot fi redefinite de date membru (\n exemplu de i cu valoarea 6 [i i cu valoarea 7). At@t constanta c@t [i redefinirile ei pot fi apelate simultan. 156 Bazele programării în Java 1. O variabil` de tip referin]` c`tre interfa]` poate memora o referin]` c`tre orice clas` care implementeaz` respectiva interfa]`. Mai mult, legarea este dinamic`, a[a cum rezult` din exemplul urm`tor. Exemplu: pentru clasele implementate anterior, se poate ob]ine acela[i efect dac` main() se scrie astfel: public static void main(String[] args) { int tip=Integer.parseInt(cin.Token()); if (tip==1) { interfA x=new A(); x.afis(); } else { interfA y=new B(); y.afis(); } } 2. O interfa]` poate extinde mai multe interfe]e. S` observ`m faptul c` o clas` poate extinde o singur` clas`, dar o interfa]` poate extinde mai multe interfe]e, ca mai jos: interface A { void metA();} interface B { void metB();} interface C { void metC();} interface Extinsa extends A,B,C { void MetE();} 3. A implementa o interfa]` extins` \nseamn` a implementa toate metodele interfe]elor care au stat la baza extinderii, plus metodele a c`ror antet se g`se[te \n interfa]a extins`. |n exemplul urm`tor se implementeaz` clasa Extinsa: class Ex implements public void metA() public void metB() public void metC() public void metE() } Extinsa { {System.out.println("metA");} {System.out.println("metB");} {System.out.println("metC");} {System.out.println("metE");} public class test { public static void main(String[] args) { Ex x=new Ex(); x.metA(); x.metB(); x.metC(); x.metE(); } } 4. O clas` poate implementa oric@te interfe]e, ca \n exemplul urm`tor: interface A { void metA();} interface B { void metB();} interface C { void metC();} Capitolul 7. Noţiuni avansate de programare orientată pe obiecte class Ex implements public void metA() public void metB() public void metC() } 157 A,B,C { {System.out.println("metA");} {System.out.println("metB");} {System.out.println("metC");} public class test { public static void main(String[] args) { Ex x=new Ex(); x.metA(); x.metB(); x.metC();} } 5. Cu ajutorul interfe]elor se poate simula mo[tenirea multipl` (se [tie c` \n Java nu este permis` mo[tenirea multipl`). Exemplu: Avem 3 clase rezultate \n urma implement`rii a 3 interfe]e. Prin procedeul de mai jos, clasa Mosten preia metodele celor 3 clase: interface A { void metA();} class Aclass implements A { public void metA() {System.out.println("metA");} } interface B { void metB();} class Bclass implements B { public void metB() {System.out.println("metB");} } interface C { void metC();} class Cclass implements C { public void metC() {System.out.println("metC");} } class Mosten public void public void public void } implements metA() { A metB() { B metC() { C A,B,C { x= new Aclass(); x.metA();} x= new Bclass(); x.metB();} x= new Cclass(); x.metC();} public class test { public static void main(String[] args) { Mosten x=new Mosten(); x.metA(); x.metB(); x.metC();} } 6. Mai mult, se pot aceea[i interfa]`. Privi]i un moment dat, o implementeaz` interfa]a interface Interf { void met();} mo[teni metode ale claselor care implementeaz` o exemplul urm`tor \n care clasa Mosten utilizeaz`, la singur` clas` dintre cele 3 (A, B, C) care numit` Interf: 158 Bazele programării în Java class A implements Interf { public void met() {System.out.println("Metoda din A");} } class B implements Interf { public void met() {System.out.println("Metoda din B");} } class C implements Interf { public void met() {System.out.println("Metoda din C");} } class Mosten { Interf x; Mosten (Interf x) { this.x=x;} void met() { x.met();} } public class test { public static void main(String[] args) { Mosten v1=new Mosten(new A()); v1.met(); Mosten v2=new Mosten(new B()); v2.met(); Mosten v3=new Mosten(new C()); v3.met();} } 7.6. Aplicaţii ale interfeţelor Vom prezenta c@teva exemple, pur didactice, care s` explice rolul interfe]elor. Atunci c@nd ve]i studia programarea vizual` v` ve]i convinge de importan]a lor. Exemplul 1. |n multe programe se solicit` citirea unui num`r natural. Aceasta se poate face prin afi[area unui mesaj, apoi urmeaz` citirea propriu-zis` a acestuia. Pentru a permite ca programul s` r`m@n` aproape neschimbat atunci c@nd citim un num`r natural \ntr-un fel sau altul, metoda care cite[te se va g`si \ntr-o interfa]`, care este implementat` diferit de mai multe clase. |n acest exemplu interfa]a CitScriu con]ine antetul unei metode de citire a unui num`r natural. Dou` clase, IO1 [i IO2 implementeaz` aceast` interfa]`. Clasa Suma este \nzestrat` cu un constructor care are ca parametru o referin]` c`tre obiectul care efectueaz` citirea [i o metod`, afis(), care cite[te dou` numere naturale [i afi[eaz` suma lor. Rula]i programul [i prin crearea obiectului Suma, cu ajutorul instruc]iunii: Suma s=new Suma (new IO2());. interface CitScriu { int citeste();} class IO1 implements CitScriu { public int citeste() { System.out.print("Introduceti valoarea "); return Integer.parseInt(cin.Token()); } } Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 159 class IO2 implements CitScriu { public int citeste() { System.out.print("Tastati valoarea dorita "); return Integer.parseInt(cin.Token());} } class Suma { CitScriu x; Suma(CitScriu x) { this.x=x;} void afis() { int n=x.citeste(); n+=x.citeste(); System.out.println("Suma este "+n);} } public class test { public static void main(String[] args) { Suma s=new Suma (new IO1()); s.afis(); } } Exemplul 2. Uneori creatorul unei clase care utilizeaz` metoda (metodele) unei interfe]e dore[te s` lase utilizatorilor clasei “pl`cerea” de a implementa respectivele metode. |ntr-un astfel de caz el furnizeaz` fi[ierul compilat al clasei respective. Iat`, pentru exemplul anterior, cum arat` clasa Suma: abstract class Suma implements CitScriu{ void afis() { int n=citeste(); n+=citeste(); System.out.println("Suma este "+n);} } Cel care utilizeaz` clasa respectiv` va scrie un program precum cel de mai jos: class SumaM extends Suma implements CitScriu { public int citeste() { System.out.print("v="); return Integer.parseInt(cin.Token()); } } public class test { public static void main(String[] args) { SumaM s=new SumaM (); s.afis(); } } Exemplul 3. Prin utilizarea interfe]elor se pot transmite metode (func]ii) ca parametri. |n exemplu, interfa]a Functia con]ine antetul unei func]ii reale de parametru real, numit` f. Interfa]a poate fi implementat` de mai multe clase, unde fiecare clas` define[te func]ia f. Clasa Afis con]ine o variabil` de tip referin]` c`tre interfa]a Functia, numit` ref. Aceast` variabil` este utilizat` pentru a memora o referin]` c`tre un obiect al uneia din clasele 160 Bazele programării în Java care implementeaz` interfa]a, deci c`tre func]ia dorit`. Prin urmare, cu ajutorul clasei Afis se poate calcula func]ia dorit`. |n exemplu, interfa]a a fost implementat` de dou` clase, care con]in func]ii diferite: Liniara [i Patratica. Clasa Afis r`m@ne nemodificat`, indiferent de func]ia pe care o evalueaz`. Compila]i interfa]a Functia [i clasele Liniara, Patratica [i Afis. interface Functia { double f(double x);} class Liniara implements Functia { public double f(double x) {return 3*x+1;} } class Patratica implements Functia { public double f(double x) {return x*x;} } class Afis { Functia ref; Afis(Functia ref) { this.ref=ref;} public double funct(double x) { return ref.f(2); } } S` presupunem c` un utilizator dore[te s` afi[eze f(1), f(2)... f(10) pentru func]ia liniar` 3x+1. Atunci el va scrie programul: public class test{ public static void main(String[] args) { Afis a =new Afis(new Liniara()); for (int i=1;i<=10;i++) System.out.println (a.funct(i)); } } S` presupunem c` utilizatorul dore[te s` afi[eze f(1), f(2)... f(10) pentru func]ia x2. Atunci el va scrie programul: public class test{ public static void main(String[] args) { Afis a =new Afis(new Patratica()); for (int i=1;i<=10;i++) System.out.println (a.funct(i)); } } Observa]ie: mai general, prin utilizarea interfe]elor se transmit de fapt obiecte rezultate din instan]ieri ale claselor care au implementat respectiva interfa]`. Exemplul 4. Nu este de neglijat faptul c` \ntr-o interfa]` se pot defini multe constante. Urm`ri]i exemplul urm`tor \n care am declarat [i “utilizat” constante pentru zilele s`pt`m@nii: Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 161 interface Saptamana { int Luni=1,Marti=2, Miercuri=3,Joi=4, Vineri=5, Sambata=6, Duminica=7; } class Ziua implements Saptamana { void ceFac() { for (int zi=Luni;zi<=Duminica;zi++) if (zi>=Marti && zi<=Joi) System.out.println("Ceva munca"); else System.out.println("Sarbatoare"); } } public class test { public static void main(String[] args) { Ziua x=new Ziua(); x.ceFac();} } |n practic`, constantele joac` un rol extrem de important asigur@nd o citire u[oar` [i chiar scriere eficient` a programelor. |n programarea vizual` ve]i \nt@lni o mul]ime de constante pentru culori, alinieri de text, etc. 7.7. Modificatori Forma general` prin care o clas` este definit` o pute]i observa mai jos. Tot ce este trecut \ntre paranteze drepte este op]ional. [<Modificatori clasa>] class <nume clasa>] implements [lista interfete] { [...] } clasa> [extends <nume Observ`m c`, p@n` acum, nu am prezentat modificatorii de clas`. Ace[tia sunt: public, abstract [i final [i se folosesc \n aceast` ordine. 1. Modificatorul public. Dac` este trecut acest modificator, atunci clasa respectiv` poate fi accesat` de orice cod Java care acceseaz` pachetul \n care se g`se[te acea clasa. Dac` acest modificator este absent, atunci clasa poate fi accesat` doar din pachetul \n care se g`se[te (revede]i crearea pachetelor). Clasele publice trebuie scrise \n fi[iere care le poart` numele [i au extensia .java. Observa]ie foarte important`. |n cazul \n care, la crearea clasei, nu se folose[te clauza package (nu se realizeaz` un pachet), se consider` c` respectiva clas` face parte dintr-un pachet f`r` nume. Pachetul f`r` nume este alc`tuit din totalitatea claselor f`r` clauza package care se g`sesc \ntr-un folder. Din acest motiv, c@t timp am lucrat numai cu clase aflate \n folder-ul bin, nu a fost nevoie ca acestea s` con]in` clauza package. 162 Bazele programării în Java 2. abstract - marcheaz` o clas` abstract` (revede]i clasele abstracte). |n absen]`, se consider` c` respectiva clas` nu este abstract`. 3. Modificatorul final este trecut atunci c@nd nu se dore[te ca respectiva clas` s` fie extins` (derivat`, mo[tenit`), caz \n care aceast` opera]ie este interzis`. |n rest, am \nv`]at faptul c` o clas` poate extinde o singur` clas`, dar poate implementa mai multe interfe]e (vede]i: extends, implements). Pentru definirea datelor membru \n Java avem forma general`: [<Modificatori>] <tip data> <Nume data membru1>[=valoare] [Nume data membru2][=valoare]... Modificatorii sunt: 1. public – data membru poate fi accesat` de oriunde este accesibil` (deci [i din afara pachetului) [i poate fi mo[tenit`; 2. protected - data membru poate fi accesat` de codul aflat \n acela[i pachet [i poate fi mo[tenit`; 3. private - data membru poate fi accesat` numai din clasa \n care se afl` [i nu este mo[tenit` (sau dac` vre]i, este mo[tenit`, dar nu poate fi accesat` din clasa care o mo[tene[te, ceea ce este acela[i lucru); 4. modificatorul implicit (package) – are efect \n absen]a modificatorilor de mai sus. Data poate fi accesat` de cod din acela[i pachet [i poate fi mo[tenit` numai de clase ale aceluia[i pachet; 5. final – data membru este considerat` constant`, deci nu poate fi modificat`; 6. static - data membru nu este memorat` de fiecare obiect al clasei respective (modificatorul a mai fost prezentat). Modificatorii public, protected, private [i cel implicit (package) se numesc modificatori de acces. Evident, o defin]ie de dat` membru va con]ine numai unul din cei trei modificatori sau, in absen]a lor, se consider` c` avem modificatorul implicit. Pentru declararea unei metode se utilizeaz` forma general`: [<Modificatori>] <Tip metoda> <Nume> (<lista parametri>) [throws <TipClasa1>[<TipClasa2>]...]]<metoda> Modificatorii sunt prezenta]i mai jos, iar clauza throws va fi studiat` \n capitolul care trateaz` excep]iile. 1. Modificatorii de acces - au aceea[i semnifica]ie ca la datele membru. Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 163 2. final - specific` faptul c` \ntr-o clas` derivat`, metoda nu poate fi redefinit`. 3. static - are ca efect faptul c` metoda nu este re]inut` de fiecare obiect al clasei respective. Acest modificator a fost prezentat. Exemple de utilizare a modificatorilor 1. Modificatorii sunt absen]i. Clasa poate fi accesat` din interiorul pachetului, poate fi derivat`, data membru i poate fi mo[tenit` ca [i metoda met(). De asemenea, data membru [i metoda pot fi accesate de date aflate \n acela[i pachet. class A { int i=2; void met() {System.out.println(“Test”);} }; 2. Clasa test trebuie s` se g`seasc` \n fi[ierul test.java (deoarece este public`). Pentru ea nu se pot crea subclase (pentru c` are modificatorul final). Data membru i este static`, adic` nu se reg`se[te \n fiecare obiect al clasei respective, iar metoda este nestatic`, deci se reg`se[te \n fiecare obiect al clasei respective. public final class test { static int i=2; void met() {System.out.println("Test");} }; |n aceste condi]ii, defini]ia clasei de mai jos este eronat`, chiar dac` se g`se[te \n acela[i pachet cu clasa test. class B extends test {} 3. Fie clasele de mai jos: class A { private int i=2; void met() {System.out.println("Test");} void metp() {System.out.println(i);} }; class B extends A { void met1() {System.out.println("Test1");} } |n aceste condi]ii, dac` \n clasa de mai jos, aflat` \n acela[i pachet, se \nlocuiesc cele trei puncte cu instruc]iunile urm`toare atunci: public class test { public static void main(String[] args) { A x=new A(); ... } } 164 Bazele programării în Java a) System.out.println(x.i); - avem eroare, deoarece modificatorul private, deci nu poate fi accesat din afara clasei; i are b) x.met(); - se afi[eaz` Test pentru c` metoda nu este privat`; c) B y=new B(); y.met1(); - se afi[eaz` Test1; d) B y=new B(); y.met(); - se afi[eaz` Test; e) x.metp(); - se afi[eaz` 2. De[i i este privat, el este afi[at de met() care are acces la datele private ale propriei clase. 4. Fie clasa de mai jos. Atunci: class A { final int i=2; final void met() {System.out.println("Test");} void metp() {System.out.println(i);} } a) Clasa urm`toare, aflat` \n acela[i pachet, este eronat` pentru c` data membru i este cu modificatorul final, este deci considerat` constant` [i prin urmare nu i se poate modifica valoarea: public class test { public static void main(String[] args) { A x=new A(); x.i=4; } } b) Clasa urm`toare, aflat` \n acela[i pachet, este eronat` pentru c` extinde clasa A [i redefine[te o metod` care con]ine modificatorul final: class B extends A { void met() {System.out.println("Test1");} } c) Clasa urm`toare, aflat` \n acela[i pachet, este corect` pentru c`, de[i extinde clasa A, redefine[te o metod` care nu are modificatorul final: class B extends A { void metp() {System.out.println("Test2");} } Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 165 Probleme propuse Testele de la 1 la 4 se refer` la clasele urm`toare. De fiecare dat`, instruc]iunea (sau setul de instruc]iuni) la care se refer` \ntrebarea va fi scris` \n locul liniei lips` (punctat`): class A { int x=1; void met() {System.out.println("Clasa A");} } class B extends A { int x=2; void met() {System.out.println("Clasa B");} } class C extends B { int x=3; void met() {System.out.println("Clasa C");} } public class test { public static void main(String[] args) { ... } } 1. Ce se afi[eaz` \n urma execut`rii secven]ei: A x=new B();x.met(); a) Clasa A; b) Clasa B; c) Clasa C; d) EROARE. 2. Ce se tip`re[te \n urma execut`rii secven]ei: A x=new B(); System.out.println(x.x); a) 1; b) 2; c) 3; d) EROARE. 3. Ce se afi[eaz` \n urma execut`rii secven]ei: B x=(A)new B(); x.met(); a) Clasa A; b) Clasa B; c) Clasa C; d) EROARE. 4. Ce se tip`re[te \n urma execut`rii secven]ei: B x=new C(); x.met(); a) Clasa A; b) Clasa B; c) Clasa C; d) EROARE. 166 Bazele programării în Java 5. Ce afi[eaz` programul de mai jos, dac` n citit este 3? class Unu { int a=1; void afis() {System.out.println(a); } } class Doi extends Unu { int a=2; void afis() { System.out.println(a);} } class t { public static void main(String[] args) { Unu x; int n=Integer.parseInt(cin.Token()); if (n==1) x=new Unu(); else x=new Doi(); x.afis(); System.out.println(x.a); } } a) 1 1; b) 2 2; c) 1 2; d) 2 1. 6. Utiliz@nd polimorfismul, scrie]i un program care cite[te un num`r natural n [i dac` este prim, afi[a]i succesorul s`u \n mul]imea numerelor prime, dac` este impar (f`r` a fi prim) afi[a]i succesorul s`u \n mul]imea numerelor impare, iar dac` este par, afi[a]I succesorul s`u \n mul]imea numerelor pare. Exemple: n=7 se afi[eaz` 11; n=21 se afi[eaz` 23; n=8 se afi[eaz` 10. Testele 7 [i 8 se refer` la programul urm`tor: interface Testare { int k=1; int f(); } class Test1 implements Testare { int k=2; public int f() {return Testare.k;} } class Test2 implements Testare { int k=3; public int f() {return k;} } Capitolul 7. Noţiuni avansate de programare orientată pe obiecte 167 public class test { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Testare x; if (n%2==0) x=new Test1(); else x=new Test2(); System.out.println(x.f()+" "+x.k); } } 7. Ce se afi[eaz` dac` se introduce valoarea 8? a) 1 2; b) 1 1; c) 3 3; d) 2 1. 8. Ce se tip`re[te dac` se cite[te valoarea 21? a) 1 3; b) 2 1; c) 3 3; d) 3 1. 9. Fiind date interfa]a de mai jos [i 3 implement`ri ale ei, se cere s` se scrie un program care afi[eaz` valoarea celor 3 func]ii con]inute de implement`ri pentru o valoare citit` de la tastatur`: interface functie { int f(int x); } class f1 implements functie { public int f(int x) { return x*x-x; } } class f2 implements functie { public int f(int x) { return 8*x-1; } } class f3 implements functie { public int f(int x) { return 3*x*x-x+10; } } 10. Pentru k valori citite de la tastatur` scrie]i un program care afi[eaz` valoarea func]iei g(x), definit` mai jos, unde f1, f2, f3 sunt cele de la problema anterioar`. g ( x) max f1 ( x), f 2 ( x) f 3 ( x) Răspunsuri: 1. b); 2. a); 3. d); 4. c); 5 d); 6. class Numar { int nr; Numar(int nr) { this.nr=nr;} int valoare () { return nr;} boolean impar() { if (nr%2==1) return true; else return false;} 168 Bazele programării în Java boolean prim () { boolean p=true; for (int i=2;i<=Math.sqrt(nr);i++) if (nr%i==0) { p=false; break;} return p; } int succesor() {return nr+1;} } class Par extends Numar { Par(int nr) { super(nr);} int succesor() { return nr+2;} } class Impar extends Numar { Impar(int nr) { super(nr);} int succesor() { return nr+2;} } class Prim extends Impar { Prim(int nr) { super(nr);} int succesor() { Numar val=new Numar(nr+2); while (!val.prim()) val=new Numar(val.succesor()); return val.valoare(); } } public class test { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); Numar x=new Numar(n); if (x.prim()) x=new Prim(x.valoare()); else if (x.impar()) x=new Impar(x.valoare()); else x=new Par(x.valoare()); System.out.println(x.succesor());} } 7. b); 8. d); 9. public class test { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); functie f=new f1(); System.out.println(funct(f ,n)); f=new f2(); System.out.println(funct(f ,n)); f=new f3(); System.out.println(funct(f ,n)); } public static int funct(functie ref, int x) { return ref.f(x);} } CAPITOLUL 8 Excepţii try {……………} catch (ER1 ob1) {……………} [ catch (ER2 ob2) {…………} catch (ER3 ob3) {…………} ... catch (ERn obn) {………} ] [ finally {……………}] Din cuprins: Noţiunea de excepţie Mecanismul de tratare a excepţiilor Metode de tratare a excepţiilor Exemple de tratare a excepţiilor Probleme propuse 170 Bazele programării în Java 8.1. Noţiunea de excepţie Prin excep]ie vom \n]elege o situa]ie nedorit` \n care poate ajunge un program \n timpul rul`rii. Exist` nenum`rate exemple de excep]ii: se dore[te citirea unui num`r natural, dar din gre[eal`, utilizatorul introduce un caracter; datele introduse pentru diverse c@mpuri nu sunt \n plaja de valori admis` pentru c@mpul respectiv; un vector are n componente (indicii sunt de la 0 la n-1) [i se \ncearc`, de exemplu, s` se atribuie o valoare componentei de indice n; se \ncearc` deschiderea unui fi[ier inexistent; ... Pentru a rezolva astfel de situa]ii, \n Java exist` un mecanism extrem de bine pus la punct (mecanism de tratare a excep]iilor). 8.2. Mecanismul de tratare a excepţiilor Pentru a prezenta acest mecanism vom porni de la un exemplu extrem de simplu, at@t de simplu \nc@t ar putea fi tratat f`r` probleme [i \n absen]a acestuia. Exemplu: s` se citeasc` [i s` se afi[eze un num`r natural 1n5. Practic, problema se reduce la citirea unui \ntreg [i afi[area lui. Dar, \n timpul execut`rii, din gre[eal`, se poate introduce o valoare numeric` care nu este \ntre aceste valori. Cum proced`m, altfel dec@t \n mod clasic? Privi]i exemplul urm`tor, \n care, dac` num`rul citit este \ntre 1 [i 5, acesta este afi[at, altfel se afi[eaz` mesajul 1<=n<=5. class Eroare extends Exception { void afis() { System.out.println("1<=n<=5"); } } class t { public static int citesc() throws Eroare { int n=Integer.parseInt(cin.Token()); if (n>=1 && n<=5) return n; else throw new Eroare(); } Capitolul 8. Excepţii 171 public static void main(String[] args) { try { int numar=citesc(); System.out.println(numar);} catch (Eroare er) {er.afis();} } } a) Clasa Eroare extinde clasa Exception (este obligatoriu s` fie precizat` aceast` extensie. Ea con]ine o singur` metod`, void afis(), care are rolul de a afi[a mesajul de eroare. b) La sf@r[itul antetului metodei int citesc() se g`se[te cuv@ntul cheie throws, urmat de numele clasei care trateaz` eroarea respectiv`. Prin aceasta se anun]` c` respectiva metod` poate \ntoarce fie un \ntreg (\n caz de introducere reu[it` a datelor, fie o referin]` c`tre un obiect al clasei Eroare (\n caz de introducere nereu[it` a datelor). Iat`, deci, c` \n acest caz, metodele pot \ntoarce [i date de alt tip dec@t cel dat de tipul metodei ! Acest aspect este esen]ial. Instruc]iunea throw returneaz` referin]a c`tre un obiect al clasei Eroare. c) Utilizarea metodei citesc() se face, \n mod obligatoriu, cu ajutorul instruc]iunii try (\ncearc`). Secven]a unde poate ap`rea excep]ia, se g`se[te \n instruc]iunea compus` subordonat` lui try (\n exemplu int numar=citesc()). Dac` citirea reu[e[te, programul \[i \ncheie execu]ia, altfel, se verific` dac` obiectul \ntors de metod` este de tip Eroare (vezi clauza catch). |n caz afirmativ, se execut` metoda afis() a acestui obiect (er este referin]a c`tre obiect). |n sintez`, putem afirma: clauza throws are rolul de a specifica faptul c` o metod` poate \ntoarce [i referin]e c`tre obiectele altor clase (dac` extind clasa Exception). Dac` sunt mai multe clase, atunci numele acestora sunt separate prin virgul`. instruc]iunea throw - returneaz` referin]a c`tre unul din obiectele claselor trecute dup` clauza throws. instruc]iunea try are forma general` (ceea ce este trecut \ntre paranteze drepte este facultativ): try { secven]a de instruc]iuni care pot conduce c`tre excep]ii } catch (ER1 ob1) { secven]a care trateaz` excep]ia cu clasa Er1 } [ catch (ER2 ob2) { secven]a care trateaz` catch (ER3 ob3) { secven]a care trateaz` ... catch (ERn obn) { secven]a care trateaz` [ finally { secv. se execut` indiferent dac` excep]ia cu clasa Er2 } excep]ia cu clasa Er2 } excep]ia cu clasa Ern } ] a fost eroare sau nu}] 172 Bazele programării în Java Exemplu: extindem, ce-i drept, \n mod artificial exemplul anterior. Pentru cele dou` excep]ii (n<1 [i n>5) vom utiliza dou` metode diferite aflate \n clase diferite (Eroare1 [i Eroare2). |n acest caz metodele sunt de tip constructor, deci corpurile catch sunt vide. class Eroare1 extends Exception { Eroare1() { System.out.println("1<=n");} } class Eroare2 extends Exception { Eroare2() { System.out.println("n<=5");} } class t { public static int citesc() throws Eroare1,Eroare2 { int n=Integer.parseInt(cin.Token()); if (n<1) throw new Eroare1(); else if (n>5) throw new Eroare2(); else return n; } public static void main(String[] args) { try { int numar=citesc(); System.out.println(numar); } catch (Eroare1 er1) {} catch (Eroare2 er2) {} } } 1. Una dintre ra]iunile existen]ei unui mecanism de tratare a excep]iilor este dat` de faptul c`, \n anumite cazuri, excep]ia poate fi tratat` \n mod corespunz`tor, dup` care secven]a se poate relua (f`r` ca programul s`-[i \ncheie execu]ia). Revenim asupra exemplului dat, \n care se citesc numere naturale din intervalul [1,5]. Programul urm`tor cite[te [i afi[eaz` un vector cu 3 astfel de componente. |n momentul \n care s-a introdus un num`r gre[it citirea se reia. Programul \[i \ncheie execu]ia atunci c@nd au fost citite toate cele 3 componente ale vectorului. class Eroare extends Exception { void afis() { System.out.println("1<=n<=5");} } class e { public static int citesc() throws Eroare { int n=Integer.parseInt(cin.Token()); if (n>=1 && n<=5) return n; else throw new Eroare(); } Capitolul 8. Excepţii 173 public static void main(String[] args) { int[] V=new int[3]; for (int i=0;i<3;i++) try { V[i]=citesc();} catch (Eroare er) { er.afis(); i--; } System.out.println("Am citit"); for (int i=0;i<3;i++) System.out.print(V[i]+" "); } } 2. Dac` clasa care trateaz` excep]ia extinde clasa Exception, atunci este obligatoriu ca apelul metodei ce poate returna o excep]ie s` se fac` \n construc]ia try, ca \n exemplul anterior, sau metoda care apeleaz` o astfel de metod` s` con]in` \n antet clauza throws. Exemplul 1: dac` \n metoda main() de mai sus, am avea V[]=citesc(), f`r` construc]ia try, atunci am primi eroare de compilare. Exemplul 2. citesc() poate fi apelat` ca mai jos, unde metoda main() con]ine clauza throws. Oricum, \n acest caz, dac` num`rul nu este \n intervalul [1.5] excep]ia este tratat` printr-un mesaj implicit, \n care se precizeaz` numele clasei c`reia \i apar]ine obiectul returnat. public static void main(String[] args) throws Eroare{ System.out.println(citesc());} Clasa Exception con]ine (printre altele): un constructor implicit (f`r` parametru): Exception(); un constructor cu parametru de tip String: Exception(String mes); o metod` care returneaz` String getMessage(). mesajul mes, primit de constructor: Exemplu: |n aceste condi]ii, programul din exemplul anterior poate fi scris [i ca mai jos (mai simplu): class e { public static int citesc() throws Exception { int n=Integer.parseInt(cin.Token()); if (n>=1 && n<=5) return n; else throw new Exception("1<=n<=5"); } public static void main(String[] args) { int[] V=new int[3]; for (int i=0;i<3;i++) try { V[i]=citesc();} catch (Exception er) {i--; System.out.println(er.getMessage());} System.out.println("Am citit"); for (int i=0;i<3;i++) System.out.print(V[i]+" "); } } 174 Bazele programării în Java Uneori, este deranjant faptul c` instruc]iunea capabil` s` produc` o excep]ie trebuie pus` automat sub try, iar clasa c`reia \i apar]ine trebuie s` con]in` clauza throws. Mai mult, chiar \n Java exist` metode care pot produce excep]ii, dar care pot fi folosite f`r` try. De exemplu, metoda parseInt a clasei Integer. Privi]i programul urm`tor, \n care dac` [irul de caractere introdus poate fi convertit c`tre un \ntreg se afi[eaz` num`rul, altfel programul se termin` cu excep]ie. {i toate acestea f`r` try... class e { public static void main(String[] args) { int n=Integer.parseInt(cin.linie()); } } S` analiz`m antetul complet al metodei parseInt: public static int parseInt(String s) throws NumberFormatException Observ`m faptul c`, \n cazul \n care apare o excep]ie, se apeleaz` la clasa NumberFormatException. De aici, putem deduce o prim` observa]ie: dac` dorim ca programul nostru s` furnizeze un mesaj \n caz de excep]ie, putem proceda ca mai jos, adic` s` folosim construc]ia try, [i \n caz c` se returneaz` un obiect al clasei NumberFormatException, s` afi[`m un mesaj de eroare l`muritor. class e { public static void main(String[] args) { System.out.print("n="); int n=1; try { n=Integer.parseInt(cin.Token());} catch (NumberFormatException e) {System.out.println nenumerica");} System.out.println(n); } } ("Valoare Mai mult, citirea se poate efectua p@n` c@nd valoarea introdus` este corect`, ca \n programul urm`tor: class e { public static void main(String[] args) { int i=1, n=1; while (i==1) { System.out.print("n="); try { n=Integer.parseInt(cin.Token()); i=0;} catch (NumberFormatException e) { System.out.println ("Valoare nenumerica");} } System.out.println(n); } } Capitolul 8. Excepţii 175 Dac` \n secven]a subordonat` lui try se depisteaz` o excep]ie, se abandoneaz` executarea tuturor instruc]iunilor. |n exemplu, aceasta implic` faptul c` i r`m@ne 1, deci se reia secven]a subordonat` lui while. Dac` nu a ap`rut excep]ia, i devine 0 [i prin urmare, executarea lui while este considerat` \ncheiat`. Dac` nu l-am fi declarat de la \nceput pe n cu valoare ini]ial`, oricare ar fi ea, programul ar fi semnalat eroare la compilare, pentru c` se ajunge la afi[area lui. Ori, \n Java, nu este permis` afi[area con]inutului unei variabile neini]ializate. Totu[i, nu se rezolv` problema pus`: cum este posibil ca parseInt s` poat` fi folosit` f`r` construc]ia try? Obiectele claselor care extind clasa RuntimeException sau Error pot fi apelate f`r` ca antetul lor s` con]in` clauza throws, ca mai jos: class Eroare extends RuntimeException { void afis() { System.out.println("1<=n<=5");} } class e { public static int citesc() // fara throws { int n=Integer.parseInt(cin.Token()); if (n>=1 && n<=5) return n; else throw new Eroare(); } public static void main(String[] args) { ... } } Pot exista urm`toarele cazuri: a) Dac` \n main() avem secven]a de mai jos, atunci distingem dou` cazuri: int numar=citesc(); a1) Se introduce un num`r \ntre 1 [i 5 - programul nu genereaz` excep]ie [i totul este OK! a2) Se introduce un num`r \n afara intervalului. Va fi afi[at` o excep]ie \ntr-un format implicit [i nu se va afi[a mesajul "1<=n<=5". b) Dac` \n main() avem secven]a: try { int numar=citesc(); System.out.println(numar); } catch (Eroare er) { er.afis();} 176 Bazele programării în Java b1) Se introduce un num`r \ntre 1 [i 5 - programul nu genereaz` excep]ie [i totul este OK! b2) Se introduce un num`r \n afara intervalului. Va fi afi[at` excep]ia cu mesajul "1<=n<=5". 8.3. Metodele care pot returna, în caz de excepţii, obiecte ale unor alte clase Privi]i antetul metodei parseInt a clasei Integer. Din considerente didactice, p@n` acum antetul nu a fost prezentat integral. |n cazul \n care se \nt@lne[te o excep]ie, se returneaz` un obiect al clasei NumberFormatException: public static int parseInt(String s) throws NumberFormatException Aceasta poate ajuta programatorul s` “gestioneze” situa]ia, ca \n exemplul de mai jos, unde se cite[te o variabil` \ntreag` care este afi[at`. |n cazul \n care valoarea introdus` nu este corect`, se reia citirea. class e { public static void main(String[] args) { int i=0; while (i==0) try { int numar=Integer.parseInt(cin.Token()); System.out.println(numar); i=1; } catch (NumberFormatException e) { System.out.println("Numar eronat");} } } Iat` si antetul complet al metodelor parseFloat [i parseDouble: 1. public static double parseDouble(String s) throws NumberFormatException 2. public static float parseFloat(String s) throws NumberFormatException |n cazul \mp`r]irii la 0 pentru tipuri \ntregi, se returneaz` un obiect al clasei ArithmeticException. Vede]i exemplul urm`tor: Capitolul 8. Excepţii 177 class t { public static void main(String[] args) { System.out.print("n="); int n=Integer.parseInt(cin.Token()); System.out.print("m="); int m=Integer.parseInt(cin.Token()); try { System.out.println(n/m);} catch (ArithmeticException e) { System.out.println ("Impartire la 0 ");} } } |n cazul \n care se \ncearc` s` se atribuie o valoare unei componente inexistente a unui vector, se returneaz` pentru tipuri \ntregi un obiect al clasei ArrayIndexOutOfBoundsException. Vede]i exemplul urm`tor: class t { public static void main(String[] args) { int []v=new int[3]; System.out.print("indice="); int indice=Integer.parseInt(cin.Token()); try { v[indice]=1;} catch (ArrayIndexOutOfBoundsException e) { System.out.println ("Eroare indice");} } } Observa]ie foarte important` Clasele ArrayIndexOutOfBoundsException, ArithmeticException ca [i multe altele de acest tip, sunt rezultate \n urma unor deriv`ri ale clasei Exception. Cum un parametru de tip referin]` c`tre un obiect al superclasei poate re]ine referin]e c`tre obiectele subclaselor sale, atunci putem scrie clauza catch de forma: catch (Exception e) {...} 8.4. Exemple de tratare a excepţiilor 1. Validare pentru numere reale. S` se scrie un program care cite[te n, num`r natural [i n numere reale. Se cere s` se calculeze suma numerelor citite. Dac` un num`r real se introduce gre[it (nu respect` formatul de num`r real) se reia citirea lui. Rezolvare. Metoda parseDouble, a clasei Double, returneaz` fie un num`r de format double, fie un obiect al clasei NumberFormatException. class e { public static void main(String[] args) { double s=0; System.out.print("n="); int n=Integer.parseInt(cin.Token()); 178 Bazele programării în Java for (int i=0;i<n;i++) try { double x=Double.parseDouble(cin.Token());s+=x;} catch (NumberFormatException e) { System.out.println("Numar eronat");i--;} System.out.println("S="+s); } } 2. Validare alfabetic`. Se cite[te un [ir de caractere alc`tuit din mai multe cuvinte separate prin blank-uri. Dac` [irul citit con]ine numai literele alfabetului (mici sau mari) sau blank-uri, acesta se va afi[a, altfel se va tip`ri mesajul sir nealfabetic. Rezolvare. Metoda citSir() cite[te [irul [i \l valideaz`. Dac` [irul este valid, el este returnat, altfel se returneaz` un obiect al clasei Nealfabetic. |n main() se testeaz` dac` a fost retrunat [irul (try), caz \n care acesta este afi[at, sau a fost returnat un obiect al clasei Nealfabetic, caz \n care se afi[eaz` mesajul de eroare sir nealfabetic prin utilizarea metodei mesaj() a obiectului. class Nealfabetic extends RuntimeException { String mesaj() { return "sir nealfabetic"; } } class e { static String citSir() { String sir=new String(cin.linie()); boolean gasit=false; for (int i=0;i<sir.length();i++) if ( (sir.charAt(i)<'A' || sir.charAt(i)>'Z') && (sir.charAt(i)<'a' || sir.charAt(i)>'z') && sir.charAt(i)!=' ') gasit=true; if (gasit) throw new Nealfabetic(); else return sir; } public static void main(String[] args) { boolean corect=false; System.out.print("Tastati sirul "); String s=""; try { s=citSir(); System.out.println(s);} catch (Nealfabetic e) { System.out.println(e.mesaj());} } } Probleme propuse 1. Se citesc n, num`r natural [i n numere reale. Se cere s` se afi[eze suma numerelor citite. Pentru citirea numerelor, programul va utiliza mecanismul excep]iilor (\n caz de introducere gre[it` a datelor - care nu corespund formatului de num`r real, se va afi[a un mesaj corespunz`tor [i se va relua citirea numerelor). Capitolul 8. Excepţii 179 2. La fel ca mai sus numai c` cele n numere citite trebuie s` fie mai mici dec@t 10. De asemenea, se va folosi mecanismul excep]iilor at@t pentru formatul real, c@t [i pentru valorile admise. 3. Scrie]i un program care cite[te dou` numere reale a [i b [i afi[eaz` rezultatul \mp`r]irii lui a la b. Dac` ambele numere sunt 0, se va afi[a un mesaj l`muritor, dac` numai b este 0, se va tip`ri alt mesaj l`muritor, iar dac` \mp`r]irea se poate face, se va afi[a rezultatul \mp`r]irii. Evident, programul va utiliza mecanismul excep]iilor [i metode ale claselor \nf`[ur`toare (de rev`zut). 4. La fel ca mai sus numai c` se vor utiliza excep]iile [i la citirea numerelor a [i b, iar \n caz c` \mp`r]irea nu se poate efectua se va repeta citirea numerelor a [i b. Rezolvări: 1. class test { public static void main(String[] args) { int n=1; double nr=0; int semnal=0; // citesc pe n while (semnal==0) { try { System.out.print("n="); n=Integer.parseInt(cin.Token()); semnal=1;} catch (Exception e) {System.out.println("Eroare la introducerea lui n");} } // citesc cele n numere double s=0; for (int i=0;i<n;i++) { nr=0; try { System.out.print("valoarea este="); nr=Double.parseDouble(cin.Token());} catch (Exception e) { System.out.println ("Valoare nenumerica"); i--;} s+=nr;} System.out.println("Suma="+s); } } 2. class Er1 extends Exception { void afis(){System.out.println ("valoarea trebuie sa fie mai mica decat 10");} } class Er2 extends Exception { void afis(){ System.out.println ("valoarea trebuie sa fie numerica");} } 180 Bazele programării în Java class test { public static void main(String[] args) { int n=1; double nr=0; int semnal=0; // citesc pe n while (semnal==0) { try { System.out.print("n="); n=Integer.parseInt(cin.Token()); semnal=1;} catch (Exception e) {System.out.println("Eroare la introducerea lui n");} } // citesc cele n numere double s=0; for (int i=0;i<n;i++) { nr=0; try { nr=citesc();} catch (Er1 e) { e.afis(); i--;} catch (Er2 e) { e.afis(); i--;} s+=nr;} System.out.println("Suma="+s); } public static double citesc() throws Er1,Er2 { double n=0; try { n=Double.parseDouble(cin.Token());} catch (Exception e) { throw new Er2();} if (n>10) throw new Er1(); else return n; } } 3. class Er1 extends Exception { void afis() { System.out.println ("Impartire la 0");} } class Er2 extends Exception { void afis() { System.out.println ("ambii operanzi sunt 0");} } class test { public static void main(String[] args) { double s=0; System.out.print("a=");double a=Double.parseDouble(cin.Token()); System.out.print("b=");double b=Double.parseDouble(cin.Token()); try {double z=divide(a,b); System.out.println(z);} catch (Er1 e) { e.afis();} catch (Er2 e) { e.afis();} } static double divide (double a, double b) throws Er1,Er2 { if (Double.isNaN(a/b)) throw new Er2(); else if (Double.isInfinite (a/b)) throw new Er1(); else return a/b; } } CAPITOLUL 9 Alte clase esenţiale în Java Din cuprins: Clasa Vector Fişiere Fire de execuţie Probleme propuse 182 Bazele programării în Java 9.1. Clasa Vector Clasa Vector ofer` posibilitatea lucrului cu o structur` asem`n`toare vectorului, dar \n plus, ofer` posibilitatea ad`ug`rii sau [tergerii unor elemente \n interiorul vectorului. Clasa Vector se g`se[te \n pachetul java.util. Astfel, structura seam`n` mult cu o list` liniar` simplu \nl`n]uit`. Idei de baz`: Elementele vectorului sunt referin]e c`tre obiecte, de orice tip dorim. Aten]ie, am spus referin]e c`tre obiecte [i nu tipuri primitive. Pentru tipurile primitive exist` acele clase \nf`[ur`toare, pe care v` sf`tuiesc s` le revede]i. La baza ierarhiei arborescente a claselor din Java se g`se[te clasa Object. Aceasta \nseamn` c` o variabil` de tip referin]` c`tre un obiect al clasei Object poate re]ine orice referin]` c`tre un obiect al unei clase descendente. Prin urmare, un element al “vectorului” poate re]ine o referin]` c`tre orice alt tip de obiect. De aici rezult` faptul c` printr-un obiect al clasei Vector se pot manipula obiecte de orice tip. Principalele metode ale clasei Vector sunt: Vector() - constructor ce creeaz` un vector f`r` nici un element (vector vid). void addElement (Object O); - adaug` la sf@r[itul vectorului un element care re]ine o referin]` c`tre un anumit obiect. Object elementAt(i) - returnaz` referin]a c`tre obiectul re]inut de componenta de indice i a vectorului. Object firstElement() - returneaz` referin]a c`tre primul element al vectorului. Object lastElement() - returneaz` referin]a c`tre ultimul element al vectorului. int size() - returneaz` num`rul de componente ale vectorului. void insertElementAt(Object O, int i) - insereaz` un obiect \n vector pe pozi]ia i. Celelalte elemente ale vectorului sunt deplasate c`tre dreapta cu o pozi]ie. Pozi]ia i trebuie s` fie cuprins` \ntre 0 [i size()-1. void removeElementAt(int i) - [terge un element al vectorului aflat pe pozi]ia i. Celelalte elemente ale vectorului sunt deplasate c`tre st@nga cu o pozi]ie. Pozi]ia i trebuie s` fie cuprins` \ntre 0 [i size()-1. Capitolul 9. Alte clase esenţiale în Java 183 setElementAt(Object O,int i) - seteaz` componenta de indice i s` re]in` o referin]` c`tre un nou obiect. Vechiul obiect a c`rui pozi]ie era re]inut` de componenta i se pierde. Pozi]ia i trebuie s` fie cuprins` \ntre 0 [i size()-1. void removeAllElements() - [terge toate elementele vectorului. void removeElement(Object O) - [terge componenta care are ca referin]` un obiect identic cu cel transmis prin parametru. Toate celelalte componente ale vectorului sunt deplasate c`tre st@nga. int indexOf(Object obiectului \n vector. O) – \ntoarce indicele primei apari]ii a Exemplu: \n programul urm`tor se citesc [i se afi[eaz` n numere naturale. Cele n numere naturale sunt re]inute de un obiect al clasei Vector. import java.util.*; class t { public static void main(String[] args) { Vector v=new Vector(); System.out.print("n="); int n=Integer.parseInt(cin.Token()); for (int i=0;i<n;i++) { System.out.print("V["+i+"]="); int valoare=Integer.parseInt(cin.Token()); v.addElement(new Integer(valoare)); } for (int i=0;i<n;i++) { Integer val=(Integer)v.elementAt(i); System.out.println(val.intValue());} } } Observa]ii asupra programului: a) Elementele vectorului sunt referin]e c`tre obiecte ale clasei Integer. Fiecare obiect al clasei Integer re]ine un num`r citit. int valoare=Integer.parseInt(cin.Token()); v.addElement(new Integer(valoare)); b) La citire se returneaz` referin]a c`tre obiectul de tip Integer. Deoarece, de fapt, un element al vectorului re]ine o referin]` c`tre un obiect de tip Object, referin]a este convertit` c`tre referin]` c`tre Integer. Integer val=(Integer)v.elementAt(i); Pentru a afi[a num`rul citit, se utilizeaz` metoda intValue() a clasei Integer, metod` care returneaz` valoarea re]inut` de obiect. System.out.println(val.intValue()); Liniile de la observa]iile 3 [i 4 pot fi \nlocuite cu linia de mai jos: System.out.println(((Integer)v.elementAt(i)).intValue()); 184 Bazele programării în Java 9.2. Fişiere 9.2.1. Noţiunea de flux |n Java, fi[ierele sunt abordate pornind de la no]iunea de flux. Prin flux vom \n]elege o cale pe care o urmeaz` datele pentru a ajunge de la surs` la destina]ie. Putem imagina un flux ca o [osea pe care circul` ma[ini. Astfel, \n Java, datele ar fi ma[inile care circul` pe [osea. Exist` dou` tipuri de fluxuri: A) Fluxuri de intrare - de la surs` (un fi[ier), c`tre destina]ie (programul), unde datele sunt prelucrate. fi[ier program Sursa Destinatie B) Fluxuri de ie[ire - de la surs`, (programul), c`tre destina]ie (fi[ier), unde se re]in rezulatatele.. program Sursa fi[ier Destinatie Clasele pe care le studiem \n acest paragraf se g`sesc \n pachetul java.IO. 9.2.2. Fluxuri de octeţi |n acest caz, datele sunt date de octe]i. A) Fluxurile de intrare sunt tratate de clasa FileInputStream. Sursa este dat` de un fi[ier, iar destina]ia este memoria. Principalele metode ale clasei FileInputStream sunt: 1. Constructorul - are rolul de a deschide fi[ierul al c`rui nume este dat de parametrul de tip String. |n cazul \n care fi[ierul nu este g`sit (excep]ie), se returneaz` un obiect al clasei FileNotFoundException. public FileInputStream(String nume) throws FileNotFoundException 2. Citirea unui octet se realizeaz` cu metoda read(): public int read() throws IOException 3. |nchiderea fi[ierului se realizeaz` cu metoda close(): public void close() throws IOException Capitolul 9. Alte clase esenţiale în Java 185 Observa]ii: Clasa IOException este o subclas` a clasei Exception. Prin urmare, orice metod` care apeleaz` o alt` metod` care poate returna un obiect al acestei clase trebuie s` aib` \n antet clauza throws sau apelul s` fie f`cut sub try (vezi excep]ii). Numele fi[ierului poate con]ine [i calea c`tre el. Aceasta trebuie pus` \n cazul \n care programul nu se g`se[te \n acela[i folder cu fi[ierul. Exemple: 1. Crea]i \n Notepad un fi[ier text oarecare, s`-l numim in.txt. El va con]ine un text oarecare, scris pe mai multe linii. Scrie]i un program care afi[eaz` con]inutul fi[ierului. import java.io.*; public class f { public static void main (String[ ] args) throws IOException { FileInputStream f=new FileInputStream("in.txt"); int ch=0; while ((ch=f.read())!=-1) System.out.print((char)ch); } } Sf@r[itul unui fi[ier se detecteaz` prin faptul c` ultimul octet re]ine -1. 2. Programul urm`tor are acela[i efect ca [i cel precedent, dar fi[ierul de intrare se g`se[te pe C:\, iar \n cazul \n care fi[ierul nu este g`sit, se afi[eaz` un mesaj corespunz`tor: import java.io.*; public class f { public static void main (String[ ] args) { try { FileInputStream f=new FileInputStream("C:\\in.txt"); int ch=0; while ((ch=f.read())!=-1) System.out.print((char)ch); } catch (IOException e) {System.out.println("Fisier negasit"); } } } B) Fluxurile de ie[ire sunt tratate de clasa FileOutputStream. Sursa este dat` de o variabil` de tip int a programului, iar destina]ia este un fi[ier. Principalele metode ale clasei FileOutputStream sunt: 1. Constructorul - are rolul de a deschide fi[ierul al c`rui nume este dat de parametrul de tip String [i de a-l preg`ti pentru scriere: public FileOutputStream(String name) throws FileNotFoundException 186 2. Bazele programării în Java Scrierea unui octet se realizeaz` cu metoda write(): public void write(int b) throws IOException 3. |nchiderea fi[ierului se realizeaz` cu metoda close(): public void close() throws IOException Exemplu: programul de mai jos copiaz` fi[ierul in.txt. Fi[ierul rezultat \n urma copierii se nume[te out.txt [i se g`se[te \n acela[i folder cu sursa. import java.io.*; public class f { public static void main (String[ ] args) throws IOException { FileInputStream f=new FileInputStream("javac.exe"); FileOutputStream g=new FileOutputStream("javac1.exe"); int ch=0; while ((ch=f.read())!=-1) g.write(ch); f.close(); g.close(); } } Observa]ii: Deschide]i fi[ierul astfel ob]inut cu Notepad. Ve]i observa c` nu exist` nici o modificare fa]` de precedentul. Cu acest procedeu se pot copia [i executabilele. Testa]i. Copia]i un executabil [i apoi, fi[ierul astfel ob]inut \l lansa]i \n executare. Evident, noul fi[ier trebuie s` aib` extensia .exe. 9.2.3. Fluxuri de caractere Vom utiliza fluxuri de caractere pentru a lucra cu fi[iere text. Acestea pot con]ine una sau mai multe linii. A) Fluxuri de intrare - se folosesc pentru citirea fi[ierelor text. Pentru a transforma un flux de octe]i \ntr-un flux de caractere, vom utiliza constructorul clasei InputStreamReader (care extinde clasa Reader): public InputStreamReader(InputStream in) |ntruc@t clasa FileInputStream extinde clasa InputStream, parametrul in (de tip InputSTream) poate fi o referin]` c`tre un obiect al clasei FileInputStream. Capitolul 9. Alte clase esenţiale în Java 187 Pentru a putea lucra cu u[urin]` cu caracterele, vom utiliza clasa BufferedReader care permite ata[area fluxului de caractere a unei memorii, numit` buffer. Practic, buffer-ul permite memorarea mai multor caractere citite, care urmeaz` s` fie prelucrate. Constructorul clasei BufferedReader este: public BufferedReader(Reader in1) |ntruc@t clasa InputStreamReader extinde clasa Reader, parametrul in1 poate fi o referin]` c`tre un obiect al clasei InputStreamReader. Clasa BufferedReader con]ine metoda readLIne() care cite[te din fi[ier (flux) o \ntreag` linie de caractere: public String readLine() throws IOException Acestea fiind spuse, pute]i analiza programul de mai jos care afi[eaz` toate liniile unui fi[ier text. De exemplu, dac` crea]i cu Notepad un fi[ier cu mai multe linii, numit in.txt, programul \l afi[eaz`: import java.io.*; public class f { public static void main (String[ ] args) throws IOException { FileInputStream f=new FileInputStream("in.txt"); InputStreamReader fchar=new InputStreamReader (f); BufferedReader buf = new BufferedReader(fchar); String linie; while ((linie=buf.readLine() )!=null) System.out.println(linie); fchar.close(); } } B) Fluxuri de ie[ire - se folosesc pentru scrierea fi[ierelor text. Clasa FileOutputStream creeaz` un flux de ie[ire c`tre un fi[ier al c`rui nume este transmis ca parametru. Ea extinde clasa OutputStream [i are constructorul: public FileOutputStream(String nume) throws FileNotFoundException Clasa PrintStream con]ine mai multe metode print [i println care func]ioneaz` exact ca System.out.print() [i System.out.print(). Practic, valoarea care este scris` \n fi[ier este mai \nt@i convertit` c`tre tipul String, a[a cum suntem deja obi[nui]i. Clasa este \nzestrat` cu constructorul: public PrintStream(OutputStream out) 188 Bazele programării în Java Exemplu: programul de mai jos creeaz` un fi[ier text (numit out.txt) care con]ine 3 linii, iar fiecare linie con]ine c@te un [ir de caractere: import java.io.*; public class f { public static void main (String[ ] args) throws IOException { FileOutputStream f=new FileOutputStream("out.txt"); PrintStream fchar=new PrintStream (f); fchar.println("O linie"); fchar.println("Alta linie"); fchar.print("A treia linie"); fchar.close(); } } 9.2.4. Intrări de la tastatură Pentru a gestiona intr`rile de la tastatur`, \n program se utilizeaz` constanta de tip in a clasei System. Practic, ea re]ine referin]a c`tre fluxul de intrare de la tastatur` (acesta din urm` este de tipul InputStream). public static final InputStream in Cel mai bun exemplu de utilizare a acestei clase este dat de metoda linie() a clasei cin (cea pe care am folosit-o de at@tea ori p@n` acum). import java.io.*; import java.util.*; class cin { static InputStreamReader f = new InputStreamReader (System.in); static BufferedReader tamp=new BufferedReader(f); static String linie() { try { return tamp.readLine();} catch (IOException e) { return ("Eroare");} } static String Token(){ StringTokenizer v=new StringTokenizer(linie()); if (v.hasMoreTokens())return v.nextToken(); else return""; } } 9.3. Fire de execuţie A]i observat, probabil, c` \n anumite programe apar mai multe cadre \n care se afi[eaz` anumite anima]ii. V` da]i seama c` fiecare anima]ie trebuie executat` separat. Imagina]i-v` c` un program con]ine, s` zicem, 6 astfel de anima]ii. Aparent, fiecare dintre ele se execut` independent. Cum a fost scris acel program? Capitolul 9. Alte clase esenţiale în Java 189 Dac` acel program a fost scris \n Java, atunci s-au utilizat firele de execu]ie. Practic, un fir de execu]ie \nseamn` o secven]` de instruc]iuni. Procesorul \[i \mparte timpul pentru a executa o parte dintr-un fir de execu]ie, apoi o parte din alt fir de execu]ie, [.a.m.d. Mai mult, de c@te ori el trebuie s` intre \n a[teptare pentru un fir de execu]ie (de exemplu, se a[teapt` introducerea unei date), reia executarea altui fir de execu]ie, [.a.m.d. V` da]i seama c` un astfel de mecanism este extrem de complex, dar \n Java se poate folosi cu u[urin]` pentru c` acesta este foarte bine pus la punct. Ce trebuie s` [tim pentru a crea fire de execu]ie? 1. Un fir de execu]ie este (mo[tene[te) clasa Thread. un obiect al unei clase care extinde 2. Secven]a de instruc]iuni a acestui fir de execu]ie este con]inut` de metoda run() a clasei. 3. Un fir de execu]ie se lanseaz` utiliz@nd metoda start() a clasei din instan]ierea c`reia a rezultat firul de execu]ie respectiv. Evident, metoda start() este mo[tenit` din clasa Thread. 4. Un fir de execu]ie poate fi pus \n a[teptare prin utilizarea metodei sleep(long m), metod` mo[tenit` de la clasa Thread. Ea poate genera o excep]ie, a[a c` trebuie pus` sub construc]ia try. Evident, \n acest timp, procesorul poate relua executarea unui alt fir de execu]ie. Timpul este dat \n milisecunde. Exemple: 1. Programul urm`tor con]ine un fir de execu]ie, care incrementeaz` valoarea unei variabile (date membru) apoi o afi[eaz`, dup` care st` \n a[teptare o secund`, [.a.m.d., p@n` c@nd valoarea variabilei devine mai mare dec@t 10: class Fir extends Thread { int i=0; public void run() { while (i!=10) { i++; System.out.println("i="+i); try { sleep(1000);} catch (Exception e) {} } } } public class pv { public static void main(String args[]) { Fir x=new Fir(); x.start(); } } 190 Bazele programării în Java 2. Programul urm`tor con]ine dou` fire de execu]ie. Fiecare dintre ele afi[eaz` valoarea unei variabile locale. Se va afi[a i=1, j=1, i=2, j=2, [.a.m.d. Observa]i puterea firelor de execu]ie. Practic, c@nd un fir de execu]ie este \ntrerupt, se salveaz` valoarea variabilelor locale [i se memoreaz` punctul \n care firul a fost \ntrerupt. class Fir extends Thread { public void run() { int i=0; while (i!=10) { i++; System.out.println("i="+i);} } } class AltFir extends Thread { public void run() { int j=0; while (j!=10) { j++; System.out.println("j="+j);} } } public class pv { public static void main(String args[]) { Fir x=new Fir(); AltFir y=new AltFir(); x.start(); y.start(); } } Probleme propuse 1. Implementa]i o stiv` prin utilizarea clasei Vector. Avantajul acestei implement`ri este evident: se poate utiliza stiva pentru a re]ine orice tip de obiect. 2. Memora]i \n stiva astfel ob]inut` 3 numere \ntregi [i afi[a]i-le \n ordinea extragerii. 3. Memora]i \n stiva astfel ob]inut` n [iruri de caractere citite de la tastatur` [i afi[a]i-le \n ordinea extragerii. 4. Crea]i o \nregistrare care re]ine pentru o persoan` numele [i vârsta. Citi]i datele pentru n astfel de persoane, ad`uga]i-le \n stiv` [i afi[a]i-le \n ordinea extragerii. 5. Implementa]i o coad` prin utilizarea clasei Vector. Capitolul 9. Alte clase esenţiale în Java 191 6. Reface]i problemele de la 2 la 4 prin utilizarea structurii de tip coad`. 7. Fi[ierul text numere.in con]ine pe prima linie mai multe numere naturale. Care este suma lor? 8. Fi[ierul text numere.in con]ine pe prima linie mai multe numere naturale, dar [i alte [iruri de caractere. Numerele sunt separate prin spa]ii de celelalte [iruri de caractere (vezi exemplul de mai jos). Care este suma lor? Exemplu: 1 asf 12 JKHS 17 aha 10 ngsvss 5 se afi[eaz` 45. 9. Reface]i programul de la problema 9, astfel \nc@t numele fi[ierului s` fie preluat de linia de comand` din fereastra CMD. Indicaţii / rezolvări: 1. import java.util.*; class Stiva { Vector st=new Vector(); void push(Object x) { st.addElement (x);} Object pop () { if (st.size()>0) { Object retur=st.lastElement(); st.removeElementAt(st.size()-1); return retur; } else return null; } } 2. class test { public static void main(String[] args) { Stiva st=new Stiva(); st.push(new Integer (1)); st.push(new Integer (2)); st.push(new Integer (3)); Integer numar; do { numar=(Integer)st.pop(); if (numar!=null) System.out.println(numar.intValue()); } while (numar!=null); } } 192 Bazele programării în Java 7. import java.io.*; import java.util.*; public class test { public static void main (String[ ] args) throws IOException { FileInputStream f=new FileInputStream("numere.in"); InputStreamReader fchar=new InputStreamReader (f); BufferedReader buf = new BufferedReader(fchar); String linie=buf.readLine(); StringTokenizer t=new StringTokenizer(linie); int s=0; while (t.hasMoreTokens()) s+=Integer.parseInt(t.nextToken()); System.out.println(s); fchar.close(); } } 8. import java.io.*; import java.util.*; public class test { public static void main (String[ ] args) throws IOException { FileInputStream f=new FileInputStream("numere.in"); InputStreamReader fchar=new InputStreamReader (f); BufferedReader buf = new BufferedReader(fchar); String linie=buf.readLine(); StringTokenizer t=new StringTokenizer(linie); int s=0; int nr; while (t.hasMoreTokens()) try { nr=Integer.parseInt(t.nextToken()); s+=nr;} catch (Exception e) {} System.out.println(s); fchar.close(); } } 9. ... public static void main (String[ ] args) throws IOException { if (args.length==0) System.out.println ("Fisierul?"); else { String nume_f=args[0]; FileInputStream f=new FileInputStream(nume_f); ... CAPITOLUL 10 Iniţiere în programarea vizuală Din cuprins: Prima fereastră Mecanismul prin care se ataşează componente ferestrei. Clasa Container Clasele JComponent şi ToolKit Poziţionarea componentelor Studiul principalelor componente Mai mult despre clasa Container Cutii de dialog Clasele Graphics şi Graphics2D Evenimente Animarea imaginilor Probleme propuse 194 Bazele programării în Java 10.1. Prima fereastră O fereastr` este un obiect al clasei JFrame. Clasa JFrame este re]inut` \n pachetul javax.swing. Mai jos pute]i observa un program care afi[eaz` o fereastr`: import javax.swing.*; public class pv { public static void main(String args[]) { JFrame fer=new JFrame("Prima mea fereastra"); fer.setSize(200,300); fer.setLocation(300,400); fer.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); fer.setVisible(true); } } S` observ`m c` fereastra con]ine meniul implicit, poate fi maximizat`, minimizat` (adus` pe bara de task-uri), dar poate fi [i \nchis`. Din analiza programului deducem c@teva metode pe care le are clasa JFrame: JFrame() - constructor. Dac` o fereastr` este creat` printr-un astfel de constructor ea apare f`r` titlu. JFrame(String titlu) - constructor. Construie[te o fereastr` care afi[eaz` un anumit titlu (\n exemplu, Prima mea fereastra). void setSize(int width, int height) - stabile[te l`]imea [i \n`l]imea ferestrei. void setLocation (int x, int y) - stabile[te pozi]ia unde va fi afi[at col]ul din st@nga sus al ferestrei ([i implicit pozi]ia ferestrei), \n raport cu col]ul din st@nga sus al ecranului. Parametrul x precizeaz` distan]a pe orizontal` a col]ului ferestrei, iar y distan]a pe vertical` a acestuia (ambele sunt date \n pixeli). void setDefaultCloseOperation(int a) - stabile[te ce se \nt@mpl` atunci c@nd se \nchide fereastra (s-a p`strat acel buton x). Parametrii sunt constante de tip \ntreg ale clasei. Cea mai important` constant` este EXIT_ON_CLOSE [i prin ea, se cere \nchiderea ferestrei [i \ncheierea execu]iei programului. void setResizable(boolean ac) - dac` parametrul este false nu se pot modifica dimensiunile ferestrei. setVisible(boolean x) - stabile[te dac` fereastra este vizibil` (apare pe ecran) sau nu (de[i exist`, nu este afi[at`). Capitolul 10. Iniţiere în programarea vizuală 195 Dac` dorim s` fim eficien]i, putem construi o clas`, de exemplu numit` Fereastra, al c`rei constructor s` returneze obiectul cu toate datele de mai sus (titlul, dimensiunile ferestrei, pozi]ia sa pe ecran). Exemplu: programul de mai jos afi[eaz` o fereastr`: import javax.swing.*; class Fereastra extends JFrame { Fereastra(String Nume, int lat, int inalt, int dreapta, int stanga) { super(Nume); setSize(lat,inalt); setLocation(dreapta, stanga); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } } public class pv { public static void main(String args[]) { Fereastra f= new Fereastra ("Prima", 100,200, 25, 100);} } 10.2. Mecanismul prin care se ataşează componente ferestrei. Clasa Container Foarte important! Pentru ca unei ferestre (obiect de tip JFrame) s` i se poat` ata[a alte componente (cum ar fi butoanele, liste, etc. – care sunt obiecte de alte tipuri), este necesar ca aceasta s` con]in` o referin]` c`tre o structur` special`, care la r@ndul ei va re]ine referin]e c`tre obiectele (componentele) care sunt ata[ate ferestrei. Structura care re]ine referin]ele c`tre obiectele care se afl` pe fereastr` este un obiect al clasei Container. Al`turat putem observa ierarhia claselor din care a rezultat clasa JFrame. Prin urmare, un obiect de tip JFrame sau dintr-o subclas` a lui JFrame con]ine datele membru [i metodele clasei Container. Object Component Container Window java.awt.Frame javax.swing.JFrame Accesul la container-ul unei ferestre se face utiliz@nd o metod` a clasei JFrame, numit` getContentPane(). Container getContentPane() - returneaz` o referin]` c`tre container-ul ferestrei. Pornind de la aceast` referin]`, putem realiza dou` lucruri: 196 Bazele programării în Java 1. Putem ad`uga ferestrei componentele dorite. Pentru aceasta se folose[te metoda add() a clasei Container: Component add(Component comp) - adaug` o component` ferestrei. Important: toate componentele sunt derivate din clasa Component. Prin urmare, parametrul comp poate re]ine referin]e c`tre componente de orice tip. 2. Putem spune cum s` fie aranjate \n fereastr` componentele ad`ugate. Important: Mecanismul din Java care rezolv` aceast` problem` presupune existen]a unor a[a numi]i gestionari de pozi]ionare. Gestionarii de pozi]ionare sunt obiecte ale unor clase specifice. Ei aranjeaz` automat componentele unui container. Pentru a ata[a unui container un gestionar de pozi]ionare, se utilizeaz` metoda clasei Container numit` setLayout(): void setLayout(LayoutManager gest) - ata[eaz` unui container un gestionar de pozi]ionare. LayoutManager - este o interfa]`. To]i gestionarii de pozi]ionare pe care \i vom studia \ntr-un paragraf separat au rezultat ca urmare a implement`rii acestei interfe]e. Aceasta \nseamn` c` metoda poate fi utilizat` pentru ata[area oric`rui gestionar de pozi]ionare. Pentru \nceput, vom folosi gestionarul de pozi]ionare FlowLayout, care are un constructor f`r` parametri. Pe scurt, acesta a[eaz` componentele \n fereastr`, pe linie, una dup` alta. |n cazul \n care o linie s-a umplut, se trece la linia urm`toare. ! Clasa Container se g`se[te \n pachetul java.awt. Exemplu: programul care urmeaz` butoanelor nu are nici un efect. afi[eaz` dou` import java.awt.*; import javax.swing.*; class Fer extends JFrame { public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Buton 1"); x.add(A); JButton B=new JButton("Buton 2"); x.add(B); setVisible(true);} } public class pv { public static void main(String args[]) { Fer fp=new Fer("Doua butoane");} } butoane! Ap`sarea Capitolul 10. Iniţiere în programarea vizuală 197 Butoanele ata[ate sunt componente de tip JButton, care au un constructor de tip JButton(String s). {irul s va ap`rea pe suprafa]a butonului. 10.3. Un mecanism prin care butoanele răspund evenimentului de “apăsare” P@n` \n prezent [tim s` construim o fereastr`, [tim s`-i ata[`m unul sau mai multe butoane, dar nu [tim s` facem de a[a manier` \nc@t la “ap`sarea” butonului (click pe suprafa]a lui) s` aib` loc o anumit` ac]iune. Este exact ce ne propunem s` prezent`m \n acest paragraf. |n Java exist` o interfa]` numit` ActionListener, “ascult`torul” de evenimente de tip ActionEvent. Un exemplu de eveniment de tip ActionEvent este “ap`sarea” unui buton. Interfa]a con]ine antetul unei singure metode: actionPerformed (ActionEvent e). Pentru ca o component` s` poat` r`spunde la un eveniment de tipul ActionEvent, trebuie s` implementeze clasa ActionListener. Aceasta \nseamn` c`: 1. Clasa care include componenta (fereastra) s` con]in` clauza implements ActionListener; 2. S` fie implementat` metoda actionPerformed(). Aceast` metod` se va executa automat atunci c@nd este ap`sat butonul. Prin urmare, implementarea ei va scrie codul necesar ac]iunii dorite. ActionEvent este o clas` care con]ine metoda: String getActionCommand() - returneaz` [irul de caractere asociat componentei care a transmis evenimentul. Metoda poate fi utilizat` pentru a depista componenta care a transmis evenimentul. Exemplu: extindem programul prezentat \n paragraful anterior. C@nd se apas` un buton, \n fereastra CMD va ap`rea [irul re]inut de butonul ap`sat. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); 198 Bazele programării în Java x.setLayout(new FlowLayout ()); JButton A=new JButton("Buton 1"); x.add(A); JButton B=new JButton("Buton 2"); x.add(B); A.addActionListener(this); B.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { if( e.getActionCommand().compareTo("Buton 1")==0) System.out.println("Ai apasat Buton 1"); else System.out.println("Ai apasat Buton 2"); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Doua butoane");} } 10.4. Clasa JComponent Prin component` vom \n]elege un obiect care are o reprezentare grafic`. Exemple de componente: butoane, liste, edit-uri, etichete (am preferat denumirea lor din cursul de Tehnologia Informa]iei. Dac` o component` este obiect, \nseamn` c` o component` rezult` \n urma instan]ierii unei clase. Fiecare tip de component` pe care o vom studia rezult` \n urma instan]erii unei clase specifice ei. De exemplu, un buton rezult` \n urma instan]ierii clasei JButton, o etichet` rezult` \n urma instan]ierii clasei JLabel, un edit rezult` \n urma instan]ierii clasei JtextField, [.a.m.d. Important: clasele tuturor componentelor enumerate mai sus sunt subclase ale clasei JComponent. Aceasta \nseamn` c` putem folosi metodele clasei JComponent pentru orice component`. Clasa JComponent este descendent`, dar nu direct, a unei alte clase numit` Component. Atunci c@nd prezent`m unele metode ale clasei JComponent, care sunt mo[tenite de la clasa Component nu vom mai face referire la acest lucru, ci le vom trata ca f`c@nd parte din clasa JComponent. |n continuare prezent`m c@teva metode ale clasei JComponent: void setBackground(Color c) - metoda stabile[te culoarea de fond a componentei. S` observ`m c` parametrul ei este de tip Color. Capitolul 10. Iniţiere în programarea vizuală 199 void setForeground(Color c) - seteaz` culoarea caracterelor (\n cazul \n care componenta con]ine un text. Clasa Color con]ine anumite constante care indic` culoarea [i mai multe metode prin care se poate stabili o culoare. Exemple de constante de culoare: black, red, white, yellow, etc. De asemenea, clasa con]ine constructorul Color(float r, float g, float b) prin care se poate forma o culoare \n sistemul RGB (Red, Green, Blue), sistem studiat la tehnologia informa]iei. setFont(Font f) seteaz` font-ul cu care se scrie, stilul s`u [i m`rimea. Parametrul este un obiect al clasei Font. Clasa Font are, printre altele, constructorul: Font(String nume, int stil, int marime). unde: nume - este numele font-ului; stil - stilul. Valorile uzuale sunt: Font.ITALIC (italic), Font.BOLD (bold), Font.PLAIN (clasic). Se pot folosi [i sume, cum ar fi pentru italic [i bold: Font.ITALIC+Font.BOLD. marime - m`rimea font-ului. Exemplu: butonul cu fond ro[u, “Apasa” con]ine text scris cu verde, se utilizeaz` font-ul Arial, m`rimea 20 [i este scris italic+bold. S` observ`m faptul c` dimensiunea butonului este stabilit` automat, \n func]ie de m`rimea textului pe care \l con]ine. JButton A=new JButton("Apasa"); A.setBackground(Color.red); A.setFont(new Font("Arial",Font.ITALIC+Font.BOLD, 20)); A.setForeground(Color.GREEN); void setToolTipText(String text); - metoda seteaz` un [ir de caractere care va fi afi[at atunci c@nd cursorul mouse-ului sta]ioneaz` asupra componentei. {irul are rolul unui mesaj l`muritor despre func]ia respectivei componente. Exemplu: JButton B=new JButton("Buton 2"); B.setToolTipText("Eu sunt butonul 2"); void setEnabled(boolean v) - Face ca o component` s` fie activat` (v re]ine true) sau nu (v re]ine false). O component` dezactivat` nu mai r`spunde comenzilor [i are un aspect specific prin care utilizatorul este anun]at de faptul c` aceasta este dezactivat`. 200 Bazele programării în Java Exemplu: \n imaginea al`turat` butonul 1 este dezactivat [i butonul 2 este activat. void setVisible(boolean v) - dac` parametrul componenta este vizibil`, altfel ea este invizibil`. re]ine true, 10.5. Clasa ToolKit Se [tie faptul c` programele scrise \n Java trebuie s` ruleze independent de rezolu]ia calculatorului. O clas` care face posibil acest lucru este clasa ToolKit. |n acest sens, cele mai importante metode ale ei sunt: public static Toolkit getDefaultToolkit() - returneaz` un obiect Toolkit (con]ine date despre set`rile curente); Dimension getScreenSize() - returneaz` o referin]` c`tre un obiect de tip Dimension care con]ine lungimea (width) [i \n`l]imea (height) \n pixeli a ecranului. Exemplu: programul de mai jos creeaz` o fereastr` care, ini]ial, ocup` \ntreg ecranul. import java.awt.*; import javax.swing.*; class Fer extends JFrame { public Fer(String titlu) { super(titlu); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Toolkit ec=Toolkit.getDefaultToolkit(); Dimension dim = ec.getScreenSize(); int i = dim.height; int l = dim.width; setSize(dim.width, dim.height); setVisible(true);} } public class pv { public static void main(String args[]) { Fer fp=new Fer("Fereastra pe intreg ecranul");} } 10.6. Poziţionarea componentelor Pentru a a[eza componentele \n pozi]ia dorit`, putem s` utiliz`m pozi]ionarea absolut` (dar este nerecomandat` pentru c` programul trebuie s` ruleze corect pe o diversitate de platforme) sau unul dintre gestionarii de pozi]ionare existen]i. Cum facem acest lucru? Ve]i vedea \n paragraful acesta! Oricum, trebuie s` [ti]i c` mecanismul este pu]in mai complicat decât cel cu care a]i fost obi[nui]i \n ipoteza c` a]i studiat programarea vizual` (de exemplu \n Borland Delphi sau Borland Builder). Nu uita]i, programele Java trebuie s` func]ioneze pe orice platform`! Capitolul 10. Iniţiere în programarea vizuală 201 10.6.1. Poziţionarea absolută Pentru a utiliza pozi]ionarea absolut` a componentelor trebuie s` lucr`m \n absen]a unui gestionar de pozi]ionare, iar coordonatele sunt date \n pixeli. Pentru aceasta trebuie s` cunoa[tem urm`toarele: 1. Secven]a de mai jos se utilizeaz` pentru a lucra \n absen]a unui gestionar de pozi]ionare. Container x=getContentPane(); x.setLayout(null); 2. |n pozi]ionarea absolut` componentele pozi]ionate, altfel nu sunt vizibile. Testa]i... trebuie dimensionate [i Pentru dimensionarea componentelor se utilizeaz` urm`toarele metode ale clasei JComponent: setBounds(int x, int y, int lat, int inal); metoda pozi]ioneaz` [i dimensioneaz` componenta. Parametrii x [i y dau pozi]ia componentei \n raportat` la col]ul din st@nga sus al componentei care o g`zduie[te, iar lat [i lung o dimensioneaz`. Metoda de mai sus poate fi \nlocuit` cu urm`toarele dou` metode: setLocation(int pozi]ionare; setSize (int dimensionare. x, lat, int int y) lung) - metod` - metod` care care are are rolul rolul de Exemplu: utiliz`m pozi]ionarea absolut` [i a[ez`m un buton \n fereastr`: Container x=getContentPane(); x.setLayout(null); JButton A=new JButton ("Exemplu"); A.setBounds(10,10, 100, 40); 10.6.2. Gestionarul de poziţionare FlowLayout . Componentele sunt afi[ate pe linii, \n ordinea \n care au fost declarate. Pe fiecare linie ele sunt afi[ate de la st@nga la dreapta (at@tea c@te \ncap). |n continuare, pute]i observa cum a fost creat` fereastra al`turat`: de 202 Bazele programării în Java class Fer extends JFrame { public Fer(String titlu) { super(titlu); setSize(300,150); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Buton 1"); JButton B=new JButton("Buton 2"); JButton C=new JButton("Buton 3"); JButton D=new JButton("Buton 4"); JButton E=new JButton("Buton 5"); JButton F=new JButton("Buton 6"); JButton G=new JButton("Buton 7"); setVisible(true); } x.add(A); x.add(B); x.add(C); x.add(D); x.add(E); x.add(F); x.add(G); } Clasa FlowLayout con]ine constante de aliniere pe linie, din care mai importante sunt: CENTER, aliniere \n centru, op]iune implicit`, LEFT, la st@nga [i RIGHT, la dreapta. Clasa FlowLayout este \nzestrat` cu 3 constructori: a) FlowLayout() - distan]a \ntre r@nduri este de 5 unit`]i, distan]a pe orizontal` \ntre componente este de 5 unit`]i [i componentele sunt aliniate pe linie la centru (CENTER). b) FlowLayout(int aliniere) - se cere explicit ca alinierea s` fie \ntr-un anumit fel (CENTER, RIGHT, LEFT, acestea sunt constante ale clasei FlowLayout). c) FlowLayout(int aliniere, int dist_oriz, int dist_vert ) se specific` [i distan]a pe orizontal` \ntre componente [i distan]a pe vertical` dintre ele. Exemple de utilizare a constructorilor: FlowLayout (FlowLayout.LEFT) FlowLayout (FlowLayout.RIGHT,15,8) Capitolul 10. Iniţiere în programarea vizuală 203 De re]inut: 1. Dimensionarea componentelor [i pozi]ionarea lor este f`cut` automat de c`tre gestionar. 2. Metodele utilizate \n pozi]ionarea absolut` pentru pozi]ionarea [i dimensionarea componentelor ( setBounds(), setLocation(), setSize()) de[i sunt acceptate la compilare, nu au nici un efect. 3. Exist`, totu[i, o metod` care dimensioneaz` componentele [i este acceptat` de gestionarul FlowLayout. Ea apar]ine clasei JComponent: setPreferredSize(Dimension dim); Clasa Dimension are constructorul Dimension(int lat, int inalt) prin care se specific` l`]imea, respectiv \n`l]imea componentei. Exemplu: prin utilizarea gestionarului FlowLayot se adaug` unei ferestre dou` butoane, primul de dimensiune stabilit`, al doilea de dimensiune implicit`: Container x=getContentPane(); x.setLayout(new FlowLayout()); JButton A=new JButton ("Buton 1"); A.setPreferredSize(new Dimension(100, 100)); JButton B=new JButton ("Buton 2"); x.add(A); x.add(B); 10.6.3. Gestionarul de poziţionare GridLayout Clasa GridLayout - aranjeaz` componentele \ntr-o alt` logic`. Ideea de baz` este aceea c` se \mparte suprafa]a ferestrei \n mai multe dreptunghiuri de suprafa]` egal` [i \n fiecare dreptunghi astfel ob]inut se a[eaz` o component` care este de cele mai multe ori extins` ca suprafa]`, astfel \nc@t s` ocupe \ntreaga suprafa]` a dreptunghiului care \i revine. Pentru a \n]elege modul de aranjare a componentelor vom prezenta pe scurt cei trei constructori ai clasei: a) GridLayout() - dac` avem n componente care trebuie a[ezate, suprafa]a ferestrei este \mp`r]it` \ntr-o singur` linie [i n coloane. Fiecare component` este a[eazat` \ntr-un dreptungi, iar componentele sunt f`r` spa]iu \ntre ele. b) GridLayout(int nr_linii, int nr_coloane) - suprafa]a \mp`r]it` \n nr_linii nr_coloane dreptunghiuri. Fiecare dreptunghi re]ine o component`. Vede]i exemplul al`turat. GridLayout (3,3) 204 Bazele programării în Java c) GridLayout(int nr_linii, int nr_col, int sp_o, int sp_v ) se procedeaz` ca anterior, numai c` se trec [i spa]iile pe orizontal` [i pe vertical` \ntre dreptunghiurile generate. GridLayout (3,3,5,8) ! Pentru GridLayout nu are nici un efect metoda setPreferredSize(). 10.6.4. Gestionarul de poziţionare BorderLayout Clasa BorderLayout - \mparte suprafa]a ferestrei \n 5 p`r]i: nord (NORTH), sud (SOUTH), est (EAST), vest (WEST) [i centru (CENTER). |n fiecare parte se poate a[eza o component`. Mai jos pute]i observa cum am ob]inut a[ezarea componentelor ca \n fereastra al`turat`. x.setLayout(new BorderLayout ()); JButton A=new JButton("Buton 1"); x.add(A,BorderLayout.SOUTH); JButton B=new JButton("Buton 2"); x.add(B,BorderLayout.NORTH); JButton C=new JButton("Buton 3"); x.add(C,BorderLayout.WEST); JButton D=new JButton("Buton 4"); x.add(D,BorderLayout.EAST); JButton E=new JButton("Buton 5"); x.add(E,BorderLayout.CENTER); De re]inut: 1. Pentru ad`ugarea unei componente container-ului, se folose[te metoda add cu 2 parametri, al doilea fiind cel care precizeaz` pozi]ia \n care este ad`ugat` componenta. Vezi, mai sus! 2. Componentele sunt extinse pentru a ocupa \ntreaga suprafa]` alocat`. Vede]i figura de mai sus. 3. Dac` lipse[te componenta din nord, sau cea din sud, spa]iul este ocupat de linia din centru. 4. Dac` lipse[te componenta din centru, spa]iul este l`sat liber. Dac` lipse[te componenta din est, sau cea din vest, spa]iul este ocupat de componenta din centru. 5. Metoda setPreferredSize() are efect par]ial. Astfel avem: dac` este aplicat` unei componente din nord sau din sud, se ia \n considerare numai \n`l]imea transmis` de metod`. Dac` este aplicat` unei componente din est, vest, sau centru se ia \n considerare numai l`]imea componentei. Capitolul 10. Iniţiere în programarea vizuală 205 10.6.5. Gestionarul GridBagLayout Gestionarul GridBagLayout() este o extindere a gestionarului GridLayout(). {i el \mparte suprafa]a container-ului \n mai multe dreptunghiuri, unde fiecare dreptunghi va fi ocupat de o component`. Evident, dreptunghiurile sunt aranjate \n linii [i coloane. Dar, aici, propor]iile \ntre linii [i coloane pot fi diferite, iar o component` poate ocupa unul sau mai multe dreptunghiuri. De asemenea, o component` poate fi plasat` \n cadrul dreptunghiului (dreptunghiurilor) \n mai multe feluri. S` vedem cum se pot realiza toate acestea. Clasa GridBagLayout - un obiect al acestei clase este de fapt, administratorul de pozi]ionare. Printre altele, clasa con]ine: GridBagLayout() - constructor; setConstraints(Component comp, GridBagConstraints cons)metod`. Pentru a [ti unde se pozi]ioneaz` fiecare component`, vom utiliza un mecanism specific. El const` \n a scrie, pentru fiecare component` \n parte, un set de restric]ii (cu ajutorul lor se determin` pozi]ionarea acesteia). Restric]iile de pozi]ionare pentru fiecare component` \n parte sunt memorate de c@te un obiect de tip GridBagConstraints. Metoda pe care o trat`m \n acest moment anun]` gestionarul de pozi]ionare, componenta [i restric]iile ei de pozi]ionare. Acum trebuie s` vedem cum stabilim restric]iile de pozi]ionare pentru o component` oarecare. Pentru aceasta vom utiliza clasa GridBagConstraints. Ea are constructorul: GridBagConstraints(int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor, int fill, Insets insets, int ipadx, int ipady) Semnifica]ia parametrilor este urm`toarea: gridx, gridy - specific` dreptunghiul care con]ine componenta. Pentru fiecare dreptunghi din exemplul al`turat am trecut, \n aceast` ordine: gridx, gridy. 0,0 1,0 0,1 1,1 0,2 1,2 206 Bazele programării în Java gridwidth, gridheight - num`rul de dreptunghiuri respectiv pe coloan` care sunt ocupate de component`. weightx si weighty - l`]imea ocupat` de dreptunghi pe linie, respectiv pe coloan`. Acestea nu sunt date \n pixeli. Pentru a u[ura \n]elegerea vom lua ca exemplu linia. Presupunem c` avem c@te dou` dreptunghiuri pe linie, ca \n exemplul de mai sus. Dac` pentru primul dreptunghi weightx re]ine 1 [i pentru al doilea, weightx re]ine 2, atunci l`]imea primului dreptunghi este 1/3 din l`]imea final`, iar a celui de-al doilea dreptunghi este 2/3 din l`]imea final`. anchor - se refer` la pozi]ionarea componentei \n cadrul dreptunghiului. Poate lua una din valorile: CENTER, NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST. fill - se refer` la cazul \n care componenta ocup` mai mult sau mai putin spa]iu dec@t dreptunghiul rezervat ei [i dorim s-o ajust`m astfel \nc@t s` \ncap` exact. |n acest caz se pune problema mic[r`rii sau m`ririi ei. Poate lua valorile: NONE (nu se ajusteaz`), HORIZONTAL (se ajusteaz` pe l`]ime, dar \n`l]imea r`m@ne nemodificat`), VERTICAL (se ajusteaz` pe \n`l]ime, dar l`]imea r`m@ne nemodificat`), BOTH (se ajusteaz` at@t l`]imea c@t [i \n`l]imea). insets - referin]` la un obiecte de tip Insets. Aceasta are rolul de a ad`uga \n fiecare parte a componentei un spa]iu exterior (dat \n pixeli). Constructorul clasei Insets are forma Insets(int sus, int stanga, int jos, int dreapta). O component` care are margini exterioare este separat` de alt` component` cel pu]in prin acele margini. ipadx, ipady - adaug` spa]iu interior pe orizontal`, respectiv pe vertical`. Dac`, de exemplu, ipadix re]ine 1, se adaug` de fapt un pixel la st@nga [i un pixel la dreapta. Diferen]a \ntre spa]iul interior [i cel exterior este dat` de faptul c` se presupune c` spa]iul interior este al componentei, deci pe aceast` suprafa]` componenta r`spunde la evenimente. pe linie, Exemplu: programul urm`tor afi[eaz` o fereastr` care con]ine o etichet`, un edit [i un buton. Cele trei componente sunt afi[ate prin utilizarea gestionarului de pozi]ionare GridBagLayout. Butonul ocup` dou` dreptunghiuri, iar raportul dintre spa]iul ocupat de etichet` [i cel ocupat de edit este de 1/4. Nu trebuie s` v` \ngrijoreze faptul c` \n exemplu s-au utilizat [i alte componente. Toate vor fi studiate \ncep@nd cu paragraful urm`tor. Capitolul 10. Iniţiere în programarea vizuală 207 import java.awt.*; import javax.swing.*; class Fer extends JFrame { public Fer(String titlu) { super(titlu); setSize(250,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GridBagLayout pozitii=new GridBagLayout(); JLabel et=new JLabel ("Numele "); JTextField txt=new JTextField(15); JButton bt=new JButton("Ce-am citit?"); Container x=getContentPane(); // pozitionare eticheta GridBagConstraints p_et=new GridBagConstraints(0,0,1,1,1,2,GridBagConstraints.EAST, GridBagConstraints.NONE,new Insets(0,0,0,0), 0,0); pozitii.setConstraints(et,p_et); // pozitionare edit GridBagConstraints p_txt=new GridBagConstraints(1,0,1,1,4,2,GridBagConstraints.EAST, GridBagConstraints.NONE,new Insets(0,0,0,0), 0,0); pozitii.setConstraints(txt,p_txt); // pozitionare buton GridBagConstraints p_bt=new GridBagConstraints(0,1,2,1,1,1,GridBagConstraints.CENTER, GridBagConstraints.NONE,new Insets(0,0,0,0), 0,0); pozitii.setConstraints(bt,p_bt); x.setLayout(pozitii); x.add(et); x.add(txt); x.add(bt); setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Gestionar de pozitionare"); } } 10.6.6. Gestionarul CardLayout Gestionarul CardLayout este caracterizeaz` prin faptul c`, la un component`. unul cu totul aparte. El se moment dat, afi[eaz` o singur` CardLayout() - constructor; next(Container parinte) - afi[eaz` urm`toarea component`. Dac` este afi[at` ultima component`, se afi[eaz` din nou prima component`; last(Container parinte) - se afi[eaz` ultima component`; 208 Bazele programării în Java first(Container parinte) - se afi[eaz` prima component`; addLayout(String nume, Component c) component` c`reia i se [i atribuie un nume. - se adaug` o Exemplu: \n programul urm`tor se afi[eaz` cu gestionarul CardLayout 3 butoane. Aceasta \nseamn` c`, la un moment dat, numai unul este vizibil. La ap`sarea butonului vizibil se afi[eaz` urm`torul buton, [.a.m.d. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { CardLayout g=new CardLayout(); Container x=getContentPane(); public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); x.setLayout(g); JButton A=new JButton("Buton 1"); x.add("Buton 1",A); A.addActionListener(this); JButton B=new JButton("Buton 2"); x.add("Buton 2",B); B.addActionListener(this); JButton C=new JButton("Buton 3"); x.add("Buton 3",C); C.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { g.next(x); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("gestionarul CardLayout"); } } 10.7. Studiul principalelor componente 10.7.1. Componente de tip JButton Cu ajutorul componentelor de acest tip se creeaz` butoane. Vom prezenta cele mai importante metode (constructori): JButton() - creeaz` un buton f`r` text, f`r` imagine asociat`. JButton(String text) - creeaz` un buton care afi[eaz` un text. JButton(Icon icon) - creeaz` un buton care re]ine o imagine de mici dimensiuni. Capitolul 10. Iniţiere în programarea vizuală 209 Exemplu: Icon icon = new ImageIcon("om.gif"); JButton A=new JButton(icon); JButton(String text, Icon icon) - creeaz` un buton cu text [i imagine. Icon icon = new ImageIcon("om.gif"); JButton A=new JButton( "Java...",icon); metoda setVericalTextPosition(constanta) seteaz` pozi]ia pe veritcal` a textului \n raport cu imaginea: deasupra (JButton.TOP), dedesubt (JButton.BOTTOM), \n centru (JButton.CENTER). metoda setHorizontalTextPosition(constanta) seteaz` pozi]ia pe orizontal` a textului \n raport cu imaginea: st@nga (JButton.LEFT), dreapta (JButton.RIGHT), \n centru (JButton.CENTER). Exemplu: Icon icon = new ImageIcon("om.gif"); JButton A=new JButton( "Java...",icon); A.setVerticalTextPosition(JButton.TOP); A.setHorizontalTextPosition(JButton.CENTER); M`rimea imaginii determin` m`rimea butonului. 10.7.2. Componente de tip JLabel Componentele de acest tip se utilizeaz` pentru a afi[a texte [i imagini, cu rol l`muritor pentru alte componente. Clasa este \nzestrat` cu urm`toarele metode mai importante: JLabel(string S) - se utilizeaz` pentru a afi[a un [ir de caractere. 210 Bazele programării în Java Exemplu: dac` constructorul ferestrei con]ine secven]a de mai jos, atunci pe fereastr` apare: Container x=getContentPane(); x.setLayout(new BorderLayout ()); JLabel A=new JLabel ("Un text "); x.add(A); JLabel(Icon image) - se utilizeaz` pentru a afi[a o imagine: Exemplu: la fel ca mai sus, numai c` pe fereastr` se afi[eaz` o imagine: Container x=getContentPane(); Container x=getContentPane(); x.setLayout(new BorderLayout ()); x.setLayout(new BorderLayout ()); Icon icon = new ImageIcon("idee.gif"); Icon icon = new ImageIcon("idee.gif"); JLabel A=new JLabel (icon); JLabel A=new JLabel (icon); x.add(A); x.add(A); JLabel(String text, Icon icon, int horizontalAlignment) afi[eaz` o imagine [i un text. Ansamblul (imagine + text) se aliniaz` pe orizontal`, conform ultimului parametru (CENTER, LEFT, RIGHT). setVerticalTextPosition(c), setHorizontalTextPosition(c) pot fi folosite [i la JLabel la fel ca la Jbutton: Exemplu: Container x=getContentPane(); x.setLayout(new GridLayout()); Icon icon = new ImageIcon("idee.gif"); JLabel A=new JLabel ("Asta era!!!",icon,JLabel.CENTER); A.setHorizontalTextPosition(Jlabel.CENTER); A.setVerticalTextPosition(JLabel.TOP); x.add(A); 10.7.3. Componente de tip JPanel Componentele JPanel (paneluri) sunt de tip container, adic` au rolul de a con]ine pe suprafa]a lor alte componente. Clasa este \nzestrat` cu urm`toarele metode: JPanel() - constructor, obiectul rezultat are gestionarul de pozi]ionare FlowLayout(). JPanel(LayoutManager layout) - constructor, obiectul rezultat are gestionarul de pozi]ionare transmis ca parametru. setLayout(LayoutManager layout); pozi]ionare. add(Compoment c) - adaug` o component` obiectului. - seteaz` gestionarul de Capitolul 10. Iniţiere în programarea vizuală 211 Exemplu: fereastra programului urm`tor con]ine o component` de tip JPanel. Pe ea sunt ata[ate 3 butoane. La ap`sarea unui buton, componenta de tip JPanel va avea culoarea afi[at` de buton. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { JPanel panel; public Fer(String titlu) { super(titlu); setSize(300,300); fer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); panel=new JPanel(); JButton A=new JButton("Rosu"); panel.add(A); A.addActionListener(this); JButton B=new J Button("Galben"); panel.add(B); B.addActionListener(this); JButton C=new JButton("Albastru"); panel.add(C); C.addActionListener(this); x.add(panel); setVisible(true);} public void actionPerformed (ActionEvent e) { String culoare=e.getActionCommand(); if (culoare.compareTo("Rosu")==0) panel.setBackground(Color.red); else if (culoare.compareTo("Galben")==0) panel.setBackground(Color.yellow); else panel.setBackground(Color.blue); } } public class cv { public static void main(String args[]) { Fer fp=new Fer("Fereastra cu panel"); } } 10.7.4. Componente de tip JTextField Componentele de tip JTextField (edit-uri) sunt utilizate pentru ca utilizatorul s` introduc` sau s` afi[eze [iruri de caractere de la tastatur`, [iruri pe care programul urmeaz` s` le prelucreze. Cele mai importante metode ale acestui obiect sunt: 212 Bazele programării în Java JTextField(int nr) - creeaz` un edit vid, dar care are o l`]ime suficient` pentru a vizualiza simultan nr caractere. {irul de caractere introdus poate avea orice lungime. JTextField(String s) - creeaz` un edit care ini]ial afi[eaz` un [ir de caractere. JTextField(String S, int nr) - creeaz` un edit care ini]ial afi[eaz` un [ir de caractere [i care are o l`]ime suficient` pentru a afi[a simultan un num`r de nr caractere. String getText() - returneaz` [irul de caractere re]inut de edit la un moment dat. void setText(String s) - are rolul de a determina ca edit-ul s` con]in` [irul de caractere specificat. Exemplul . Programul urm`tor afi[eaz` fereastra al`turat`. Utilizatorul introduce un [ir de caractere [i, la ap`sarea butonului se afi[eaz`, \n fereastra CMD, textul introdus de acesta. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { JTextField txt; public Fer(String titlu) { super(titlu); setSize(300,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JLabel et=new JLabel ("Numele dv:"); x.add(et); txt=new JTextField(15); x.add(txt); JButton but=new JButton("Ce-am introdus?"); x.add(but); but.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { System.out.println(txt.getText());} } public class pv { public static void main(String args[]) { Fer fp=new Fer("Exemplu de edit"); } } Capitolul 10. Iniţiere în programarea vizuală Exemplul . Programul urm`tor rezolv` ecua]ia de gradul 1 [i afi[eaz` o fereastr` precum cea al`turat`. Rezolvare: a) Pentru a grupa elementele vom utiliza trei componente de tip JPanel [i un obiect de tip JButton. Fiecare component` de tip JPanel va re]ine o component` de tip Jlabel (de ex afi[eaz` “a=”) [i una de tip JTextField (de exemplu, pentru introducerea lui a). b) Datele citite sunt validate prin utilizarea mecanismelor de excep]ie. c) La ap`sarea butonului se afi[eaz` rezultatul. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { JTextField a,b,r; JButton but; public Fer(String titlu) { super(titlu); setSize(200,200); fer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); //primul panel JPanel panel1 = new JPanel(); JLabel et=new JLabel ("a="); panel1.add(et); a=new JTextField(15); panel1.add(a); x.add(panel1); //al doilea panel JPanel panel2 = new JPanel(); JLabel et1=new JLabel ("b="); panel2.add(et1); b=new JTextField(15); panel2.add(b); x.add(panel2); // al treilea panel JPanel panel3 = new JPanel(); JLabel et2=new JLabel ("x="); panel3.add(et2); r=new JTextField(15); panel3.add(r); x.add(panel3); // butonul Rezulta but=new JButton("Rezultat"); x.add(but); but.addActionListener(this); setVisible(true); } 213 214 Bazele programării în Java public void actionPerformed (ActionEvent e) { double aR=0,bR=0,xR=0, er=0; try // incerc sa-l citesc pe A { aR=Double.parseDouble(a.getText()); } catch (NumberFormatException exc) { er=1; System.out.println("a este introdus gresit"); r.setText("");} try // incerc sa-l citesc pe B { bR=Double.parseDouble(b.getText()); } catch (NumberFormatException exc) { er=1; System.out.println("b este introdus gresit"); r.setText("");} if (er==0)// daca aR si bR au fost citite if (aR!=0) r.setText(""+(double)-bR/aR); else if (bR==0) r.setText("Infinitate de solutii"); else r.setText("Nu are solutie"); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Ecuatia de gradul 1"); } } 10.7.5. Componente de tip JComboBox Obiectele clasei JComboBox sunt a[a numitele liste, din care utilizatorul poate selecta o anumit` op]iune (unic`). Principalele metode ale clasei JComboBox sunt: JComboBox () – constructor. void addItem(Object s) - adaug` listei o op]iune. Cum clasa Object este la baza ierarhiei de clase Java, parametrul efectiv poate fi o referin]` c`tre orice obiect, inclusiv c`tre tipul des utilizat String. Object getSelectedItem() corespunz`tor op]iunii selectate. int getItemCount() - returneaz` num`rul de op]iuni. int getSelectedIndex() - returneaz` indexul op]iunii selectate. Object getItemAt(int ind) - returneaz` obiectul re]inut de item-ul de indice ind (dac` trebuie s` ob]inem un obiect de tip String, atunci converti]i c`tre String prin operatorul de conversie). – returneaz` [irul de caractere Capitolul 10. Iniţiere în programarea vizuală 215 Exemplu: Programul urm`tor afi[eaz` o list`. Selecta]i din list` o op]iune [i ap`sa]i butonul. |n fereastra CMD va fi afi[at` op]iunea selectat`. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { JComboBox lista; public Fer(String titlu) { super(titlu); setSize(300,200); fer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JLabel et=new JLabel ("Selectati materia preferata:"); x.add(et); lista=new JComboBox (); lista.addItem("Matematica"); lista.addItem("Informatica"); lista.addItem("Engleza"); lista.addItem("Alta materie"); x.add(lista); JButton but=new JButton("Ce-am selectat?"); x.add(but); but.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { System.out.println(lista.getSelectedItem()); } } public class cp { public static void main(String args[]) { Fer fp=new Fer("Exemplu de lista"); } } 10.7.6. Componente de tip JCheckBox şi JRadioButton şi gruparea lor Obectele clasei JCheckBox sunt a[a-numitele butoane de validare. Fereastra poate con]ine unul sau mai multe astfel de butoane. Principalele metode ale acestei clase sunt: JCheckBox(String s) - creeaz` un buton de validare care con]ine [irul de caractere transmis ca parametru. JCheckBox(String s, boolean v) - creeaz` un buton de validare care con]ine [irul de caractere transmis ca parametru [i care este marcat sau nu \n func]ie de valoarea pe care o re]ine parametrul v, respectiv true sau false. 216 Bazele programării în Java JCheckBox(String s, Icon f) - creeaz` un buton de validare care con]ine [irul de caractere transmis ca parametru si o imagine. booolean isSelected() - returneaz` true dac` butonul a fost selectat [i false \n caz contrar. String getText() - returneaz` [irul de caractere re]inut de buton. Exemplu. Programul urm`tor afi[eaz` mai multe butoane de validare, din care unul (cel care afi[eaz` Informatica) este selectat de la \nceput! La ap`sarea butonului Ce-am selectat? este afi[at` selec]ia f`cut`. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { JCheckBox b1,b2,b3,b4; public Fer(String titlu) { super(titlu); setSize(150,200); Container x=getContentPane(); x.setLayout(new FlowLayout (FlowLayout.LEFT)); fer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel et=new JLabel ("Selectati"); x.add(et); b1=new JCheckBox("Matematica");x.add(b1); b2=new JCheckBox("Informatica",true);x.add(b2); b3=new JCheckBox("Engleza"); x.add(b3); b4=new JCheckBox("Biologie");x.add(b4); JButton but=new JButton("Ce-am selectat?"); x.add(but); but.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { if (b1.isSelected()) System.out.println(b1.getText()); if (b2.isSelected()) System.out.println(b2.getText()); if (b3.isSelected()) System.out.println(b3.getText()); if (b4.isSelected()) System.out.println(b4.getText()); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Validare"); } } Obiectele de tip JRadioButton sunt asem`n`toare cu cele de tip JCheckBox, negrupate au acela[i comportament, numai c` arat` ca ni[te butoane radio. Capitolul 10. Iniţiere în programarea vizuală 217 Butoanele pot fi grupate, adic` pot fi toate tratate ca un \ntreg. Un exemplu conving`tor este dat de necesitatea grup`rii butoanelor radio (unde, la un moment dat, numai un singur buton poate fi selectat). Pentru a grupa butoanele se folose[te un obiect al clasei ButtonGroup. Cele mai importante metode ale acestei clase sunt: ButtonGroup() - constructor; void add(AbstractButton b) – adaug` un buton grupului (clasa AbstractButton este superclas` pentru JButton, JRadioButton, JCheckBox). Enumeration getElements(); - returneaz` un pointer la grupul de butoane. int getButtonCount() - returneaz` num`rul de butoane din grup. import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; class Fer extends JFrame implements ActionListener { ButtonGroup grup; public Fer(String titlu) { super(titlu); setSize(150,200); fer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout (FlowLayout.LEFT)); JLabel et=new JLabel ("Selectati"); x.add(et); JRadioButton b1=new JRadioButton("Matematica");x.add(b1); JRadioButton b2=new JRadioButton("Informatica",true);x.add(b2); JRadioButton b3=new JRadioButton("Engleza"); x.add(b3); JRadioButton b4=new JRadioButton("Biologie");x.add(b4); JButton but=new JButton("Ce-am selectat?"); x.add(but); but.addActionListener(this); grup = new ButtonGroup(); grup.add(b1);grup.add(b2); grup.add(b3);grup.add(b4); setVisible(true); } public void actionPerformed (ActionEvent e) { Enumeration enum=grup.getElements(); while (enum.hasMoreElements()) { JRadioButton b=(JRadioButton)enum.nextElement(); if(b.isSelected()) System.out.println(b.getText()); } } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Validare"); } } 218 Bazele programării în Java 10.7.7. Meniuri |n Java, meniurile se construiesc prin utilizarea obiectelor mai multor clase: A) Clasa JMenuBar - obiectele acestei clase se utilizeaz` pentru a ob]ine meniuri clasice, aflate \n partea de sus a ferestrei. Cele mai importante metode ale acestei clase sunt: JMenuBar() - constructor; add(JMenu) - adaug` meniului componente de tip JMenu, vede]i \n continuare. B) Clasa JMenu - obiectele acestei clase au rolul de a \nscrie \n meniu anumite op]iuni, care la r@ndul lor pot con]ine alte op]iuni. Cele mai importante metode ale acestei clase sunt: JMenu(String s) - constructor. Obiectul va afi[a [irul s add(JMenuItem meniu) - adaug` o component` de tip JMenuItem. Vede]i mai jos clasa JMenuItem; add (Comonent c) - adaug` o alt` component` (de un tip derivat din tipul Component). C) Clasa JMenuItem - o astfel de component` care apare \n meniu, arat` ca o op]iune [i are rolul unui buton, adic` selectat`, conduce la o anumit` ac]iune. Cele mai importante metode ale acestei clase sunt: JMenuItem(String s) - constructor, op]iunea afi[eaz` [irul s; JMenuItem(Icon imagine; JMenuItem(String s, Icon ic) - constructor, op]iunea afi[eaz` un [ir de caractere [i o mic` imagine. ic) - constructor, Exemplu: programul urm`tor construie[te un meniu clasic. Pentru fiecare op]iune selectat` se afi[eaz` \n fereastra CMD [irul afi[at de op]iune. import java.awt.*; import java.awt.event.*; import javax.swing.*; op]iunea afi[eaz` o mic` Capitolul 10. Iniţiere în programarea vizuală 219 class Fer extends JFrame implements ActionListener { TextArea t; public Fer(String titlu) { super(titlu); setSize(400,400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Bara meniu JMenuBar bara = new JMenuBar(); // Creez meniul principal JMenu meniu1 = new JMenu("Operatii 1"); bara.add(meniu1); JMenu meniu2 = new JMenu("Operatii 2"); bara.add(meniu2); // adaug itemi pentru fiecare optiune din meniul principal JMenuItem item11 = new JMenuItem("OP 11"); item11.addActionListener(this); meniu1.add(item11); JMenuItem item12 = new JMenuItem("OP 12"); item12.addActionListener(this); meniu1.add(item12); JMenuItem item21 = new JMenuItem("OP 21"); item21.addActionListener(this); meniu2.add(item21); setJMenuBar(bara); Container x=getContentPane(); x.setLayout(new GridLayout ()); setVisible(true); } public void actionPerformed (ActionEvent e) { System.out.println(e.getActionCommand()); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Fereastra cu meniu"); } } Metoda clasei JFrame setJMenuBar(JMenuBar b) are rolul de a ata[a bara de meniu ferestrei. Meniurile pot de tip JMenu i componente de tip tot de tip JMenu. componente de tip con]ine [i submeniuri. Pentru aceasta, unei componente se adaug`, pe lâng` alte JMenuItem, o alt` component`, Acesteia din urm` i se adaug` JMenuItem. Exemplu: pentru a ob]ine meniul al`turat, ad`uga]i programului de mai sus secven]a urm`toare: //submeniuri JMenu altele = new JMenu("Altele"); meniu1.add(altele); 220 Bazele programării în Java JMenuItem item131 = new JMenuItem("OP 131"); altele.add(item131); item131.addActionListener(this); JMenuItem item132 = new JMenuItem("OP 132"); altele.add(item132); item132.addActionListener(this); Evident, procedeul se poate repeta pentru a submeniuri dori]i. ob]ine oric@te Acceleratori. |n multe aplica]ii, anumite op]iuni din meniuri sunt \nzestrate cu acceleratori (shortcut-uri de meniu) prin care o anumit` comand` se poate ob]ine fie din meniu, fie dintr-o combina]ie de taste. {i \n Java se pot crea acceleratori [i acest mecanism este prezentat \n continuare. Metoda: void setAccelerator(KeyStroke keyStroke) are rolul de a ata[a unui obiect de tip JMenuItem un accelerator, adic` de a invoca ac]iunea specific` acestuia atunci c@nd utilizatorul a ap`sat fie o tast`, fie o combina]ie de taste. |n primul caz (o tast`), se folose[te metoda: static KeyStroke getKeyStroke(char keyChar), iar \n al doilea caz metoda: static KeyStroke getKeyStroke(int keyCode, int modifiers) Cum ob]inem parametrii pentru a doua metod` getKeyStrohe()? Primul parametru este o constant` a clasei KeyEvent. Iat` c@teva astfel de constante: static int VK_1 (tasta 1), static int VK_2 (tasta 2), static int VK_F1 (tasta F1), static int VK_V (tasta V) [.a.m.d. Al doilea parametru este o constant` a clasei ActionEvent: SHIFT_MASK, (codul 1), CTRL_MASK (codul 2) , META_MASK ( codul 4), ALT_MASK (codul 8). Exemplu: \n primul program de la \nceputul paragrafului, pentru item21 doresc s` am un accelerator, adic` s` ob]in acela[i efect prin ap`sarea combina]iei de taste ALT+2 ca [i \n cazul \n care oper`m selec]ia din meniu: JMenuItem item21 = new JMenuItem("OP 21"); item21.setAccelerator(KeyStroke.getKeyStroke (KeyEvent.VK_2, ActionEvent.ALT_MASK)); item21.addActionListener(this); Capitolul 10. Iniţiere în programarea vizuală 221 |n acest caz, dac` ap`s`m ALT+2, ob]inem acela[i efect ca atunci c@nd oper`m selec]ia din meniu. Dac` dorim s` ob]inem o combina]ie din trei taste, de exemplu CTRL+ALT+2, vom folosi (datorit` codific`rii din ActionEvent): getKeyStroke( KeyEvent.VK_2, ActionEvent.ALT_MASK + ActionEvent.CTRL_MASK)); Alte tipuri de componente. Unui meniu i se pot ad`uga [i alte componente dintre cele prezentate. Iat` un exemplu \n care se adaug` \n meniu mai multe butoane: JRadioButton b1=new JRadioButton("Text 1"); meniu1.add(b1); JButton b2=new JButton("Text2"); meniu1.add(b2); JCheckBox b3=new JCheckBox("Text 3"); meniu1.add(b3); Grupuri de butoane. Meniurilor li se pot ad`uga grupuri de butoane (revede]i Gruparea butoanelor). Mai mult, pentru a identifica un grup \n meniu, se utilizeaz` separatori (linii orizontale) care sunt obiecte ale clasei JSeparator(). Exemplu: meniu1.add(new JSeparator()); JRadioButton b1=new JRadioButton("Matematica"); meniu1.add(b1); JRadioButton b2=new JRadioButton("Informatica"); meniu1.add(b2); JRadioButton b3=new JRadioButton("Engleza"); meniu1.add(b3); JRadioButton b4=new JRadioButton("Biologie"); meniu1.add(b4); meniu1.add(new JSeparator()); ButtonGroup grup = new ButtonGroup(); grup.add(b1); grup.add(b2); grup.add(b3); grup.add(b4); 10.7.8. Cutii (casete) de dialog predefinite Cutiile de dialog predefinite sunt extrem de utile pentru introducerea sau afi[area unor date. Pentru a putea folosi astfel de cutii, vom utiliza clasa JOptionPane care con]ine mai multe metode statice care afi[eaz` astfel de cutii. Cutiile sunt predefinite, con]inând automat anumite componente (nu mai este necesar ca acestea s` fie create de programator). 222 Bazele programării în Java 10.7.8.1. Cutii de dialog de intrare Iat` c@teva metode prin care putem apela astfel de cutii: public static String showInputDialog(Object mes) creeaz` [i afi[eaz` \n centrul ecranului o cutie de dialog care afi[eaz` mesajul transmis ca parametru. |n cazul \n care utilizatorul apas` Cancel, se returneaz` pointer-ul null, motiv pentru care trebuie tratat` aceast` excep]ie. Exemplu: try { String intr = JOptionPane.showInputDialog("a="); if (intr.length()==0) System.out.println("Intr vida"); else System.out.println(intr);} catch(NullPointerException exc) { System.out.println("S-a apasat Cancel");} public static String showInputDialog(Object mes, Object val) la fel ca mai sus, numai c` edit-ul memoreaz` de la \nceput valoarea transmis` de al doilea parametru (valoare ini]ial`). |n exemplul de mai jos, valoarea ini]ial afi[at` este “0”. String intr = JOptionPane.showInputDialog("a=","0"); public static String showInputDialog(Component par, Object mes) - ca mai sus, numai c` se afi[eaz` o cutie de dialog care are o component` p`rinte. |n exemplul urm`tor, afi[area se face cu ajutorul clasei care descrie fereastra principal`, deci p`rintele este this (acest obiect): String intr = JOptionPane.showInputDialog(this,"a="); public static String showInputDialog(Component par, Object mes, Object val) - ca mai sus, numai c` se afi[eaz` o cutie de dialog \n care edit-ul re]ine [i o valoare ini]ial`. 10.7.8.2. Cutii de dialog pentru afişarea mesajelor Astfel de cutii de dialog se utilizeaz` pentru a transmite utilizatorului anumite mesaje de eroare, sau rezultate. public static void showMessageDialog(Component par, Object mes) - afi[eaz` o cutie de dialog cu un mesaj dorit. Exemplu: clasa asociat` ferestrei se g`se[te secven]a: Capitolul 10. Iniţiere în programarea vizuală 223 int a=125; JOptionPane.showMessageDialog(this , "a="+a); 10.7.8.3. Cutii de dialog de confirmare O astfel de cutie de dialog afi[eaz` trei butoane Yes, No [i Cancel. public static int showConfirmDialog(Component par, Object mes);. Metoda returneaz` un \ntreg a c`rui valoare este dat` de butonul pe care-l apas` utilizatorul: 0 pentru Yes, 1 pentru No sau 2 pentru Cancel. Observa]ie: de fapt, se returneaz` indicele butonului ap`sat: Yes are 0 pentru c` este primul buton, No are 1 pentru c` este al doilea buton, iar Cancel are 2 deoarece este al treilea buton. Exemplu: secven]a urm`toare testeaz`, prin afi[are, valorile returnate de showConfirmDialog(): int a=125; int rasp= JOptionPane.showConfirmDialog(this,"a="+a+"?"); System.out.println(rasp); 10.7.8.4. Cutii de dialog cu opţiuni Aceste cutii de dialog sunt mai complexe. Ele permit s` select`m un set de butoane (vom vedea cum) [i s` le schimb`m numele conform propriilor dorin]e! public static int showOptionDialog (Component f_par, Object mesaj, String titlu, int tip_optiune, int tip_mesaj, Icon icon, Object[] vect, Object buton_selectat_initial) Parametrii metodei sunt: Component f_par - fereastra p`rinte; Object mesaj - [irul de caractere care apare afi[at \n cutie; String titlu - titlul ferestrei; 224 Bazele programării în Java int tip_optiune - se alege una dintre op]iunile urm`toare pentru a preciza tipul butoanelor (DEFAULT_OPTION, YES_NO_OPTION, YES_NO_CANCEL_OPTION, OK_CANCEL_OPTION); int tip_mesaj - are ca efect selectarea unei mici imagini care este afi[at` pe cutie. Astfel avem valorile: ERROR_MESSAGE INFORMATON_MESSAGE WARNING_MESSAGE QUESTION_MESSAGE Icon icon - icon-ul ferestrei; Object[] vect - vector de obiecte cu numele butoanelor; Object buton_selectat_initial - butonul care este ini]ial. selectat Exemplu: \n programul urm`tor se afi[eaz` o astfel de cutie \n care numele butoanelor sunt buton 1, buton 2, buton 3. La ap`sarea unui buton se afi[eaz` un mesaj care precizeaz` numele butonului ap`sat. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Apasa"); x.add(A); A.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { Object[] butoane = {"Buton 1","Buton 2","Buton 3"}; int n = JOptionPane.showOptionDialog(this, "Apasati un buton", "Test showOptionDialog", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, butoane, butoane[2]); if (n==0) JOptionPane.showMessageDialog(this, " butonul 1"); else if (n==1) JOptionPane.showMessageDialog(this, " butonul 2"); else JOptionPane.showMessageDialog(this, " butonul 3"); } } public class pv1 { public static void main(String args[]) { Fer fp=new Fer("Fereastra cu buton") } } Capitolul 10. Iniţiere în programarea vizuală 225 10.7.9. Componente de tip JTextArea Componentele de acest tip permit utilizatorului s` introduc` text pe mai multe linii. Se poate utiliza un singur font, de o singur` m`rime! Un astfel de text, cu un singur font, care nu permite s` fie formatat se nume[te text plan. Cele mai importante metode ale clasei sunt: JTextArea() - constructor. void append(String S) - adaug` la sf@r[itul [irului re]inut de component` un alt [ir. void insert(String s, int pozitie) - insereaz` \n text, \ncep@nd de la pozitie un [ir de caractere. Dac` pozitie dep`[e[te indicele ultimului caracter, atunci inserarea se face la sf@r[itul [irului re]inut de component`. void replaceRange(String str, int start, int end) \nlocuie[te [irul dintre indicii start [i end cu [irul transmis ca parametru. Evident, dac` acesta din urm` este vid, se [terge \ntreg textul. setFont(Font f) - seteaz` fontul utilizat. String getText() - returneaz` [irul de caractere con]inut de component` (inclusiv dac` el con]ine newline, altfel spus, mai multe paragrafe). void setText(String S) JTextArea s` re]in` [irul S. void setBackground(Color c) - seteaz` culoarea de fond a suprafe]ei care afi[eaz` literele. String selectat. void selectAll() - selecteaz` \ntreg textul re]inut de component`. int getSelectionStart() - returneaz` indicele primului caracter selectat. int getSelectionEnd() selectat. void setLineWrap(boolean v) - dac` re]ine true, seteaz` obiectul ca textul scris f`r` newline (adic` un singur paragraf) s` se afi[eze pe mai multe r@nduri (\n cazul \n care nu \ncape pe l`]ime). Dac` re]ine false, acesta este afi[at pe o singur` linie, chiar dac`, la un moment dat, nu este toat` vizibil`. getSelectedText() - - - determin` returneaz` ca obiectul [irul de de tip caractere returneaz` indicele ultimului caracter 226 Bazele programării în Java Obiectele de tip JTextArea nu se afi[eaz` pe fereastr` \n mod direct, ci prin intermediul altor obiecte de tip JScrollPane, asem`n`toare obiectelor de tip JPanel, dar care permit ata[area unor bare de scroll, a[a cum se vede mai jos: JScrollPane panel = new JScrollPane(t); panel.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWA YS); panel.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ ALWAYS); Exemplu: programul urm`tor afi[eaz` o component` de tip JTextArea [i un meniu. Utilizatorul introduce un text la alegerea sa. Textul poate fi salvat cu ajutorul meniului (File si Save) [i poate fi recuperat tot cu ajutorul meniului (File [i Open). Pentru simplificarea programului fi[ierul \n care se salveaz` este \ntotdeauna test.txt. |nainte de a studia programul, recomand o scurt` recapitulare a lucrului cu fi[iere. import import import import import java.io.*; java.util.*; java.awt.*; java.awt.event.*; javax.swing.*; class Fer extends JFrame implements ActionListener { JTextArea t; public Fer(String titlu) { super(titlu); setSize(200,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new GridLayout()); JMenuBar bara = new JMenuBar(); JMenu meniu1 = new JMenu("File"); bara.add(meniu1); JMenuItem item11 = new JMenuItem("Open"); item11.addActionListener(this); meniu1.add(item11); JMenuItem item12 = new JMenuItem("Save"); item12.addActionListener(this); meniu1.add(item12); setJMenuBar(bara); t=new JTextArea(); t.setLineWrap(true); JScrollPane panel = new JScrollPane(t); panel.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); panel.setHorizontalScrollBarPolicy (JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); x.add(panel); setVisible(true); } Capitolul 10. Iniţiere în programarea vizuală 227 void scriuFisier() throws IOException { FileOutputStream f=new FileOutputStream("test.txt"); PrintStream fchar=new PrintStream (f); StringTokenizer tok=new StringTokenizer(t.getText(),"\n"); while (tok.hasMoreTokens()) fchar.println(tok.nextToken()); fchar.close(); } void citFisier() throws IOException { FileInputStream f=new FileInputStream("test.txt"); InputStreamReader fchar=new InputStreamReader (f); BufferedReader buf = new BufferedReader(fchar); t.setText(""); String linie; while ((linie=buf.readLine() )!=null) t.append(linie+"\n"); } public void actionPerformed (ActionEvent e) { if( e.getActionCommand().compareTo("Save")==0) // Daca s-a selectat Save { try {scriuFisier(); } catch (Exception excp) {} } else // Daca s-a selectat Open { try {citFisier(); } catch (Exception excp) {} } } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Fereastra din care pot introduce textul"); } } 10.7.10. Componente de tip JProgressBar Astfel de componente, numite bare de progres, se utilizeaz` atunci c@nd programul efectueaz` anumite opera]ii consumatoare de timp [i se dore[te informarea utilizatorului asupra timpului r`mas pentru executarea opera]iei respective. Clasa JProgressBar con]ine urm`toarele metode mai importante: JProgressBar() - constructor; void setMinimum(int a) - memoreaz` valoarea componenta indic` faptul c` nu s-a efectuat nimic; la care void setMaximum(int b) - memoreaz` valoarea componenta indic` faptul c` opera]ia este terminat`; la care void setValue(int c) - seteaz` valoarea pe care o re]ine componenta la un moment dat. Ea trebuie s` fie \ntre valorile a [i b, setate cu setMinimum() [i setMaximum(). 228 Bazele programării în Java void setStringPainted(boolean b) dac` prime[te parametru true, seteaz` bara ca s` afi[eze un [ir de caractere. void setString(String s) - seteaz` [irul de caractere care va fi afi[at de bar`. Evident, trebuie ca s` fi fost executat` metoda anterioar` cu parametrul true. Exemplu: programul urm`tor, la ap`sarea butonului Start, “pune \n mi[care” o bar` de progres. |nainte de a-l studia, revede]i fire de execu]ie. Bara “se mi[c`” \ntr-un fir de execu]ie separat de program. Lansarea firului de execu]ie se face la ap`sarea butonului. Firul de execu]ie este oprit, temporar, la fiecare actualizare a valorii re]inute de bar`. import java.awt.*; import java.awt.event.*; import javax.swing.*; class AcBara extends Thread { JProgressBar bara; void ref(JProgressBar bara) { this.bara=bara; } public void run() { for (int i=0;i<=1000;i++) { bara.setValue(i); bara.setString(""+i/10+"%"); try {sleep(10);} catch (Exception e) { } } } } class Fer extends JFrame implements ActionListener { JProgressBar bara; AcBara t; public Fer(String titlu) { super(titlu); setSize(200,100); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Start"); x.add(A); A.addActionListener(this); bara = new JProgressBar(); bara.setMinimum(0); bara.setMaximum(1000); bara.setStringPainted(true); x.add(bara); setVisible(true); } public void actionPerformed (ActionEvent e) { if (t==null) { t= new AcBara(); t.ref(bara); t.start();} } } ca Capitolul 10. Iniţiere în programarea vizuală 229 public class pv { public static void main(String args[]) { Fer fp=new Fer("Bara de progres"); WindowListener t=new Evfer(); fp.addWindowListener(t); } } |ntrebare: de ce a fost necesar ca “punerea \n mi[care” a barei s` se fac` \ntr-un fir de execu]ie [i n-am descris secven]a de instruc]iuni \n metoda care se ruleaz` la ap`sarea butonului (actionPerformed()) ? R`spuns: chiar merit` \ncercat! Exerci]iu! Dar, ve]i r`m@ne dezam`gi]i. Practic, c@nd ap`sa]i butonul, acesta r`m@ne ap`sat p@n` se desf`[oar` \ntreaga activitate consumatoare de timp. |n acest timp bara r`m@ne nemodificat`. La sf@r[it, ea va indica brusc 100%. De ce? Cum crede]i c` se actualizeaz` valoarea ar`tat` de bar` atunci c@nd se utilizeaz` setValue()? Nu este o simpl` memorare, a[a cum pare la prima vedere! Se memoreaz` valoarea [i se genereaz` un eveniment, \n urma c`ruia se declan[eaz` o metod` a barei care actualizeaz` desenul pentru a indica progresul. Atunci c@nd ap`s`m butonul se declan[eaz` un eveniment. P@n` c@nd acesta nu este tratat, adic` p@n` c@nd nu se ruleaz` metoda actionPerformed(), celelalte evenimente sunt \n a[teptare. Prin urmare, la sf@r[it, sunt tratate rapid toate celelalte evenimente de redesenare a barei, dar ac]iunea dureaz` at@t de pu]in, \nc@t noi vedem c` bara arat` deodat` 100%. 10.7.11. Componente de tip JSpinner Componentele de tip JSpinner sunt un tip special de liste, \n care o valoare se poate selecta cu ajutorul unor s`ge]i. Principalele metode ale acestei clase sunt: JSpinner(SpinnerModel model) SpinnerModel este o interfa]`. void setValue(Object value) - componenta va afi[a valoarea setat`. Aten]ie la parametru, este de tip Object. Aceast` clas` st` la baza ierarhiei de clase din Java. Prin urmare, parametrul poate primi o referin]` c`tre orice obiect, \n particular pentru un \ntreg. Pentru a folosi metoda vom crea un obiect de tip Integer pe care \l transmitem ca parametru. Exemplu: s =new JSpinner (m); s.setValue(new Integer (5)); - constructor, unde parametrul 230 Bazele programării în Java object getValue() - returneaz` valoarea selectat` de utilizator. Valoarea selectat` este de tip Object. Pentru a o transforma \ntr-un \ntreg, vom proceda ca mai jos: Exemplu: pentru componenta JSpinner s; int k =((Integer) s.getValue()).intValue(); unde =(Integer) s.getValue() este o referin]` c`tre un obiect Integer, c`reia i se aplic` metoda intValue() care returneaz` valoarea re]inut` de ea. O implementare a interfe]ei SpinnerModel SpinnerNumberModel, care are constructorul: este dat` de clasa SpinnerNumberModel(int v_initiala, int v_min, int v_max, int pas) Constructorul seteaz` o plaj` de valori cuprins` \ntre v_min [i v_max, o valoare care va fi afi[at` ini]ial de component` (v_initiala) [i pasul de afi[are al valorilor (pas). Exemplu: programul urm`tor afi[eaz` o component` de tip JSpinner [i un buton. La ap`sarea butonului se afi[eaz` valoarea selectat` \n component`. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { JSpinner s; public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); SpinnerNumberModel m= new SpinnerNumberModel (0,-10, 10, 1); s =new JSpinner (m); x.add(s); JButton A=new JButton("Ce-am selectat?"); x.add(A); A.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { System.out.println(((Integer) s.getValue()).intValue());} } public class pv { public static void main(String args[]) { Fer fp=new Fer("JSpinner"); } } Capitolul 10. Iniţiere în programarea vizuală 231 10.7.12. Cutii de tip Open / Save Astfel de cutii se utilizeaz` \n opera]iile de \nc`rcare [i salvare a fi[ierelor. Cu ajutorul lor se selecteaz` fi[ierele [i folder-ele necesare acestor opera]ii. Ele pot fi ob]inute cu metodele clasei JFileChooser(). Cele mai importante metode ale acestei clase sunt: JFileChooser() - constructor; int showOpenDialog(Component fer_parinte) - afi[eaz` o cutie de dialog de tip Open, a[a cum este cea de mai jos: Valoarea returnat` este 0, dac` s-a ap`sat butonul Open sau este 1 dac` s-a ap`sat butonul Close. Rolul ei este ca, atunci c@nd a fost selectat un anumit fi[ier [i s-a ap`sat Open, obiectul de tip JFileChooser s` con]in` date despre fi[ierul selectat. int showSaveDialog(Component fer_parinte) - afi[eaz` o cutie de dialog de tip Save, asem`n`toare cu cutia precedent`. Valoarea returnat` este 0 dac` s-a ap`sat butonul Save [i 1 dac` s-a ap`sat butonul Cancel. Ca [i cutia precedent` (de tip Open), rolul ei este ca obiectul de tip JFileChooser s` con]in` date despre fi[ierul salvat. Aten]ie: cutia de tip Open nu deschide fi[ierul, iar cutia de tip Save nu-l salveaz`. Rolul lor este de a ob]ine informa]iile necesare deschiderii [i salv`rii fi[ierelor. File getSelectedFile() - metoda returneaz`, at@t \n cazul salv`rii, c@t [i \n cazul deschiderii fi[ierelor, date despre fi[ierul selectat (furnizate de showOpenDialog() [i showSaveDialog()). Pentru a putea accesa aceste informa]ii, trebuie s` studiem c@teva metode ale tipului File. 232 Bazele programării în Java void addChoosableFileFilter(Filter x); - metoda se utilizeaz` pentru a ad`uga un filtru cutiilor de tip Open [i Save. Despre filtre vom \nv`]a \n cadrul acestui paragraf. setCurrentDirectory(File f) - seteaz` cutia astfel \nc@t s` se deschid` \ntr-un anumit folder. Clasa File. Cele mai importante metode ale acestei clase sunt: File() - constructor; File(String nume) - construie[te un obiect care con]ine numele unui fi[ier (folder). boolean isDirectory() - returneaz` true dac` fi[ierul re]inut de obiect este folder (folder-ele sunt fi[iere speciale), sau false \n caz contrar. String getName() - returneaz` numele fi[ierului. String getPath() - returneaz` numele \ntreg al fi[ierului, inclusiv calea c`tre el. Filtre. |n partea de jos a cutiilor de tip Open sau Save se g`se[te o list` (File Name). Dac` programul nostru nu con]ine un filtru, implicit se afi[eaz` doar op]iunea All Files, adic` cutiile vizualizeaz` toate folder-ele [i toate fi[ierele, indiferent de tipul lor. |n cazul \n care dorim ca programul s` con]in` filtre, adic` s` se vizualizeze doar fi[ierele de un anumit tip (sau tipuri), vom utiliza clasa FileFilter. Clasa FileFilter este abstract`. Pentru a crea un filtru este necesar s` rescriem dou` metode ale sale: public String getDescription() public boolean accept(File f) - metod` care returneaz` true pentru un fi[ier care, fie are o extensie dorit`, fie este de tip folder, altfel returneaz` false. Dac` metoda returneaz` true, fi[ierul este aflat de cutiile Open/Save, altfel acesta nu este afi[at. - trebuie s` returneze un [ir de caractere care va fi afi[at de lista File of Type, list` con]inut` de cutiile Open [i Save. Exemple de utilizare a cutiilor Open [i Save: 1. Programul urm`tor afi[eaz` o fereastr` cu dou` butoane: Open [i Save. La ap`sarea unuia dintre ele se afi[eaz` cutia respectiv`. Dup` ce utilizatorul selecteaz` fi[ierul (pentru Open) sau selecteaz` folder-ul [i scrie \n editul corespunz`tor numele fi[ierului, \n fereastra CMD se va afi[a numele fi[ierului selectat, inclusiv calea. Cutiile Open [i Save vor afi[a doar folder-ele [i fi[ierele cu extensiile .java [i .txt. Capitolul 10. Iniţiere în programarea vizuală import import import import 233 java.io.*; java.awt.*; java.awt.event.*; javax.swing.*; class Filtre extends javax.swing.filechooser.FileFilter { // redefinesc cele doua functii pentru filtru public boolean accept(File f) { if (f.isDirectory()) { return true;} String nume_fis = f.getName(); return nume_fis.endsWith(".java") || nume_fis.endsWith(".txt") ; } public String getDescription() { return "*.java" + " "+"*.txt" ;} } class Fer extends JFrame implements ActionListener { public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Open"); x.add(A); JButton B=new JButton("Save"); x.add(B); A.addActionListener(this); B.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { if (e.getActionCommand().compareTo("Open")==0) // daca am apasat Open { JFileChooser c_op = new JFileChooser(); c_op.addChoosableFileFilter(new Filtre()); int valRet = c_op.showOpenDialog(this); if (valRet==0) { File f=c_op.getSelectedFile(); System.out.println(f.getPath());} } else // daca am apasat Save { JFileChooser c_save = new JFileChooser(); c_save.addChoosableFileFilter(new Filtre()); int valRet = c_save.showSaveDialog(this); if (valRet==0) { File f=c_save.getSelectedFile(); System.out.println(f.getPath());} } } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Open/Save"); } } 234 Bazele programării în Java 2. Programul de mai jos este un editor primitiv de fi[iere text. El nu con]ine \n meniu dec@t dou` op]iuni: Open [i Save. Oricare dintre ele are ca efect afi[area cutiilor respective [i salvarea sau deschiderea cu afi[are a unui fi[ier cu una din extensiile .java [i .txt. Afi[area fi[ierului se face cu ajutorul unei componente de tip JTextArea. import import import import import java.io.*; java.util.*; java.awt.*; java.awt.event.*; javax.swing.*; class Filtre extends javax.swing.filechooser.FileFilter public boolean accept(File f) { if (f.isDirectory()) {return true;} String nume_fis = f.getName(); return nume_fis.endsWith(".java") || nume_fis.endsWith(".txt"); } public String getDescription() { return "*.java" + " "+"*.txt" ;} } class Fer extends JFrame implements ActionListener { JTextArea t; public Fer(String titlu) { super(titlu); setSize(200,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new GridLayout()); JMenuBar bara = new JMenuBar(); JMenu meniu1 = new JMenu("File"); bara.add(meniu1); JMenuItem item11 = new JMenuItem("Open"); item11.addActionListener(this); meniu1.add(item11); JMenuItem item12 = new JMenuItem("Save"); item12.addActionListener(this); meniu1.add(item12); setJMenuBar(bara); t=new JTextArea(); t.setLineWrap(true); JScrollPane panel = new JScrollPane(t); panel.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); panel.setHorizontalScrollBarPolicy (JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); x.add(panel); setVisible(true); } void scriuFisier(String nume) throws IOException { FileOutputStream f=new FileOutputStream(nume); PrintStream fchar=new PrintStream (f); StringTokenizer tok=new StringTokenizer(t.getText(),"\n"); while (tok.hasMoreTokens()) fchar.println(tok.nextToken()); fchar.close(); } Capitolul 10. Iniţiere în programarea vizuală 235 void citFisier(String nume) throws IOException { FileInputStream f=new FileInputStream(nume); InputStreamReader fchar=new InputStreamReader (f); BufferedReader buf = new BufferedReader(fchar); t.setText(""); String linie; while ((linie=buf.readLine() )!=null) t.append(linie+"\n"); } public void actionPerformed (ActionEvent e) { if( e.getActionCommand().compareTo("Open")==0) { JFileChooser c_op = new JFileChooser(); c_op.addChoosableFileFilter(new Filtre()); int valRet = c_op.showOpenDialog(this); if (valRet==0) { File f=c_op.getSelectedFile(); { try { citFisier(f.getPath()); } catch (Exception excp) {} } } } else { JFileChooser c_save = new JFileChooser(); c_save.addChoosableFileFilter(new Filtre()); int valRet = c_save.showSaveDialog(this); if (valRet==0) { File f=c_save.getSelectedFile(); { try {scriuFisier(f.getPath()); } catch (Exception excp) {} } } } } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Fereastra din care pot introduce textul"); } } 10.7.13. Componente de tip JColorChooser |n programarea vizual` culorile au un rol fundamental. Pentru a u[ura selectarea culorilor, Java pune la dispozi]ia programatorilor clasa JColorChooser. |n linii mari, aceast` clas` permite afi[area unui panou prin care se selecteaz` u[or culorile (fie direct, fie folosind sistemul RGB, fie folosind sistemul HSL). Iat` cele mai importante metode ale acestei clase: JColorChooser() - constructor. |n panoul culorilor este automat selectat` culoarea alb`; JColorChooser(Color c) - constructor. |n panoul culorilor este automat selectat` culoarea transmis` ca parametru; 236 Bazele programării în Java static Color showColorDialog (Component parinte, String mes, Color c) - lanseaz`, modal, o cutie de dialog care con]ine panoul culorilor. Dup` cum observa]i, metoda returneaz` culoarea selectat` (dac` se apas` butonul OK, iar dac` se apas` Cancel se returneaz` null). Parametrii sunt: parinte (fereastra p`rinte), mes (mesaj ce se afi[eaz` pe bara de titlu a cutiei) [i c (culoarea ini]ial setat` \n cutie). Utilizarea acestei metode este cel mai simplu mecanism prin care utilizatorul poate selecta culoarea. Color getColor() - returneaz` culoarea selectat` \n cutie. Exemplu. Din fereastra principal`, la ap`sarea unui buton se afi[eaz` o cutie de dialog specific` pentru selectarea culorii. Culoarea selectat` va fi culoarea de fond a ferestrei principale. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { Container x; public Fer(String titlu) { super(titlu); setSize(200,100); x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Alta culoare"); x.add(A); A.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { Color c=JColorChooser.showDialog (this, "Alege culoarea", Color.red); if (c!=null) x.setBackground(c); } } public class pv1 { public static void main(String args[]) { Fer fp=new Fer("Schimbarea culorii ferestrei"); } } Capitolul 10. Iniţiere în programarea vizuală 237 10.7.14. Componente de tip JToolBar O astfel de component` creeaz` o “bar` cu unelte”. Pe ea se a[eaz` numeroase alte componente, \ntocmai ca pe un panel. De regul` se g`se[te \n partea de sus a ferestrei, dar \ntotdeauna sub meniu. Clasa JToolBar con]ine urm`toarele metode mai importante: JToolBar() - constructor, creeaz` o bar` de unelte pozi]ionat` orizontal; JToolBar(int orientare) - creeaz` o bar` de unelte orientat` fie orizontal, orientare va avea valoarea JToolBar.HORIZONTAL, fie vertical, orientare va avea valoarea JToolBar.VERTICAL. Diferen]a de orientare afecteaz` modul \n care sunt a[ezate pe ea diferitele componente (pe orizontal sau pe vertical). Component add(Component comp) - adaug` o component`; void addSeparator() - adaug` un separator (spa]iu liber) \ntre componente. Exemplu: mai jos pute]i observa programul care afi[eaz` o ferastr` cu o bar` de unelte [i \n rest, un panel (component` de tip JPanel): import java.awt.*; import javax.swing.*; class Fer extends JFrame { public Fer(String titlu) { super(titlu); setSize(600,800); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); JToolBar bara=new JToolBar(); bara.setBackground(Color.red); bara.setLayout(new FlowLayout(FlowLayout.LEFT)); JPanel panel=new JPanel(); panel.setBackground(Color.yellow); JComboBox lista=new JComboBox (); x.setLayout(new BorderLayout()); x.add(bara,BorderLayout.NORTH); x.add(panel,BorderLayout.CENTER); JButton A=new JButton("buton 1"); bara.add(A); A.setPreferredSize(new Dimension (70,30)); JButton B=new JButton("buton 2"); B.setPreferredSize(new Dimension (70,30)); bara.add(B); 238 Bazele programării în Java bara.addSeparator(); lista.addItem("Optiunea 1"); lista.addItem("Optiunea 2"); bara.add(lista); lista.setPreferredSize(new Dimension (100,30)); setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Bara cu unelte"); } } Observa]ii: 1. Pentru a pozi]iona bara orizontal se prefer` gestionarul GridLayout [i bara se a[eaz` \n nord. 2 |n aceste condi]ii, panelul s-a aranjat \n centru. Cum celelalte trei componente lipsesc, componenta din centru ocup` toat` linia din mijloc, iar linia din mijloc ocup` [i partea de sud! 3. Pentru bar` se prefer` gestionarul FlowLayout (FlowLayout.LEFT) care aranjeaz` componentele pe bar` de la dreapta la st@nga, dar aliniate st@nga! 4. Pentru a ne asigura c` butoanele [i lista au aceea[i \n`l]ime, am preferat dimensionarea lor prin setPreferredSize(). 5. |ntre cele dou` butoane [i list` a fost introdus un separator. Observa]il \n imaginea de pe pagina anterioar`! 10.7.15. Componente de tip JTable Cu ajutorul componentelor de acest tip se creeaz` tabele. continuare prezent`m cele mai importante metode ale acestui tip. |n JTable(Object[][] celule, object[] cap_t) - constructor. Parametrul celule este o matrice de referin]e c`tre obiectele afi[ate de celulele tabelului, iar cap_t este un vector de referin]e c`tre obiectele afi[ate de capul de tabel. Num`rul coloanelor matricei de referin]e celule trebuie s` coincid` cu num`rul elementelor vectorului de referin]e cap_t [i reprezint` num`rul coloanelor din tabel. |nainte de a da primul exemplu de tabel, trebuie precizat c` aceast` component` se plaseaz`, de obicei, pe o component` de tip JScroolPane. public void setPreferredScrollableViewportSize(Dimension dim) are rolul de preciza dimensiunea tabelului [i faptul c` acesta trebuie s` con]in` o bara scroll vertical` (dac` tabelul are suficiente linii astfel \nc@t s` nu \ncap` \n totalitate \n spa]iul generat de dim). Capitolul 10. Iniţiere în programarea vizuală 239 Exemplu: tabelul al`turat a fost ob]inut cu secven]a de mai jos: class Fer extends JFrame { public Fer(String titlu) { super(titlu);setSize(600,800); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Object[][] date = { {"x(0,0)", "x(0,1)","x(0,2)"}, {"x(1,0)", "x(1,1)","x(1,2)"} }; String[] cap_tabel = {"Coloana 1", "Coloana 2", "Coloana 3"}; Container x=getContentPane(); x.setLayout(new FlowLayout()); JTable table = new JTable(date, cap_tabel); JScrollPane panel = new JScrollPane(table); table.setPreferredScrollableViewportSize (new Dimension(200, 30)); x.add(panel);setVisible(true); } } Dac` dorim, putem inversa ordinea coloanelor \n tabel prin drag and drop. |ncerca]i! Tabelul este, de fapt, format din dou` componente: tabelul propriu-zis (de tip JTable) [i capul de tabel (de tip JTableHeader). JTableHeader getTableHeader()- metoda returneaz` o referin]` c`tre capul de tabel. Imediat ce cre`m un tabel ne punem problema culorilor de fond [i de scriere, at@t pentru capul de tabel c@t [i pentru tabelul propriu-zis. Dac` ambele sunt componente, atunci putem utiliza metodele clasei JComponent: setBackground(), setForeground() [i setColor(). Exemplu: ad`uga]i exemplului anterior secven]a de mai jos [i ve]i ob]ine efectul scontat! // pentru tabel table.setFont(new Font("Arial",Font.ITALIC, 10)); table.setBackground(Color.GREEN); table.setForeground(Color.RED); // pentru capul de tabel JTableHeader cap= table.getTableHeader(); cap.setFont(new Font("Arial",Font.BOLD, 12)); cap.setBackground(Color.YELLOW); cap.setForeground(Color.RED); Observa]i faptul c` fiecare celul` a tabelului este editabil`. Aceasta \nseamn` c` dac` execut`m click pe celula respectiv`, aceasta se comport` ca un edit oarecare. De aici, rezult` faptul c` un tabel poate fi folosit [i pentru introducerea datelor, nu doar pentru afi[area lor! 240 Bazele programării în Java Object getValueAt(int linie, int coloana) referin]` c`tre obiectul memorat de celula respectiv`; void setValueAt(Object ref, int linie, int coloana) memoreaz` referin]a c`tre obiect \n linia [i coloana dat` de indicii transmi[i. JTable(int n_linii, int n_coloane) - este un alt constructor al tabelului, \n care se creeaz` un tabel n_linii [i n_coloane). Liniile sunt numerotate \ncep@nd de la 0. De asemenea, coloanele sunt numerotate \ncep@nd de la 0. \ntoarce o Exemplu: programul urm`tor creeaz` un tabel f`r` date cu 2 linii [i 4 coloane. Utilizatorul introduce date \n fiecare celul` a tabelului. La ap`sarea butonului se afi[eaz`, \n fereastra CMD, valorile re]inute de fiecare celul`. Observa]i faptul c` numele coloanelor a fost dat automat. import import import import java.awt.*; javax.swing.*; javax.swing.table.*; java.awt.event.*; class Fer extends JFrame implements ActionListener { JTable table; public Fer(String titlu) { super(titlu);setSize(600,800); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout()); table = new JTable(3, 4); JScrollPane panel = new JScrollPane(table); table.setPreferredScrollableViewportSize (new Dimension(200, 30)); x.add(panel); JButton A=new JButton("Afiseaza"); x.add(A); A.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { if (table.getCellEditor() != null) table.getCellEditor().stopCellEditing(); for (int i=0;i<2;i++) for (int j=0;j<4;j++) System.out.println(i+" "+j+" "+table.getValueAt(i,j)); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Tabel"); } } Capitolul 10. Iniţiere în programarea vizuală 241 S` urm`rim metoda actionPerformed(). Ce rost are acel if? Atunci c@nd se scriu datele \ntr-o celul`, p@n` nu s-a trecut la celula urm`toare (click pe suprafa]a ei), data con]inut` de ea nu este memorat` [i prin urmare, la afi[are va ap`rea null (obiectul null). Pentru a evita aceasta, s-a utilizat metoda getCellEditor() a clasei JTable. TableCellEditor getCellEditor() - metoda returneaz` o referin]` c`tre un obiect dac` o celul` a tabelului este sub editare [i null \n caz contrar. TableCellEditor este o interfa]` care, evident, este implementat`. F`r` a intra \n am`nunte, interfa]a con]ine antetul metodei stopCellEditing(), metod` care are rolul de a stopa editarea [i, prin urmare, de memorare a tuturor datelor introduse \n tabel. |n continuare, vedem cum putem proiecta capul de tabel! Clasa JTable con]ine metodele: TableColumnModel getColumnModel(). TableColumnModel este o interfa]`, implementat` de o anumit` clas` (DefaultTableColumnModel). Prin urmare, putem utiliza metodele clasei pornind de la referin]a \ntoars` de metod`. Cu ajutorul lor proiect`m capul de tabel. TableColumn getColumn(int index) - returneaz` o referin]` c`tre un obiect TableColumn. Un astfel de obiect con]ine toate atributele unei coloane a tabelului. Iat` c@teva metode, mai importante ale acestui obiect: void setHeaderValue(Object ob) coloana respectiv` (numele coloanei). setPreferredWidth(int lat) - seteaz` l`]imea coloanei. setResizable(boolean v); coloane se pot deplasa, astfel [i de utilizator. Dac` metoda marginile nu mai pot fi stabilite - seteaz` obiectul afi[at de - \n mod normal, marginile unei \nc@t l`]imea coloanei poate fi stabilit` prime[te ca parametru valoarea false, de utilizator. Exemplu: secven]a de mai jos ne arat` cum putem construi un tabel precum cel al`turat, care con]ine numele coloanelor, dar \n care, primei coloane nu i se poate modifica l`]imea (implicit, [i celeilalte coloane). table = new JTable(6, 2); TableColumnModel mColoane=table.getColumnModel(); TableColumn coloana=mColoane.getColumn(0); coloana.setHeaderValue("Coloana 1"); 242 Bazele programării în Java coloana.setPreferredWidth(150); coloana.setResizable(false); coloana=mColoane.getColumn(1); coloana.setHeaderValue("Coloana 2"); JScrollPane panel = new JScrollPane(table); table.setPreferredScrollableViewportSize (new Dimension(200, 80)); Alte metode ale clasei JTable: void setGridColor(Color c) - seteaz` culoarea liniilor care separ` celulele tabelului. void setRowHeight(int inalt) tabelului (\n pixeli). void setSelectionBackground(Color c) - seteaz` culoarea liniei selectate (atunci c@nd se execut` click pe o celul`, se selecteaz` \ntreaga linie). void setSelectionForeground(Color c) - seteaz` culoarea cu care se scrie \n linia selectat` (mai pu]in celula \n care se editeaz`). setIntercellSpacing(Dimension dim) - seteaz` spa]iile \ntre linii [i coloane. Aceasta nu afecteaz` liniile separatoare dintre celule (vecine), ci numai spa]iul dintre p`rtile lor editabile. Primul parametru pentru dim este pentru linii, al doilea parametru este pentru coloane. void setShowHorizontalLines(boolean v) - dac` parametrul este false, atunci nu mai sunt trasate liniile orizontale ale tabelului. setShowGrid(boolean v) dac` parametrul este false, atunci nu mai sunt trasate liniile orizontale [i verticale ale tabelului. - seteaz` \n`l]imea liniilor 10.8. Mai mult despre clasa Container Este momentul s` analiz`m modul \n care fereastra aplica]iei re]ine componentele grafice ata[ate. Logic vorbind, este nevoie de o variabil`, asem`n`toare unui vector, \n care fiecare component` a sa va re]ine referin]e c`tre componentele grafice. De asemenea, este necesar` [i o variabil` care re]ine o referin]` c`tre gestionarul de pozi]ionare. Atunci c@nd ata[`m ferestrei componente grafice, mai \nt@i declar`m o referin]` la un obiect al clasei Container [i o ini]ializ`m cu adresa obiectului de tip Container al ferestrei (returnat` de metoda clasei JFrame, numit` getContentPane()): Exemplu: Container x=getContentPane();. Capitolul 10. Iniţiere în programarea vizuală 243 Clasa Container con]ine mai multe metode, dintre care le prezent`m pe urm`toarele: Component add(Component c); - adaug` o component` containerului. Cum orice component` este un obiect al unei clase derivate din clasa Component, parametrul metodei poate fi utilizat pentru a transmite referin]e c`tre orice tip de component`. P@n` \n prezent am folosit de multe ori aceast` metod`. int getComponentCount(); re]inute de container. returneaz` num`rul componentelor Spuneam c` un container este asem`n`tor unui vector. Astfel, prima component` ad`ugat` cu metoda de mai sus are indicele 0, a doua component` are indicele 1, [.a.m.d. Component getComponent(i); - returneaz` referin]a la componenta de indice i. Am precizat faptul c` tipurile tuturor componentelor grafice pe care le-am studiat sunt derivate din clasa Component, dar nu direct. Aceasta din urm` con]ine [i metodele: void setName(String name); metoda prin care unei componente, indiferent de tipul ei, i se poate ata[a un nume. Acesta poate fi folosit atunci c@nd trebuie s` detect`m o anumit` component` din container. String getName(); - metoda returneaz` numele componentei dat prin setName(). Prin operatorul de conversie explicit`, o referin]` de tip Component poate fi convertit` c`tre o referin]` la o component` de un anumit tip, numai dac` componenta propriu-zis` are tipul respectiv. De exemplu, dac` c este tip Component [i re]ine adresa unui obiect de tip JButton, atunci conversia JButton buton (JButton)c; este corect`. Dac` \ns` c re]ine adresa unei componente de tip JLabel, atunci prin conversia de mai sus se ob]ine o excep]ie. |n cazul componentelor de tip JPanel, lucrurile stau pu]in diferit, \n sensul c` pentru a depista componentele pe care le con]ine, vom utiliza metodele de mai jos (ale tipului JPanel): Ad`ugarea unei componente se face cu metoda add() a tipului JPanel, a[a cum suntem deja obi[nui]i; Component[] getComponents() returneaz` un vector de referin]e c`tre componente. 244 Bazele programării în Java Exemplu: programul urm`tor creeaz` o fereastr` cu diverse componente: un buton, o etichet` (obiect de tip JLabel) [i un panel (obiect de tip JPanel). Acesta din urm` con]ine un buton [i o etichet`. Toate componentele au primit un nume. La ap`sarea butonului Componente, se afi[eaz` numele tuturor componentelor din fereastr` [i panel. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { Container x; JPanel panel; public Fer(String titlu) { super(titlu);setSize(300,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); x=getContentPane(); x.setLayout(new FlowLayout ()); // Adaug elemente pe fereastra si panel JButton A=new JButton("Componente"); A.setName("Buton A"); x.add(A); JLabel et =new JLabel("O eticheta"); et.setName("Eticheta et");x.add(et); JTextField txt=new JTextField(20); txt.setName("edit-ul txt");x.add(txt); panel=new JPanel(new FlowLayout());panel.setName("panelul"); JButton B=new JButton("Buton pe panel"); B.setName("Buton pe panel");panel.add(B); JLabel et1 =new JLabel("Eticheta pe panel"); et1.setName("Eticheta pe panel"); panel.add(et1); x.add(panel); A.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { int nr_comp=x.getComponentCount(); System.out.println ("Numar componente atasate ferestrei="+nr_comp); // afisez numele componentelor de pe fereastra for(int i=0;i<nr_comp;i++) { Component c=x.getComponent(i); System.out.println(c.getName());} Component[] vect=panel.getComponents(); System.out.println ("Numar componente atasate panelului="+vect.length); // afisez numele componentelor de pe panel for(int i=0;i<vect.length;i++) { Component c=vect[i]; System.out.println(c.getName());} } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Fereastra cu diverse componente");} } Capitolul 10. Iniţiere în programarea vizuală 245 10.9. Cutii de dialog P@n` \n prezent am studiat numai cutiile de dialog predefinite. Desigur, cutiile predefinite sunt u[or de folosit, dar nu r`spund tuturor necesit`]ilor. Uneori, suntem obliga]i s` cre`m cutii de dialog care s` includ` componentele pe care le dorim. |n acest paragraf vom prezenta modul \n care putem construi cutiile de dialog dup` propria dorin]`. Pentru \nceput trebuie spus c` putem afi[a o cutie de dialog \n dou` feluri: A) Modal - dup` afi[area cutiei nu mai putem ac]iona asupra ferestrei din care aceasta a fost lansat`. B) Nemodal - de[i cutia este afi[at`, putem ac]iona [i asupra componentelor re]inute de cutie, dar [i asupra componentelor din fereastra din care aceasta a fost lansat`. Pentru a construi o cutie de dialog trebuie s` [tim c`: 1. Cutia de dialog propriu-zis` se ob]ine ca instan]iere a unei clase derivat` din clasa JDialog. Clasa JDialog con]ine constructorul: JDialog (Dialog fer_parinte,String prin care se specific` fereastra p`rinte comanda care a lansat-o), titlul ferestrei boolean, care dac` re]ine true, afi[area va false, afi[area va fi nemodal`. titlu,boolean modal) (fereastra care con]ine [i un parametru de tip fi modal`, iar dac` re]ine 2. Clasa JDialog, ca [i clasa JWindow au o superclas` comun` (Window). Aceasta are ca efect faptul c` putem construi cutia la fel cum am construit fereastra principal`. Exemplul (afi[are modal`) programul urm`tor afi[eaz` fereastra al`turat`: Dac` se apas` butonul “Afi[eaz` cutia” se afi[eaz` cutia de dialog al`turat`. Introduce]i \n edit un [ir oarecare de caractere [i ap`sa]i butonul “Inchide cutia!” Analiza]i modul \n care am detectat [irul de caractere introdus \n edit prin ap`sarea butonului “Ce-am citit?”. Va ap`rea cutia de dialog standard de mai jos: 246 Bazele programării în Java Prezent`m programul: import java.awt.*; import java.awt.event.*; import javax.swing.*; class Dial extends JDialog implements ActionListener { // Constructia cutiei de dialog JButton buton=new JButton("Inchide cutia!"); JTextField txt=new JTextField(10); Container y; String sir=txt.getText(); Dial (JFrame parinte,String mesaj, boolean modal) { super(parinte,mesaj,modal); y=getContentPane(); setSize(200,200); y.setLayout(new FlowLayout()); y.add(buton); y.add(txt); buton.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) // inchide cutia { setVisible(false);} } class Fer extends JFrame implements ActionListener { Dial cutie=null; public Fer(String titlu) { super(titlu); setSize(400,400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Afiseaza cutia"); x.add(A); A.addActionListener(this); JButton B=new JButton("Ce-am citit?"); x.add(B); B.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { //Daca a fost apasat butonul “Afiseaza cutia” if( e.getActionCommand().compareTo("Afiseaza cutia")==0) //daca cutia nu a fost afisata if (cutie==null) cutie=new Dial(this,"Cutie de dialog", true); // daca cutia a fost afisata else cutie.setVisible(true); Capitolul 10. Iniţiere în programarea vizuală 247 else //daca a fost apasat butonul “Ce-am citit?” if (cutie!=null) { // recuperez container-ul cutiei Container t=cutie.y; // recuperez referinta catre edit JTextField com=(JTextField)t.getComponent(1); // recuperez continutul edit-ului JOptionPane.showMessageDialog(this,com.getText()); } // daca vreau sa vad ce-am scris fara sa fi afisat cutia else JOptionPane.showMessageDialog (this,"Mai intai afiseaza cutia de dialog"); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Fereastra din care apelez cutia"); } } Observa]ii: A \nchide o fereastr` (cutie de dialog) \nseamn` a o face invizibil` (setVizible(false)). A deschide o fereastr`, deja creat`, care a fost \nchis` \nseamn` a o face vizibil` (setVizible(true)). Prin urmare, chiar dac` fereastra a fost \nchis`, pornind de la o referin]` c`tre container-ul ei, putem accesa componentele pe care fereastra (cutia de dialog) le con]ine, deoarece ea exist` \n memorie. Practic, datele din cutie se pot recupera pornind de la container-ul cutiei, iar dac` se dore[te, din cutie se pot accesa datele ferestrei pornind de la referin]a c`tre p`rintele cutiei, adic` fereastra. Exemplul (afi[are nemodal`). Programul de mai jos creeaz` o fereastr` cu un buton. La ap`sarea lui, se afi[eaz` o cutie de dialog cu dou` butoane. Prin ap`sarea oric`rui buton al cutiei, se schimb` culoarea de fond a ferestrei principale. Cutia de dialog este afi[at` nemodal! Practic, dac` ap`s`m un buton al ei, culoarea ferestrei principale se schimb` instantaneu, f`r` s` fim nevoi]i s` \nchidem cutia. 248 Bazele programării în Java import java.awt.*; import java.awt.event.*; import javax.swing.*; class Dial extends JDialog implements ActionListener { Container y; JFrame frs; Dial (JFrame parinte,String mesaj, boolean modal) { super(parinte,mesaj,modal); y=getContentPane(); frs=parinte; setSize(100,100); y.setLayout(new FlowLayout()); JButton b1=new JButton("Rosu"); y.add(b1); b1.addActionListener(this); JButton b2=new JButton("Galben"); y.add(b2); b2.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { Container z=frs.getContentPane(); if( e.getActionCommand().compareTo("Rosu")==0) z.setBackground(Color.red); else z.setBackground(Color.yellow); } } class Fer extends JFrame implements ActionListener { Dial cutie=null; public Fer(String titlu) { super(titlu); setSize(150,100); Container x=getContentPane(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); x.setLayout(new FlowLayout ()); JButton A=new JButton("Seteaza culoarea"); x.add(A); A.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { if (cutie==null) cutie=new Dial(this,"Seteaza culoarea", false); else cutie.setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Culori"); } } Exemplul Din fereastra principal` se afi[eaz` nemodal o cutie de dialog care con]ine un buton [i o component` de tip JColorChooser. Utilizatorul selecteaz` culoarea [i apas` butonul. Automat (f`r` \nchiderea cutiei), fereastra principal` va avea culoarea selectat`. Capitolul 10. Iniţiere în programarea vizuală import java.awt.*; import java.awt.event.*; import javax.swing.*; class Dial extends JDialog implements ActionListener { Container y; JColorChooser col; JFrame frs; Dial (JFrame parinte,String mesaj, boolean modal) { super(parinte,mesaj,modal); y=getContentPane(); frs=parinte; setSize(500,500); y.setLayout(new FlowLayout()); JButton b=new JButton("Gata!"); y.add(b); b.addActionListener(this); col = new JColorChooser(Color.yellow); y.add(col); setVisible(true); } public void actionPerformed (ActionEvent e) { Container z=frs.getContentPane(); z.setBackground(col.getColor()); } } class Fer extends JFrame implements ActionListener { Dial cutie=null; public Fer(String titlu) { super(titlu); setSize(150,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Seteaza culoarea"); x.add(A); A.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { if (cutie==null) cutie=new Dial (this,"Seteaza culoarea",false); else cutie.setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Culori"); } } 249 250 Bazele programării în Java 10.10. Clasa Graphics 10.10.1. Afişarea imaginilor Pentru a afi[a o imagine aflat` \ntr-un fi[ier, vom scrie o clas` care extinde clasa Canvas. Obiectele clasei Canvas con]in o metod` numit` paint(Graphics ecr). Aceast` metod` este apelat` automat atunci c@nd componenta respectiv` este afi[at` [i are rolul de a desena componenta. Observa]i c` metoda paint() prime[te ca parametru o referin]` c`re un obiect al clasei Graphics [i, pornind de la ea, putem apela toate metodele acestei clase, metode cu ajutorul c`rora putem afi[a imaginea, scrie \n mod grafic sau desena. |n programul urm`tor, clasa care construie[te componenta ce afi[eaz` imaginea se nume[te Imagine. Clasa Imagine con]ine: 1. O referin]` c`tre un obiect de tip Image. Un astfel de obiect poate re]ine o imagine citit`. Referin]a este utilizat` \n metoda paint() pentru a afi[a imaginea respectiv`. 2. Un constructor, care cite[te imaginea, stabile[te m`rimea componentei (setSize()) [i culoarea de fundal (setBackground()). Pentru citirea imaginii se utilizeaz` metoda clasei Toolkit numit` getImage(): Image getImage(String fisier), unde parametrul reprezint` calea c`tre fi[ierul respectiv. 3. Metoda paint() (redefinit`, pentru a avea acces). Metoda “deseneaz`” imaginea [i folose[te metoda drawImage() a clasei Graphics): drawImage(image im, int a, int b, int latime, int inaltime, this), unde: a,b - coordonatele relative (fa]` de col]ul din st@nga-sus al componentei care afi[eaz` imaginea; \n exemplu Imagine) ale col]ului din st@nga sus al dreptunghiului care con]ine imaginea. latime, inaltime - l`]imea [i \n`l]imea dreptunghiului care con]ine imaginea. this - obiectul curent (cel al clasei semnifica]ia general` a acestui parametru. Imagine). Nu trat`m Observa]ii: Metoda poate redimensiona imaginea citit` (o m`re[te sau mic[oreaz`) prin valorile transmise pentru latime [i inaltime. o Capitolul 10. Iniţiere în programarea vizuală 251 Fi[ierul imagine se g`se[te \n Bin (folder-ul curent), dar \i putem ata[a o cale. Exemplul urm`tor con]ine o component` care afi[eaz` desenul \n centrul ei. Desigur, imaginea putea acoperi \ntreaga suprafa]` a componentei Imagine, dar din considerente didactice, pentru a distinge \ntreaga suprafa]` unde am fi putut desena, am preferat s` folosim setBackground(). Programul de mai jos construie[te o fereastr` care afi[eaz` o imagine: import java.awt.*; import java.awt.event.*; import javax.swing.*; class Imagine extends Canvas { Image im; Imagine() { Toolkit ec=Toolkit.getDefaultToolkit(); im=ec.getImage("calculator.jpg"); setSize(300,300); setBackground(Color.YELLOW); } public void paint (Graphics ecr) { ecr.drawImage(im,50,50,200,200,this);} } class Fer extends JFrame { Imagine p=new Imagine(); public Fer(String titlu) { super(titlu);setSize(150,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); x.add(p); setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Imagine"); } } 10.10.2. Cum scriem ? |nainte de parcurgerea acestui paragraf, revede]i 8.15. “Afi[area imaginilor”. A]i putut observa acolo c` metoda Paint prime[te ca referin]` un obiect al clasei Graphics. Putem utiliza metodele acestui obiect pentru a desena ceva sau pentru a \nc`rca o imagine care se g`se[te \ntr-un fi[ier. Cele mai importante metode ale acestei clase sunt: 252 Bazele programării în Java void setFont (Font f) - seteaz` obiectul pentru ca scrierea grafic` s` se realizeze cu un anumit font; void setColor(Color c) - seteaz` culoarea de scriere (desenare); drawString(String str, int x, int y) - scrie pe ecran un [ir de caractere. Şirul este scris cu font-ul [i culoarea setate la un moment dat. Parametrii x [i y reprezint` coordonatele col]ului din st@nga sus al [irului de caractere afi[at. Exemplu: iat` cum arat` metoda Paint() pentru a putea scrie dou` [iruri de caractere cu font-uri [i culori diferite: public void paint (Graphics ecr) { Fontf=new Font("Arial",Font.ITALIC+Font.BOLD, 11); ecr.setFont(f); ecr.setColor(Color.red); ecr.drawString("Un exemplu de scriere",20, 30); ecr.setColor(Color.black); Font f1=new Font("CourierNew",Font.BOLD, 14); ecr.setFont(f1); ecr.drawString("Scriu cu alta culoare si alt font",20, 50); } 10.10.3. Cum desenăm ? drawLine(int x1, int y1, int x2, int y2) - deseneaz` o linie (segment) \ntre punctele de coordonate (x1,y1) [i (x2,y2). drawRect(int x, int y, int latime, int inaltime) deseneaz` un dreptunghi pentru care col]ul din st@nga sus are coordonatele (x,y) [i de l`]ime [i \n`l]ime date. drawRoundRect(int x, int y, int latime, int inaltime, int lat, int inal) - deseneaz` un dreptunghi care are col]urile rotunjite, (vede]i al`turat). void fillRect(int x, int y, int latime, int inaltime), la fel ca drawRect(), numai c` dreptunghiul este colorat \n interior. void fillRoundRect(int x, int y, int latime, int inaltime, int lat, int inal) - la fel ca drawRoundRect(), numai c` dreptunghiul rotunjit este colorat \n interior. lat inal Capitolul 10. Iniţiere în programarea vizuală 253 void drawPolygon(int[] X, int[] Y, int nr) - deseneaz` un poligon care are nr vârfuri. Coordonatele x ale punctelor se g`sesc \n vectorul X, iar coordonatele y ale punctelor se g`sesc \n vectorul Y. Practic, primul punct are coordonatele (X[0],Y[0]), al doilea punct are coordonatele (X[1],Y[1]), [.a.m.d. |n final, pentru a ob]ine poligonul se unesc printr-un segment primul [i ultimul punct. Poligonul este oarecare, deci poate fi [i neconvex. Exemplu: ecr.setColor(Color.black); int[] X= {10, 100,25, 80}; int[] Y= {10, 100,75, 30}; ecr.drawPolygon(X, Y, 4); void fillPolygon(int[] X, int[] Y, int nr) - la fel ca mai sus, numai c` poligonul este colorat \n interior. void drawPolyline(int[] X, int[] Y, int nr) - la fel ca mai sus, numai c` nu se mai une[te primul punct cu ultimul punct. Astfel se ob]ine o succesiune de segmente. void drawOval(int x, int y, int latime, int inaltime) deseneaz` un oval. Coordonatele x [i y sunt ale col]ului din st@nga sus al dreptunghiului circumscris ovalului, iar latime [i inaltime sunt l`]imea [i \n`l]imea acelui dreptunghi. 90 fillOval(int x, int y, int latime, int inaltime) - la fel ca mai sus, numai c` ovalul este colorat \n interior. drawArc(int x, int y, int latime, int inaltime, int u1, int u2) - traseaz` un arc. Arcul este o por]iune dintr-un oval [i primii 4 270 parametri sunt ai ovalului c`ruia \i apar]ine arcul. Ultimii doi parametri sunt: unghiul de unde porne[te arcul [i num`rul de grade al arcului. Unghiurile sunt date \n grade. fillArc(int x, int y, int latime, int inaltime, int u1, int u2) - la fel ca drawArc, numai c` se consider` sectorul (nu numai arcul) [i acesta este colorat. De exemplu, \n cazul \n care latime [i inaltime re]in aceea[i valoare, ovalul este, de fapt, un cerc. |n acest caz avem un sector de cerc. 180 0 254 Bazele programării în Java drawImage(image im, int a, int b, int latime, int inaltime, this), unde: a,b sunt coordonatele relative (fa]` de componenta creat`, vezi setSize()) ale col]ului din st@nga sus al dreptunghiului care con]ine imaginea. latime, inaltime - l`]imea [i \n`l]imea dreptunghiului care con]ine imaginea. this - obiectul curent (cel al clasei Imagine). Nu trat`m semnifica]ia general` a acestui parametru. Observa]ie: Metoda a mai fost folosit` atunci c@nd am afi[at o imagine! 10.11. Clasa Graphics2D Clasa Graphics2D mo[tene[te clasa Graphics [i prin urmare, ofer` mai multe posibilit`]i de lucru, unele dintre ele cu adev`rat spectaculoase. Pentru a o utiliza se procedeaz` ca mai jos, unde a fost rescris` metoda paint() pentru o clas` care mo[tene[te clasa Canvas (la fel ca atunci c@nd am creat imagini care se afi[eaz` pe fereastr`). Toate desenele [i set`rile f`cute se utilizeaz` identic ca [i c@nd ar fi fost realizate \n Graphics. public void paint (Graphics ecr1) { Graphics2D ecr=(Graphics2D) ecr1; ecr.setColor(Color.red); ... } 10.11.1. Cum desenăm ? Pentru desenare nu avem multe metode proprii (altele dec@t ale clasei mo[tenite), dar se pot utiliza metode ale altor clase aflate \n pachetul geom (ad`uga]i import java.awt.geom.*). Acestea construiesc obiectul \n memorie, iar pentru afi[are vom utiliza metodele clasei Graphics2D urm`toare: draw(Shape S) - deseneaz` obiectul f`r` a-l “umple” cu culoare sau gradient, ori textur`. Toate aceste no]iuni sunt prezentate pe larg, \n cadrul aceluia[i capitol. fill (Shape S) - deseneaz` obiectul „umplut‟ cu o culoare (gradient sau textur`). Capitolul 10. Iniţiere în programarea vizuală 255 Ambele metode au parametrii de tipul Shape, care este o interfa]`. Clasele care construiesc figurile geometrice prezentate \n continuare, sunt implement`ri ale tipului Shape: Clasa Line2D.float - are constructorul: Line2D.Float(float x1, float y1, float x2, float y2); construie[te o linie care une[te punctele de coordonate (x1,y1) [i (x2,y2). Exemplu: construiesc [i afi[ez o linie ro[ie (ecr este de tipul Graphics2D). ecr.setColor(Color.red); Line2D.Float linie = new Line2D.Float(10,10, 100,100); ecr.draw(linie); Clasa Rectangle2D.Float - are constructorul: Rectangle2D.Float(float x, float y, float latime, float inaltime) - construie[te un dreptunghi. Col]ul din st@nga sus are coordonatele (x,y), iar dreptunghiul are l`]imea [i \n`l]imea specificate de parametri. Exemplu: construiesc [i afi[ez un dreptunghi cu interiorul “umplut” cu ro[u: ecr.setColor(Color.red); Rectangle2D.Float drept = new Rectangle2D.Float(10,10, 50, 50); ecr.fill(drept); Clasa Ellipse2D.Float - are constructorul: Ellipse2D.Float(float x, float y, float latime, float inaltime) - construie[te o elips`. Parametrii se refer` la dreptunghiul circumscris elipsei. Clasa Arc2D.Float - are constructorul: Arc2D.Float(float x, float y, float latime, float inaltime, float start, float nr, int type) - construie[te un arc. Primii 4 parametri se refer` la elipsa c`reia \i apar]ine arcul, start este unghiul de pornire, nr este num`rul de grade al arcului, iar type este o constant` care determin` modul \n care arat` arcul. Valoarea constantei type rezult` din imaginile de mai jos: Exemplu: construim un arc de 90 de grade al unui cerc. Punctul de start al arcului este la 45 de grade: Arc2D.CHORD Arc2D.OPEN Arc2D.PIE 256 Bazele programării în Java Clasa GeneralPath se utilizeaz` pentru trasarea unei linii fr@nte sau, \n particular, pentru trasarea unui poligon. Clasa con]ine: GeneralPath()- constructor; moveTo(float x, float y) - mut` un cursor imaginar \n punctul de coordonate (x,y); lineTo(float x, float y) - traseaz` o dreapt` \ntre punctul \n care se g`se[te cursorul imaginar [i cel de coordonate transmise ca parametru; closePath() - traseaz` dreapta care \nchide linia fr@nt` (adic` se creeaz` un poligon). Exemplu: \n secven]a de mai jos se afi[eaz` un triunghi. V@rfurile sale sunt (5.5). (100,100), (150,10): GeneralPath path= new GeneralPath(0,0); path.moveTo(5,5); path.lineTo(100,100); path.lineTo(150,10); path.closePath(); ecr.draw(path); 10.11.2. Stabilirea modului de trasare a liniilor |n clasa Graphics, toate liniile aveau o singur` grosime: 1 pixel. |n Graphics2D, se poate stabili ca liniile s` aib` o anumit` grosime, mai mare sau egal` cu 1. De asemenea, se pot face set`ri ale modului \n care se termin` segmentele [i asupra modului \n care acestea se \mbin`. Pentru a realiza aceste lucruri, se utilizeaz` o metod` a clasei Graphics2D, numit` setStroke(): void setStroke(Stroke s); Dup` cum vede]i, parametrul metodei este de tip Stroke. Dar, Stroke este o interfa]`. Ea este implementat` de clasa BasicStroke. Clasa BasicStroke are mai mul]i prezenta]i doar doi, mai importan]i: constructori, din care, aici sunt BasicStroke(float latime) - seteaz` l`]imea liniilor (\n pixeli); BasicStroke(float latime, int cap, int join) - seteaz` l`]imea liniilor (latime), modul \n care arat` capetele segmentelor (cap) [i modul \n care acestea sunt unite (join). Pentru ultimii doi parametri, apelul metodei se realizeaz` utiliz@nd constantele clasei BasicStroke. Capitolul 10. Iniţiere în programarea vizuală 257 Exemplu: pentru a crea imaginea al`turat` am utilizat clasa de mai jos: class Imagine extends Canvas { Imagine() { setSize(300,300);} public void paint (Graphics ecr1) { Graphics2D ecr=(Graphics2D) ecr1; ecr.setColor(Color.red); BasicStroke c =new BasicStroke(10, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL); ecr.setStroke(c); GeneralPath path= new GeneralPath(0,0); path.moveTo(5,5); path.lineTo(75,75); path.lineTo(150,5); ecr.draw(path); } } |n continuare, ne propunem s` analiz`m valorile pe care le poate lua parametrul cap, prezent@nd de fiecare dat`, c@te o dreapt` (segment). Pentru ultimele dou` cazuri, segmentului i se adaug` un p`trat, respectiv un semicerc: CAP_BUTT CAP_SQUARE CAP_ROUND Iat` care sunt valorile pe care le poate lua parametrul join (modul de unire a segmentelor). Pentru fiecare din cazuri vom prezenta o linie fr@nt` realizat` cu GeneralPath: JOIN_MITER JOIN_BEVEL JOIN_ROUND Parametrul join are efect doar \n cazul figurilor unitare (linie fr@nt`, dreptunghi, etc.). El nu va func]iona \n cazul \n care tras`m dou` drepte (segmente) care se unesc \ntr-un punct, pentru c` nu exist` informa]ii care s` determine acest efect. 258 Bazele programării în Java Prin utilizarea parametrului join, nu mai sunt necesare metode de tipul celor care creeaz` un dreptunghi cu col]urile rotunjite. Acestea pot fi rotunjite prin valoarea pe care o transmitem pentru join. 10.11.3. Gradient P@n` \n prezent, atunci c@nd am colorat o anumit` imagine, am utilizat numai o singur` culoare. |n Graphics2D se poate utiliza un gradient, adic` o trecere treptat` de la o culoare la alta, ob]in@ndu-se astfel efecte deosebite. Pentru a realiza un gradient vom folosi metoda setPaint() a clasei Graphics2D: setPaint(Paint p) - dup` cum observa]i, parametrul este de tip Paint, care este o interfa]` implementat` de mai multe clase. Pentru a stabili un gradient vom utiliza clasa GradientPaint. Clasa GradientPaint are constructorul urm`tor: GradientPaint(float x1, float y1, Color c1, float y2, Color c2, boolean cyclic); float x2, Semnifica]ia parametrilor este urm`toarea: \n punctul de coordonate (x1,y1) vom avea culoarea c1, \n punctul de coordonate (x2,y2) vom avea culoarea c2. |ntre aceste puncte se va face o trecere treptat` de la culoarea c1 la culoarea c2. Trecerea poate fi aciclic` (parametrul cyclic re]ine false) sau ciclic` (parametrul cyclic re]ine true). Pentru cea aciclic`, trecerea de la c1 la c2 se face treptat, iar pentru cea ciclic`, \ntre cele dou` puncte se trece de mai multe ori de la c1 la c2 [i invers [i nu exist` cerin]a ca \n punctele date s` fie exact culorile solicitate. Exemplu: pentru a crea un dreptunghi cu gradient, prin trecerea de la galben la negru, vom utiliza clasa de mai jos. |n exemplu, gradientul este aciclic, dar figurile prezint` [i gradientul ciclic: aciclic ciclic Capitolul 10. Iniţiere în programarea vizuală 259 class Imagine extends Canvas { Imagine() { setSize(300,300);} public void paint (Graphics ecr1) { Graphics2D ecr=(Graphics2D) ecr1; GradientPaint g=new GradientPaint(50,50, Color.YELLOW, 100,100, Color.BLACK, false); ecr.setPaint(g); Rectangle2D.Float drept = new Rectangle2D.Float (50,50, 100, 100); ecr.fill(drept); } } 10.11.4. Clasa BufferedImage Uneori, prefer`m s` cre`m un desen pe care s`-l p`str`m \n memorie. Pentru aceasta utiliz`m clasa BufferedImage. Afi[area desenului se face atunci c@nd dorim, \n paint(), cu drawImage() a[a cum suntem obi[nui]i. Clasa BufferedImage con]ine: BufferedImage(int latime, int inaltime, int imageType) constructor. Primii doi parametri specific` l`]imea [i \n`l]imea imaginii memorate de obiect. Ultimul parametru prime[te o constant` a clasei BufferedImage [i semnific` un anumit tip de imagine cu o anumit` culoare de fond. Graphics2D createGraphics() - returneaz` o referin]` c`tre obiect de tip Graphics2D cu ajutorul c`ruia putem desena o imagine re]inut` de obiectul de tip BufferedImage. ImageProducer getSource() obiect. returneaz` imaginea re]inut` de Pentru a realiza cele propuse mai avem nevoie s` utiliz`m o metod` a clasei Toolkit (vezi 10.5): Image createImage(ImageProducer buf) - creeaz` un obiect de tip Image pornind de la o implementare a interfe]ei ImageProducer. class Imagine extends Canvas { Image im; BufferedImage imag_a; Graphics2D gr; 260 Bazele programării în Java Imagine() { // creez un obiect BufferedImage imag_a=new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); // pentru a desena ii asociez un un obiect Graphics2D gr=imag_a.createGraphics(); // desenez Line2D.Float linie = new Line2D.Float(10,10, 100,100); gr.draw(linie); // obtin un obiect de tip Image care contine desenul im=Toolkit.getDefaultToolkit().createImage(imag_a.getSource()); setSize(300,300); setBackground(Color.WHITE); } public void paint (Graphics ecr) { // desenez imaginea p ecr.drawImage(im,0,0,this); } } class Fer extends JFrame { Imagine p=new Imagine(); public Fer(String titlu) { super(titlu);setSize(400,400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); x.add(p); setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Imagine ascunsa"); } } 10.11.5. Texturi Suprafe]ele pot fi acoperite de o aceea[i culoare, de un gradient sau de o textur`. Pentru a acoperi o suprafa]` cu o textur`, vom utiliza aceea[i metod` a clasei Graphics2D ca [i c@nd acoperim suprafa]a cu un gradient [i anume setPaint(Paint p). Dup` cum am ar`tat, Paint este o interfa]`. Ea este implementat` de clasa GradientPaint (cu ajutorul ei cre`m un gradient), dar [i de clasa TexturePaint, clas` cu ajutorul c`reia cre`m o textur`. Clasa TexturePaint are constructorul: TexturePaint(BufferedImage buf, Rectangle drept). Dup` cum observa]i, ambii parametri sunt de tip referin]` la obiect. Obiectele apar]in de dou` clase distincte, BufferedImage [i Rectangle. Capitolul 10. Iniţiere în programarea vizuală 261 |nainte de a prezenta cei doi parametri, s` vedem principial, cum se realizeaz` o textur` (textura al`turat` este ob]inut` de programul din acest paragraf). Atunci c@nd desen`m o figur` geometric`, ea poate fi acoperit` de o textur`. Textura este alc`tuit` dintr-o imagine desenat` care se repet` de c@te ori \ncape \n cadrul figurii. Prin urmare, pentru a defini textura, trebuie s` cunoa[tem: 1. Care este imaginea care se repet`? 2. Care este m`rimea afi[at` a imaginii care se repet`? R`spunsul la prima \ntrebare este c`, pentru a specifica imaginea se utilizeaz` un obiect al clasei BufferedImage. Pentru a preciza dimensiunea imaginii care se repet`, se utilizeaz` un obiect al clasei Rectangle. Observa]ie. A nu se confunda dimensiunile imaginii re]inute de obiectul de tip BufferedImage cu dimensiunile la care se va afi[a imaginea \n textur`. Dac` imaginea re]inut` de obiectul de tip BufferedImage este mai mic` dec@t cea la care se va afi[a imaginea, atunci imaginea este m`rit` automat. Dac`, dimpotriv`, imaginea re]inut` de obiect are dimensiuni mai mari dec@t cea afi[at`, se va afi[a ce se poate din ea (pornind de la col]ul din st@nga sus). Clasa Rectangle se utilizeaz`, a[a cum am precizat, pentru a specifica m`rimea imaginii afi[ate. Unul din constructorii ei este: Rectangle (int latime, int inaltime). preciz`m dimensiunile imaginii afi[ate. Prin utilizarea lui Exemplu: programul de mai jos afi[eaz` textura dat`, de exemplu, \n acest paragraf. import import import import java.awt.*; javax.swing.*; java.awt.geom.*; java.awt.image.BufferedImage; class Imagine extends Canvas { Imagine() { setSize(300,300);} 262 Bazele programării în Java public void paint (Graphics ecr1) { Graphics2D ecr=(Graphics2D) ecr1; BufferedImage buf=new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB); Graphics2D model = buf.createGraphics(); model.setColor(Color.red); Ellipse2D.Float el= new Ellipse2D.Float(0, 0, 50, 50); model.fill(el); Rectangle r = new Rectangle(50,50); TexturePaint tp = new TexturePaint(buf, r); ecr.setPaint(tp); ecr.fillRect(0,0,300,300); } } class Fer extends JFrame { Imagine p=new Imagine(); public Fer(String titlu) { super(titlu); setSize(500,500); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); x.add(p); setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Imagine"); } } 10.11.6. Dreptunghiuri 3D Clasa Graphics2D ne ofer` posibilitatea s` desen`m dreptunghiuri \n relief. |n acest scop, ea con]ine metodele draw3DRect() [i fill3DRect(): draw3DRect(int x, int y, int latime, int inaltime, boolean raised) - deseneaz` un deptunghi. fill3DRect(int x, int y, int latime, int inaltime, boolean raised) - deseneaz` un deptunghi “umplut cu culoare”. Primii parametrii parametri caracterizeaz` orice dreptunghi. Ultimul parametru, de tip boolean, precizeaz` dac` dreptunghiul este ridicat (true) sau cobor@t (false). Pentru a utiliza cu succes aceast` metod`, trebuie s` [tim urm`toarele: 1. Metoda nu deseneaz` dec@t un dreptunghi cu linia de grosime 1 pixel. Pentru a ob]ine efectul scontat, trebuie s-o utiliz`m de mai multe ori, realiz@nd mai multe dreptunghiuri incluse unul \n altul, dar cu laturile lipite. Capitolul 10. Iniţiere în programarea vizuală 263 2. Atunci c@nd parametrul raised re]ine true, laturile din st@nga [i sus sunt desenate \ntr-o culoare deschis`, iar laturile din dreapta [i jos sunt desenate \ntr-o culoare \nchis`. Dac` raised re]ine false, culorile laturilor se inverseaz`. Exact aceste culori creeaz` impresia de ridicat sau cobor@t. 3. Practic, culoarea deschis` este cea setat` pentru desen, iar culoarea \nchis` este aleas` automat de metod`. Din acest motiv, dac` avem setat` culoarea negru, efectul este nul, iar dac` avem setat` culoarea alb efectul este maxim. Exemplu: butoanele al`turate au fost realizate \n clasa urm`toare: class Imagine extends Canvas { Imagine() { setSize(300,300);} public void paint (Graphics ecr1) { Graphics2D ecr=(Graphics2D) ecr1; ecr.setColor(Color.red); for (int i = 0; i <= 10; i++) ecr.draw3DRect(50 - i, 20 - i, 80 + 2 * i, 30 + 2 * i, true); for (int i = 0; i <= 10; i++) ecr.draw3DRect(200 - i, 20 - i,80 + 2 * i, 30 + 2 * i, false); } } 10.11.7. Spaţiul de coordonate al utilizatorului P@n` \n prezent am lucrat folosind exclusiv spa]iul de coordonate al dispozitivului. Tot ce am desenat a fost raportat la acest spa]iu. |n Graphics2D se poate lucra \ntr-un alt spa]iu de coordonate, acela al utilizatorului. Mecanismul este urm`torul: 1. Ini]ial, spa]iul de coordonate al dispozitivului coincide cu spa]iul de coordonate al utilizatorului; 2. Spa]iul de coordonate al utilizatorului poate deveni altul fa]` de spa]iul de coordonate al dispozitivului, \n urma unor opera]ii de transla]ie [i de rota]ie. Pentru a realiza aceste opera]ii, se utilizeaz` urm`toarele metode ale clasei Graphics2D: translate(int x1, int y1) - are rolul ca, dup` executarea ei, originea spa]iului de coordonate al utilizatorului s` aib` originea \n punctul de coordonate (x1, y1); rotate(double alfa) - rote[te spa]iul de coordonate \n sens invers trigonometric (sensul acelor de ceasornic cu unghiul transmis ca parametru). Unghiul alfa trebuie s` fie exprimat \n radiani. De acum, spa]iul utilizatorului este cel ob]inut \n urma rota]iei. 264 Bazele programării în Java 3. |n urma opera]iilor de transla]ie [i rota]ie, ce era desenat anterior r`m@ne nemodificat. |n noul spa]iu, se lucreaz` cu ceea ce se deseneaz` de acum \ncolo. Exemplu: Desenul de mai jos a fost ob]inut cu metoda urm`toare: public void paint (Graphics ecr1) { Graphics2D ecr=(Graphics2D) ecr1; ecr.setColor(Color.red); ecr.setStroke(new BasicStroke(4)); Line2D.Float linie = new Line2D.Float(0,0,100,100); ecr.draw(linie); ecr.translate(0,25); ecr.draw(linie); ecr.rotate(Math.PI/4); ecr.draw(linie); Rectangle2D.Float drept = new Rectangle2D.Float(100,10, 50, 50); ecr.fill(drept); } Aceea[i dreapt` (segment) a fost desenat` de 3 ori: - o dat` clasic (prima din dreapta), - apoi, \n urma unei transla]ii ( a doua din dreapta), - apoi, \n urma unei rota]ii (linia vertical`). Se observ` [i faptul c` dup` aplicarea unei rota]ii, p`tratul se afi[eaz` rotit. Capitolul 10. Iniţiere în programarea vizuală 265 10.12. Evenimente 10.12.1. Generalităţi |n exemplele date p@n` acum, majoritatea opera]iilor erau efectuate ca urmare a ap`s`rii unui buton. |n realitate, mecanismul declan[`rii [i trat`rii evenimentelor este cu mult mai complex. Exist` mai multe tipuri de evenimente [i ele sunt tratate de “ascult`tori” diferi]i. |n continuare, le vom prezenta pe cele mai des utilizate \n programarea vizual`. 10.12.2. Evenimente de tip Action Aceste evenimente sunt produse de componente de tipurile: JButton - atunci c@nd se execut` click pe suprafa]a butonului; JComboBox - atunci c@nd se opereaz` o selec]ie \n list`; JTextField - atunci c@nd se scrie \n edit [i se tasteaz` Enter; JCheckBox, JRadioButton debifeaz` butonul respectiv; - atunci c@nd se bifeaz` sau se JMenuItem - atunci c@nd se selecteaz` op]iunea respectiv`. Pentru a le capta, trebuie ca: 1. Fereastra care include componentele s` implementeze interfa]a ActionListener. Interfa]a con]ine antetul metodei care trebuie scris`: void actionPerformed(ActionEvent e) - metod` prin care se programeaz` ac]iunea care trebuie \ntreprins`, dac` evenimentul s-a produs. Evenimentul produs are tipul ActionEvent. O metod` important` a acestei clase este: String getActionCommand() - returneaz` un [ir de caractere dup` care se poate identifica componenta care a transmis evenimentul. Astfel, \n cazul butoanelor, se returneaz` [irul afi[at de ele; \n cazul edit-ului, se returneaz` [irul de caractere introdus de utilizator; \n cazul listelor, se returneaz` [irul ComboBoxChanged, iar \n cazul componentelor de tip JMenuItem, se returneaz` [irul afi[at de component`. 2. Fiecare component` care trebuie s` emit` un astfel de eveniment trebuie s` fie ad`ugat` “ascult`torului” de evenimente de tip ActionEvent. 266 Bazele programării în Java Astfel, fiecare component` care poate emite mesaje de acest tip con]ine metoda: void addActionListener(ActionListener l) adaug` componenta gestionarului curent (al ferestrei). Testa]i programul urm`tor pentru a va convinge! import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fer extends JFrame implements ActionListener { public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); //Butonul JButton A=new JButton("Buton 1"); x.add(A); A.addActionListener(this); //Lista JComboBox lista=new JComboBox (); lista.addItem("Optiunea 1"); lista.addItem("Optiunea 2"); x.add(lista); lista.addActionListener(this); // Edit-ul JTextField t=new JTextField(10); x.add(t); t.addActionListener(this); // JCheckBox JCheckBox b=new JCheckBox("Bifeaza"); x.add(b); b.addActionListener(this); // JCheckBox JRadioButton c=new JRadioButton("Radio"); x.add(c); c.addActionListener(this); setVisible(true); } public void actionPerformed (ActionEvent e) { System.out.println(e.getActionCommand()); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Test ActionEvent"); } } prin care se Capitolul 10. Iniţiere în programarea vizuală 267 10.12.3. Evenimente de tip MouseEvent Acestea sunt evenimente care se genereaz` \n urma ac]iunilor executate cu mouse-ul. Componenta care recep]ioneaz` astfel de evenimente trebuie s` implementeze una sau dou` dintre interfe]ele prezentate mai jos: Interfa]a MouseListener - con]ine antetele metodelor de mai jos, metode care se ruleaz` atunci c@nd se \nt@lne[te un eveniment de mouse: mouseClicked(MouseEvent e) - se execut` efectueaz` click pe suprafa]a componentei; mouseEnteed(MouseEvent e) - se execut` atunci c@nd cursorul mouse-ului ajunge pe suprafa]a grafic` a componentei; mouseExited(MouseEvent e) - se execut` atunci c@nd cursorul mouse-ului p`r`se[te suprafa]a grafic` a componentei; mousePressed(MouseEvent e) - se execut` aunci c@nd am ap`sat butonul mouse-ului; mouseReleased (MouseEvent e) - se execut` aunci c@nd s-a eliberat butonul mouse-ului. atunci c@nd se Interfa]a MouseMotionListener - con]ine urm`toarele antete: MouseDragged() - metoda se execut` \n mod continuu, c@t timp am ap`sat un buton al mouse-ului [i deplas`m cursorul (c` la opera]ia Drag and Drop); MouseMoved(MouseEvent e) - se execut` \n mod continuu, c@t timp cursorul mouse-ului se “plimb`” pe suprafa]a componentei. Dup` cum observa]i, parametrul oric`rei metode care r`spunde unei ac]iuni efectuate cu mouse-ul este de tip MouseEvent. Printre altele, clasa MouseEvent con]ine urm`toarele dou` metode: getX() - returneaz` coordonata x a cursorului grafic; getY() - returneaz` coordonata y a cursorului grafic. Ambele coordonate sunt relative la col]ul din st@nga-sus al componentei. Evenimentele de mouse pot fi tratate de orice component` care are la baz` clasa Component, deci sfera de ac]iune a sa este foarte larg`. Pentru a implementa “ascult`torii” de evenimente de mouse, se utilizeaz` metodele clasei Component: 268 Bazele programării în Java void addMouseListener(MouseListener l) - pentru “ascult`torul” MouseListener; void addMouseMotionListener(MouseMotionListener l) - pentru “ascult`torul” MouseMotionListener. Exerci]iu: urm`ri]i modul \n care se genereaz` evenimentele de mouse, rul@nd programul urm`tor. Pentru fiecare eveniment produs, \n fereastra CMD se afi[eaz` numele evenimentului. import import import import java.awt.*; java.awt.event.*; javax.swing.*; java.awt.image.*; class Imagine extends Canvas implements MouseListener, MouseMotionListener { Imagine() { setSize(200,200); setBackground(Color.RED); this.addMouseListener(this); this.addMouseMotionListener(this); } public void mouseClicked(MouseEvent e) { System.out.println("MouseClicked"); } public void mouseEntered(MouseEvent e) { System.out.println("MouseEntered");} public void mouseExited(MouseEvent e) { System.out.println("MouseExiteted");} public void mousePressed(MouseEvent e) { System.out.println("MousePressed");} public void mouseReleased(MouseEvent e) { System.out.println("MouseReleased"); } public void mouseDragged(MouseEvent e) { System.out.println("MouseDragged");} public void mouseMoved(MouseEvent e) { System.out.println("MouseMoved");} } class Fer extends JFrame { Imagine p=new Imagine(); public Fer(String titlu) { super(titlu); setSize(400,400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); x.add(p); setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("MouseEvent");} } Capitolul 10. Iniţiere în programarea vizuală 269 Aplica]ie - program prin care se deseneaz` cu mouse-ul. Programul urm`tor va exemplifica modul \n care se poate utiliza mouse-ul pentru a desena. Observa]i c`: 1. Desenul este re]inut de o component` dintr-o clas` care mo[tene[te clasa Canvas. Clasa componentei implementeaz` MouseListener [i MouseMotionListener. 2. Desenul este practic realizat \n memorie, prin utilizarea unui obiect de tip BufferedImage, iar metoda Paint nu face altceva dec@t s` deseneze pe ecran imaginea din memorie. 3. Evenimentele de mouse sunt generate astfel: a) mousePressed() - memoreaz` \n pozvX [i pozvY coordonatele cursorului grafic \n momentul \n care se apas` butonul mouse-ului. b) void mouseDragged() - traseaz` un segment de dreapt` \ntre coordonatele memorate \n pozvX [i pozvY [i cele actuale, memorate \n poznX [i poznY. Apoi, coordonatele actuale sunt memorate \n pozvX [i pozvY. Dup` aceasta, se redeseneaz` imaginea prin utilizarea metodei repaint(). Cum evenimentul se genereaz` \n mod continuu, se ob]ine efectul scontat. import import import import java.awt.*; java.awt.event.*; javax.swing.*; java.awt.image.*; class Imagine extends Canvas implements MouseListener, MouseMotionListener { Image im; BufferedImage desen; Graphics gr; int pozvX, pozvY, poznX, poznY; Imagine() { desen = new BufferedImage (200, 200, BufferedImage.TYPE_INT_RGB); gr = desen.createGraphics(); im=Toolkit.getDefaultToolkit().createImage(desen.getSource()); setSize(200,200); this.addMouseListener(this); this.addMouseMotionListener(this); } public void paint (Graphics ecr) { ecr.drawImage(im,0,0,this); } public void update(Graphics ecr) { paint(ecr);} public void mouseClicked(MouseEvent e) { } 270 Bazele programării în Java public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) { pozvX=e.getX(); pozvY=e.getY(); } public void mouseReleased(MouseEvent e){ } public void mouseDragged(MouseEvent e) { poznX=e.getX(); poznY=e.getY(); gr.drawLine(pozvX,pozvY,poznX,poznY); pozvX=poznX; pozvY=poznY; im=Toolkit.getDefaultToolkit().createImage(desen.getSource()); repaint(); } public void mouseMoved(MouseEvent e){} } class Fer extends JFrame { Imagine p=new Imagine(); public Fer(String titlu) { super(titlu); setSize(400,400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); x.add(p); setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Imagine"); } } Observa]i faptul c` programul con]ine [i metoda update (Graphics ecr). Ce este cu ea, de ce am pus-o? Pentru a redesena, se apeleaz` repaint(). Practic, metoda apeleaz` update() [i, aceasta din urm` apeleaz` paint(). Metoda update(), apelat` implicit, are rolul de a [terge suprafa]a desenat` [i de a o afi[a, dup` care se apeleaz` paint(). Apoi, metoda paint() realizeaz` noul desen. Desigur, toate acestea se produc \ntr-un timp foarte scurt. Cu toate acestea, apare o “p@lp@ire” a imaginii, care deranjeaz`. Solu]ia? Metoda update() a fost rescris`. |n noua “versiune”, metoda nu mai cuprinde [tergerea imaginii. Aceasta are un efect deosebit \n acest caz, deoarece \ntotdeauna noua imagine se ob]ine din precedenta, la care se adaug` un segment! Capitolul 10. Iniţiere în programarea vizuală 271 10.12.4. Focus, evenimente de tip FocusEvent Prin faptul c` o component` are focus-ul, \n]elegem c` respectiva component` este preg`tit` s` primeasc` date sau comenzi de la tastatur`. Putem distinge vizual componentele care au focus-ul. De exemplu, dac` un buton are focus-ul, atunci el apare ca selectat (con]ine pe suprafa]a lui un dreptunghi care marcheaz` acest fapt). Dac` este programat s` r`spund` la evenimente de tip Action, simpla ap`sare a blank-ului ([i nu Enter) are acela[i efect ca executarea unui click pe suprafa]a lui. Dac` un edit (component` de tip JTextField) are focus-ul, atunci ce se tasteaz` apare \n edit. De asemenea, \n interiorul lui, \n dreptul caracterului care urmeaz` s` fie introdus, clipe[te cursorul de editare. Pentu a putea lucra cu focus-ul, trebuie s` mai [tim urm`toarele: 1. O component` prime[te focus-ul dac` se execut` click pe suprafa]a ei. 2. Pentru ca focus-ul s` apar]in` componentei urm`toare, se apas` Tab. Ordinea \n care se parcurg componentele, la ap`sarea tastei Tab, este de la st@nga la dreapta, de sus \n jos. Astfel, teoretic, se poate lucra f`r` mouse. 3. Se poate programa ca o anumit` component` s` primeasc` focus-ul. Se va utilizeaza metoda: void requestFocus() – apar]ine de clasa Component. 4. Pentru a r`spunde la evenimente, se FocusListener cu cele dou` metode ale ei: implementeaz` interfa]a void focusGained(FocusEvent e) c@nd o component` prime[te focus-ul; void focusLost(FocusEvent e) - metoda se ruleaz` atunci c@nd o component` pierde focus-ul. Ambele metode con]in un parametru important` a acestei clase este: de - tip metoda se ruleaz` atunci FocusEvent. O metoda Component getComponent() - metoda returneaz` o referin]` la componenta care a recep]ionat evenimentul. Pornind de la aceast` referin]`, se poate detecta componenta ca \n exemplul urm`tor: Exemplul . Programul urm`tor probeaz` cele prezentate. Fereastra con]ine dou` butoane [i un edit. Ini]ial, “Butonul 1” are implicit focus-ul. Dac` ap`sa]i Blank ve]i ob]ine acela[i efect ca [i c@nd a]i executat click pe suprafa]a butonului. Urm`ri]i atribuirea focus-ului prin ap`sarea tastei Tab. Atunci c@nd o component` prime[te focus-ul, metoda focusGained() afi[eaz` numele ei. 272 Bazele programării în Java import java.awt.*; import javax.swing.*; import java.awt.event.*; class Fer extends JFrame implements FocusListener, ActionListener { JTextField txt; public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("Buton 1"); x.add(A); A.setName("Buton 1"); A.addFocusListener(this); A.addActionListener(this); JButton B=new JButton("Buton 2"); x.add(B); B.addFocusListener(this); B.setName("Buton 2"); txt =new JTextField(10); txt.setName("Edit"); txt.addFocusListener(this); x.add(txt); setVisible(true); } public void focusGained(FocusEvent e) { System.out.println(e.getComponent().getName());} public void focusLost(FocusEvent e) {} public void actionPerformed (ActionEvent e) { System.out.println("blank sau click");} } public class pv { public static void main(String args[]) { Fer fp=new Fer("Focus"); } } Exemplul . Validare. Una dintre cele mai frecvente utiliz`ri a focus-ului este dat` de opera]ia de validare. Concret: c@nd un edit pierde focus-ul, \n metoda focusLost() se scrie secven]a de validare. Dac` data introdus` este incorect`, se afi[eaz` mesajul corespunz`tor [i se redirec]ioneaz` focus-ul c`tre edit. |n acest fel, nu se poate p`r`si opera]ia de editare p@n` c@nd nu am introdus o valoare corect`. |n exemplu, se cere ca valoarea introdus` s` fie de tip double. import java.awt.*; import javax.swing.*; import java.awt.event.*; Capitolul 10. Iniţiere în programarea vizuală 273 class Fer extends JFrame implements FocusListener { JTextField txt; public Fer(String titlu) { super(titlu); setSize(200,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); JButton A= new JButton("Apasa"); x.add(A); txt =new JTextField(10); txt.addFocusListener(this); x.add(txt); setVisible(true); } public void focusGained(FocusEvent e){} public void focusLost(FocusEvent e) { String t=txt.getText(); try { double x=Double.parseDouble(txt.getText()); System.out.println(t);} catch (Exception ex) { System.out.println("Numar eronat"); txt.requestFocus();} } } public class pv { public static void main(String args[]) { Fer fp=new Fer("Focus");} } 10.12.5. Evenimemente de selectare a item-ilor Astfel de evenimente apar pentru componente precum JCheckBox sau JComboBox. Ele se pot trata \n mod direct, imediat ce selectarea a fost implementat`. Pentru aceasta, trebuie utilizat` interfa]a ItemListener care con]ine o singur` metod`: void itemStateChanged(ItemEvent e) - metod` care se apeleaz` de c@te ori se produce o deselectare sau o selectare. Aten]ie: dac`, de exemplu, \ntr-o list` se selecteaz` o alt` op]iune, mai \nt@i op]iunea curent` este deselectat`, dup` care este selectat` op]iunea aleas` de utilizator. Aceasta \nseamn` c`, \n acest caz, metoda se apeleaz` de dou` ori. S` observ`m c` parametrul metodei de mai sus este ItemEvent. O metod` important` a acestei clase este: de tipul int getStateChange() - returneaz` o valoare de tip int corespunz`toare uneia din cele dou` posibilit`]i de generare a evenimentului (deselectarea sau selectarea). Cele dou` valori sunt SELECTED [i DESELECTED (constante ale clasei ItemEvent). Componentele care pot transmite astfel de evenimente con]in metoda addItemListener(ItemLitener a). 274 Bazele programării în Java Exemplu: programul urm`tor afi[eaz` o fereastr` care con]ine o list`. La fiecare selectare, se afi[eaz` \n fereastra CMD numele op]iunii selectate. Observa]i faptul c`, de aceast` dat`, ascult`torul de evenimente a fost implementat ca o clas` aparte (AsLIsta). import java.awt.*; import javax.swing.*; import java.awt.event.*; class AsLista implements ItemListener { JComboBox lista; AsLista(JComboBox lista) { this.lista=lista;} public void itemStateChanged (ItemEvent e) { if (e.getStateChange()==ItemEvent.SELECTED) System.out.println(lista.getSelectedItem());} } class Fer extends JFrame { JComboBox lista; JSpinner s; public Fer(String titlu) { super(titlu); setSize(200,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); lista=new JComboBox (); x.setLayout(new FlowLayout()); lista.addItem("Optiunea 1"); lista.addItem("Optiunea 2"); lista.addItem("Optiunea 3"); lista.addItem("Optiunea 4"); x.add(lista); AsLista as=new AsLista(lista); lista.addItemListener(as); setVisible(true); } } public class pv { public static void main(String args[]) { Fer fp=new Fer("ItemListener");} } 10.12.6. Evenimemente pentru fereastră Obiectele de tip JFrame pot transmite urm`toarele evenimente: WINDOW_ACTIVATED - se produce atunci c@nd fereastra devine activ`. Acest eveniment se poate \nt@mpla atunci c@nd fereastra a fost afi[at` pentru prima dat`, atunci c@nd dup` minimizarea ei se revine la dimensiunea ini]ial` sau atunci c@nd a fost activat` o alt` fereastr` (s-a executat click pe suprafa]a ei) dup` care este reactivat` fereastra studiat`. Capitolul 10. Iniţiere în programarea vizuală 275 WINDOW_OPENED - se produce atunci c@nd este deschis` fereastra. WINDOW_DEACTIVATED - se produce c@nd fereastra devine inactiv`. Evenimentul se poate \nt@mpla atunci c@nd am activat o alt` fereastr` sau atunci c@nd am minimizat-o. WINDOW_CLOSING - se produce atunci c@nd se \nchide fereastra. WINDOW_ICONIFIED fereastra. WINDOW_DEICONIFIED - se produce atunci c@nd se execut` click pe fereastra minimizat`. WINDOW_CLOSED - se produce dup` ce fereastra a fost \nchis`. - se produce atunci c@nd am minimizat Pentru fiecare eveniment, interfa]a WindowListener con]ine antetul unei metode care trebuie apelat`. Leg`tura dintre numele evenimentelor [i cel al metodelor este evident`. Astfel, avem urmatoarele antete \n WindowListener: public public public public public public public void void void void void void void windowOpened(WindowEvent e) windowClosing(WindowEvent e) windowClosed(WindowEvent e) windowIconified(WindowEvent e) windowDeiconified(WindowEvent e) windowActivated(WindowEvent e) windowDeactivated(WindowEvent e) Metoda clasei JFrame, void addWindowListener(WindowListener a) are rolul de a asocia ferestrei ascult`torul de evenimente. Exemplu: programul de mai jos v` permite s` studia]i “pe viu” evenimentele declan[ate atunci c@nd se efectueaz` diverse opera]ii cu fereastra. Numele evenimentelor este afi[at \n fereastra CMD: import javax.swing.*; import java.awt.event.*; class InchidF extends Evfer { public void windowClosing(WindowEvent e) { System.out.println("WINDOW_CLOSING"); System.exit(0); } public void windowOpened(WindowEvent e) { System.out.println("WINDOW_OPENED");} public void windowActivated(WindowEvent e) { System.out.println("WINDOW_ACTIVATED");} 276 Bazele programării în Java public void windowDeactivated(WindowEvent e) { System.out.println("WINDOW_DEACTIVATED");} public void windowIconified(WindowEvent e) { System.out.println("WINDOW_ICONIFIED"); } public void windowDeiconified(WindowEvent e) { System.out.println("WINDOW_DEICONIFIED");} } public class td { public static void main(String args[]) { JFrame fp=new JFrame("Fereastra care se inchide"); WindowListener t=new InchidF(); fp.addWindowListener(t); fp.setSize(200,300); fp.setVisible(true); } } 10.13. Animarea imaginilor Este momentul s` prezent`m modul \n care se realizeaz` \n Java animarea imaginilor. În principal, dac` se dispune de o succesiune de imagini, mecanismul este simplu: 1. Se \ncarc` imaginile \n memorie, \ntr-un vector de componente de tip Image. 2. O imagine este afi[at` un inteval de timp, apoi se afi[eaz` urm`toarea imagine un interval de timp, [.a.m.d. Exemplu: avem mai multe imagini succesive \n fi[ierele Poza1.jpg, Poza2.jpg,..., Poza12.jpg. O fereastr` afi[eaz` la nesf@r[it imaginile \n ordinea 1, 2...12, apoi 12, 11, ...1, [i iar, 1, 2,...12, etc… Poza1.jpg…………….Poza4.jpg…………....Poza8.jpg…………...Poza12.jpg De fapt, efectul ob]inut este o iluzie optic`. Dac` anima]ia este realizat` într-un mod coerent [i intuitiv, ea va fi perceput` foarte u[or de privitori. Totul depinde de îndemânarea [i talentul programatorului la crearea unor efecte vizuale cât mai realiste. Capitolul 10. Iniţiere în programarea vizuală Programul este urm`torul: import java.awt.*; import java.awt.event.*; import javax.swing.*; class Fir extends Thread { // fir de executie pentru afisarea imaginilor la nesfarsit // constructorul primeste ca parametru referinta catre imagine Imagine imag ; int i; Fir (Imagine imag) { this.imag=imag;} public void run() { while (true) { while (i!=11) { i++; imag.afis(i); try { sleep(300); } catch (Exception e) {} } while (i!=0) { i--; imag.afis(i); try { sleep(300); } catch (Exception e) {} } } } } class Imagine extends Canvas { Image[] im= new Image[12]; int i=0; Imagine() { Toolkit ec=Toolkit.getDefaultToolkit(); for (int i=0;i<=11;i++) im[i]=ec.getImage("C:\\Foto\\Poza"+(i+1)+".jpg"); setSize(300,300); setBackground(Color.YELLOW); } public void paint (Graphics ecr) { ecr.drawImage(im[i],0,0,300,300,this);} public void update(Graphics ecr) { paint(ecr);} void afis(int i) { this.i=i; repaint();} } class Fer extends JFrame { Imagine p=new Imagine(); public Fer(String titlu) { super(titlu); setSize(400,400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new FlowLayout ()); x.add(p); Fir f=new Fir(p); f.start(); setVisible(true); } } 277 278 Bazele programării în Java public class pv { public static void main(String args[]) { Fer fp=new Fer("Imagine");} } Observa]ii asupra programului: 1. Clasa imagine este asem`n`toare cu clasa care afi[eaz` o imagine [i este dat` ca exemplu \n acesat` carte (vezi 10.10.1). Deosebirile sunt date de urm`toarele: a) Nu se re]ine o imagine, ci 12. Ele sunt \nc`rcate de constructorul clasei. b) Clasa are data membru i. Metoda paint() deseneaz` imaginea cu indicele i. c) Metoda afis() are rolul de a transmite valoarea care este memorat` de i [i de a comanda redesenarea imaginii. d) Metoda update() este redefinit`, pentru c` dac` n-ar fi fost redefinit`, \nainte de a fi desenat` noua imagine de paint(), vechea imagine ar fi fost [tears`. Aceasta ar crea efectul de “p@lp@ire”. 2. Practic, clasa Fir este un fir de executare care asigur` animarea imaginilor. S-a procedat \n felul urm`tor: a) Constructorul ei prime[te ca parametru referin]a c`tre obiectul de tip Imagine [i o memoreaz`; b) Pornind de la aceast` referin]`, se apeleaz` continuu metoda afis() a clasei Imagine, metod` care redeseneaz` imaginea de indice dat. Probleme propuse 1. Scrie]i un program \n care o fereastr` afi[eaz` un buton. La ap`sarea butonului, programul va afi[a \n fereastra CMD rezolu]ia ecranului. 2. Scrie]i un program \n care o fereastr` afi[eaz` dou` butoane: Buton 1 [i Buton 2. {tiind c` metoda boolean isEnabled() a clasei JComponent returneaz` true dac` butonul este activ [i false \n caz contrar, face]i \n a[a fel \nc@t, la ap`sarea primului buton, daca al doilea buton este activ s` devin` inactiv [i invers, dac` este inactiv s` devin` activ. 3. Cum se pot a[eza dou` butoane \n fereastr` ca \n exemplul al`turat? Observa]i faptul c` primul buton ocup` toat` partea de sus, iar al doilea este a[ezat centrat pe orizontal`, \n partea de jos. Capitolul 10. Iniţiere în programarea vizuală 279 4. Cum se poate ca o fereastr` s` afi[eze cinci butoane, precum cea de mai jos: 5. Prin utilizarea gestionarului fereastra de mai jos: de pozi]ionare GridBagLayout, crea]i 6. Se [tie c` pentru a citi o parol` se utilizeaz` o component` de tip JPasswordField (clas` care are ca superclas` pe JTextField). Se [tie de asemenea, c` pentru o component` de tip JPasswordField, metoda getText() este depreciat` [i \n locul ei se utilizeaz` metoda: char[] getPassword(). Se cere ca programul dvs. s` citeasc` o parol` [i s` afi[eze OK dac` parola introdus` este [irul “Mama” [i NO \n caz contrar. 7. Realiza]i un program \n care \ntr-un edit s` se poat` introduce numere prin ap`sarea unor butoane, ca al`turat. Extinde]i apoi programul pentru simularea unui calculator de buzunar. 8. S` se scrie un program care con]ine trei metode prin care se determin` dac` un num`r natural n citit este prim sau nu. Prima dintre ele testeaz` to]i divizorii num`rului de 2 la n-1, a doua divizorii de la 2 la n , a treia de 2 la 2 n. Pentru citerea num`rului, fereastra va con]ine o etichet` [i un edit, pentru selectarea algoritmului se va utiliza o list`, iar dup` introducerea num`rului [i selectarea algoritmului, un buton va declan[a prelucrarea corespunz`toare. 280 Bazele programării în Java 9. Programul dvs. va efectua o copie a un fi[ier text. Numele fi[ierului care se copiaz` va fi introdus \ntr-un edit, iar numele fi[ierului destina]ie \n alt edit. 10. Scrie]i un program care genereaz` un fi[ier text cu n numere naturale. Valoarea lui n va fi introdus` cu ajutorul unui edit! 11. Scrie]i un program care creeaz`, pornind de la fi[ierul anterior, un altul care con]ine acelea[i numere, dar sortate cresc`tor. Se vor implementa mai mul]i algoritmi de sortare, iar selec]ia celui care va sorta fi[ierul se va face cu ajutorul unei liste aflat` pe fereastra principal`. 12. Scrie]i un program care cite[te dou` numere reale. Programul va putea afi[a suma, diferen]a, produsul [i c@tul lor. Opera]ia care se efectueaz` se va selecta dintr-un meniu. Rezultatul va fi afi[at cu ajutorul unor cutii de dialog predefinite. 13. Crea]i un fi[ier text \n care fiecare linie con]ine numele unei persoane [i v@rsta ei. Datele se introduc secven]ial. Pentru a le introduce, o fereastr` va avea ata[ate dou` edit-uri (unul pentru nume [i altul pentru v@rst`) [i un buton. La ap`sarea butonului se va efectua validarea datelor (alfabetic pentru nume [i numar natural \ntre 1 [i 99 pentru v@rst`). Dac` datele introduse nu corespund, se va afi[a un mesaj de avertizare [i utilizatorul va fi invitat s` introduc` corect datele. Dac` datele sunt introduse corect, se va scrie linia corespunz`toare \n fi[ierul text. 14. Ad`uga]i o list` ferestrei de la problema precedent` din care se pot selecta mai multe op]iuni, \n urma c`rora programul va putea afi[a: a) Media v@rstelor persoanelor a c`ror date au fost trecute \n fi[ier; b) Num`rul de persoane care au datele trecute \n fi[ier. 15. Scrie]i un program care afi[eaz` [i actualizeaz` fi[ierul creat la problema 13. Pentru a realiza opera]iile propuse se va utiliza o component` de tip JTextArea, iar opera]iile Open, Save [i Save As se vor selecta dintr-un meniu. 16. Scrie]i un program care genereaz` un fi[ier text care con]ine cel pu]in 10.000 numere naturale aleatoare. Apoi, scrie]i un alt program care sorteaz` fi[ierul prin utilizarea mai multor metode de sortare. Metoda de sortare se va selecta dintr-o list`. La fiecare sortare, se va estima timpul r`mas prin utilizarea unei componente de tip JProgressBar. 17. Scrie]i un program \n care o component` de tip JTextArea afi[eaz` un text preluat dintr-un fi[ier text dat. Se cere s` se seteze font-ul prin selectarea sa dintr-o list` [i m`rimea lui prin utilizarea unei componente de tip JSpinner. 18. Scrie]i un program \n care se creeaz` [i se actualizeaz` un fi[ier text. Textul se introduce cu ajutorul unei componente de tip JTextArea. Pentru Capitolul 10. Iniţiere în programarea vizuală 281 deschiderea fi[ierului [i salvarea lui, se utilizeaz` cutii de dialog de tip Open / Save apelabile dintr-un meniu. 19. Completa]i programul anterior astfel componentei de tip JTextArea s` poat` fi componente de tip JColorChooser, apelabil` pe bara de unelte. De asemenea, fontul va m`rimea lui cu ajutorul unei componente de tip bara cu unelte (component` de tip JToolBar). \nc@t culoarea suprafe]ei selectat` cu ajutorul unei cu ajutorul unui buton aflat fi selectat dintr-o list`, iar JSpinner, ambele aflate pe 20. Citi]i dou` matrice 44. Afi[a]i produsul lor. Pentru citire [i afi[are se vor utiliza componente de tip JTable. 21. Scrie]i un program care creeaz` [i actualizeaz` fi[ierul text persoane.txt. Fi[ierul con]ine, pe fiecare linie, numele [i v@rsta unei persoane. Pentru introducerea datelor [i actualizarea lor se va utiliza o component` de tip JTable. 22. La fel ca la problema 21, numai c` pentru introducerea datelor sau actualizarea lor se se utilizeaz` mai multe cutii de dialog create de dvs. 23. Scrie]i un program \n care fereastra va afi[a, la alegere, mai multe imagini. Imaginea afi[at` va fi selectat` dintr-o list`. 24. Scrie]i un program care afi[eaz` toate solu]iile pentru problema celor n dame. |n exemplu, se consider` n=8. Dup` afi[area unei solu]ii, pentru a fi afi[at` urm`toarea solu]ie, se va ap`sa un buton. Pentru afi[are, ve]i utiliza o component` de tip JTable. 25. Scrie]i un program \n care fereastra afi[eaz` \n permanen]` un segment care se rote[te \n jurul unei extremit`]i. 26. Programul va afi[a un p`trat care se rote[te \n jurul unui col] al s`u. 27. Scrie]i un program care v` permite s` realiza]i desene. Cerin]e: se pot utiliza mai multe culori, selectabile cu ajutorul unei componente de tip JColorChooser. De asemenea, programul v` va permite s` [terge]i por]iuni din desen. Indicaţii: 1. La ap`sarea butonului, r`spunde metoda: public void actionPerformed (ActionEvent e) { Toolkit ec=Toolkit.getDefaultToolkit(); Dimension dim = ec.getScreenSize(); System.out.println(dim.width); System.out.println(dim.height); } 282 Bazele programării în Java 2. JButton B trebuie declarat ca dat` membru a clasei pentru a avea acces la el din metoda urm`toare, care r`spunde la ap`sarea primului buton: public void actionPerformed (ActionEvent e) { if (B.isEnabled()) B.setEnabled(false); else B.setEnabled(true); } 3. Fereastra are gestionarul de pozi]ionare BorderLayout. |n nord, avem primul buton. |n centru avem un panel. Acesta se extinde pe \ntreaga suprafa]` r`mas`. La r@ndul lui, panelul este gestinat de FlowLayout. Lui \i ad`ug`m al doilea buton. ... Container x=getContentPane(); x.setLayout(new BorderLayout ()); JButton A=new JButton("Buton 1"); x.add(A,BorderLayout.NORTH); JPanel panel=new JPanel(); x.add(panel,BorderLayout.CENTER); panel.setLayout(new FlowLayout()); B=new JButton("Buton 2"); panel.add(B); ... 4. ... Container x=getContentPane(); x.setLayout(new BorderLayout ()); JButton A=new JButton("Buton 1"); x.add(A,BorderLayout.SOUTH); JPanel panel=new JPanel(); x.add(panel,BorderLayout.CENTER); panel.setLayout(new GridLayout(2,2)); JButton B=new JButton("Buton 2"); panel.add(B); JButton C=new JButton("Buton 3"); panel.add(C); JButton D=new JButton("Buton 4"); panel.add(D); JButton E=new JButton("Buton 5"); panel.add(E); ... 5. class Fer extends JFrame { public Fer(String titlu) { super(titlu); setSize(250,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GridBagLayout pozitii=new GridBagLayout(); JLabel et=new JLabel ("Numele "); JTextField txt=new JTextField(15); JLabel et1=new JLabel("Varsta"); JTextField txt1=new JTextField(2); JButton bt=new JButton("Apasa"); Container x=getContentPane(); Capitolul 10. Iniţiere în programarea vizuală // pozitionare et GridBagConstraints p_et=new GridBagConstraints(0,0,1,1,1,2,GridBagConstraints.WEST, GridBagConstraints.NONE,new Insets(0,0,0,0), 0,0); pozitii.setConstraints(et,p_et); // pozitionare txt GridBagConstraints p_txt=new GridBagConstraints(1,0,1,1,4,2,GridBagConstraints.WEST, GridBagConstraints.NONE,new Insets(0,0,0,0), 0,0); pozitii.setConstraints(txt,p_txt); // pozitionare et1 GridBagConstraints p_et1=new GridBagConstraints(0,1,1,1,1,2,GridBagConstraints.WEST, GridBagConstraints.NONE,new Insets(0,0,0,0), 0,0); pozitii.setConstraints(et1,p_et1); // pozitionare txt1 GridBagConstraints p_txt1=new GridBagConstraints(1,1,1,1,4,2,GridBagConstraints.WEST, GridBagConstraints.NONE,new Insets(0,0,0,0), 0,0); pozitii.setConstraints(txt1,p_txt1); // pozitiona buton GridBagConstraints p_bt=new GridBagConstraints(0,2,2,1,1,1,GridBagConstraints.CENTER, GridBagConstraints.NONE,new Insets(0,0,0,0), 0,0); pozitii.setConstraints(bt,p_bt); x.setLayout(pozitii); x.add(et); x.add(txt); x.add(bt); x.add(et1); x.add(txt1); setVisible(true); } } 6. Utiliza]i metoda: public void actionPerformed (ActionEvent e) { String parola=new String(txt.getPassword()); if (parola.compareTo("Mama")==0) System.out.println("OK"); else System.out.println("KO"); } 7. Proceda]i ca mai jos: class Fer { JButton JButton JButton JButton JButton extends JFrame implements ActionListener zero=new JButton("0"); unu=new JButton("1"); doi=new JButton("2"); trei=new JButton("3"); patru=new JButton("4"); 283 284 Bazele programării în Java JButton cinci=new JButton("5"); JButton sase=new JButton("6"); JButton sapte=new JButton("7"); JButton opt=new JButton("8"); JButton noua=new JButton("9"); JTextField txt=new JTextField(""); JPanel panel=new JPanel(); public Fer(String titlu) { super(titlu); setSize(200,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container x=getContentPane(); x.setLayout(new BorderLayout ()); panel.setLayout(new GridLayout(4,3)); x.add(txt,BorderLayout.NORTH); x.add(panel,BorderLayout.CENTER); panel.add(unu); panel.add(doi); panel.add(trei); panel.add(patru); panel.add(cinci); panel.add(sase); panel.add(sapte); panel.add(opt); panel.add(noua); panel.add(zero); unu.addActionListener(this); doi.addActionListener(this); trei.addActionListener(this); patru.addActionListener(this); cinci.addActionListener(this); sase.addActionListener(this); sapte.addActionListener(this); opt.addActionListener(this); noua.addActionListener(this); zero.addActionListener(this); setVisible(true); txt.setHorizontalAlignment(JTextField.RIGHT); } public void actionPerformed (ActionEvent e) { txt.setText(txt.getText()+e.getActionCommand()); } } CAPITOLUL 11 Applet-uri Din cuprins: Crearea şi executarea applet-urilor Arhive Java şi atributele elementului APPLET Redefinirea unor metode ale applet-ului Afişarea imaginilor. Clasa URL Redarea sunetelor Exemple de applet-uri Capitolul 11. Applet-uri 286 11.1. Generalităţi Pentru a \n]elege acest capitol, trebuie s` ave]i no]iuni despre HTML [i modul \n care se “posteaz`” pe Internet o pagin` WEB. Aceste no]iuni pot fi g`site, fie \n “Crearea [i programarea paginilor WEB”, fie \n “Tehnologia Informa]iei [i a Comunica]iilor”, manual pentru clasa a IX-a, ambele scrise de autorii acestei c`r]i. Important: 1. Un applet este asem`n`tor unei ferestre. El poate con]ine una sau mai multe componente pe suprafa]a sa. 2. Pentru crearea unui applet vom utiliza o component` de tip JApplet. 3. Applet-ul este ata[at unui fi[ier HTML, la fel ca o imagine. 4. Applet-ul este afi[at de c`tre browser-ul calculatorului de pe care se vizualizeaz` pagina WEB [i este rulat tot de acesta. 5. Pentru ca browser-ul s` poat` rula applet-ul este necesar ca pe acel calculator s` se g`seasc` implementat` (instalat`) o ma[in` virtual` Java (Java Virtual Machine, JVM). Cum noi avem deja implementat soft-ul de dezvoltare Java, nu mai avem nici o problem`, deoarece JVM este inclus \n acesta. Dar, un utilizator oarecare poate desc`rca [i instala JVM de pe site-ul firmei Sun. 6. M`surile de securitate impun anumite restric]ii. V` da]i seama ce ar fi dac` nu s-ar lua m`surile de securitate de mai jos: Applet-urile nu pot scrie sau citi fi[iere; Nu pot apela programe aflate pe sistemul utilizatorului. 11.2. Crearea şi executarea applet-urilor Mai jos ave]i un exemplu de applet. Pe suprafa]a sa se g`se[te un buton, la ap`sarea c`ruia se afi[eaz` o cutie de dialog cu un mesaj oarecare. Observa]i c@t de asem`n`tor este acest program cu un altul care afi[eaz` o fereastr` cu un buton. {i aici avem un container c`ruia i s-a ad`ugat un buton, am implementat ActionListener pentru ca butonul s` r`spund` la ap`sare. Pentru crearea [i afi[area unui applet, trebuie s` respecta]i urm`torii pa[i: Textul applet-ului se va g`si \ntr-un fi[ier text. Pentru a-l scrie [i corecta, putem folosi Notepad-ul. Fi[ierul text care-l con]ine, va avea extensia .java. Numele fi[ierului trebuie s` coincid` cu numele clasei care con]ine applet-ul, \n exemplu Ap.java. 287 Bazele programării în Java import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Ap extends JApplet implements ActionListener { public void init () { Container x = getContentPane(); x.setLayout(new FlowLayout ()); JButton A=new JButton("merge"); A.addActionListener(this); x.add(A); } public void actionPerformed (ActionEvent e) { JOptionPane.showMessageDialog (this, "La fel ca la fereastra clasica"); } } Compil`m programul a[a cum suntem deja obi[nui]i: pentru exemplul dat, vom scrie comanda javac Ap.java. Scriem un text HTML (tot cu Notepad) care include applet-ul scris, ca mai jos. Observa]i faptul c` prin WIDTH [i HEIGHT am precizat (\n pixeli) l`]imea, respectiv \n`l]imea dreptunghiului \n care se \ncadreaz` applet-ul. Fi[ierul are \n mod obligatoriu extensia .html, dar numele lui poate fi oarecare (nu este obligatoriu s` coincid` cu cel al applet-ului): <HTML> <BODY> <APPLET CODE="Ap.class" </BODY> </HTML> WIDTH=300 HEIGHT=300> Test`m rezultatul, execut@nd dublu click pe fi[ierul cu extensia .html. Automat, va fi apelat browser-ul care va afi[a applet-ul. Dup` ce fi[ierul HTML este gata (putem ad`uga orice altceva \n el, a[a cum suntem obi[nui]i), \l transfer`m pe site cu ajutorul unui program FTP (eventual cu programul WS_FTP). De asemenea, transfer`m pe site [i applet-ul compilat (cu extensia class). De acum, \l putem apela de pe orice calculator cu acces la Internet [i care are implementat` JVM. Capitolul 11. Applet-uri 288 11.3. Arhive Java şi atributele elementului APPLET Ce se \nt@mpl` \n situa]ia \n care applet-ul utilizeaz` mai multe clase? Dar dac`, \n plus, sunt necesare [i fi[iere imagine? Dup` cum vedem, \n fi[ierul HTML se declar` un singur fi[ier de tip class, dar la compilare, pentru fiecare clas` rezult` c@te un fi[ier de acest tip... Mediul de dezvoltare Java con]ine [i un program care poate crea arhive. O arhiv` este un fi[ier alc`tuit din mai multe fi[iere. Prin arhivare \n]elegem opera]ia prin care, pornind de la mai multe fi[iere, se creeaz` o arhiv` \n care datele sunt compresate, iar prin dezarhivare se \n]elege opera]ia prin care, pornind de la o arhiv`, se refac toate fi[ierele care o alc`tuiesc. |n Java, arhivele se creeaz` cu programul jar, furnizat de mediul de dezvoltare (ca [i javac, de exemplu). Arhivele pot fi recunoscute dup` extensia lor: .jar. Forma simplificat` a apelului programului jar pentru crearea unei arhive alc`tuit` din fi[ierele: f1, f2,... fn este: jar cf nume_arhiva f1 f2... fn Pute]i vedea to]i parametrii programului jar, dac`-l apela]i f`r` nici un parametru ! Exemplu: \n mod for]at, applet-ul dat ca exemplu \n paragraful anterior a fost creat prin utilizarea a dou` clase: import java.awt.*; import javax.swing.*; import java.awt.event.*; class Buton extends JButton { } public class Ap extends JApplet implements ActionListener { public void init () { Container x = getContentPane(); x.setLayout(new FlowLayout ()); Buton A=new Buton(); A.addActionListener(this); x.add(A); } public void actionPerformed (ActionEvent e) { JOptionPane.showMessageDialog(this, "La fel ca la fereastra clasica"); } } 289 Bazele programării în Java La compilare, rezult` dou` fi[iere cu extensia .class: Buton.class. Form`m arhiva arh.jar prin comanda: Ap.class [i jar cf arh.jar Ap.class Buton.class Mai jos, se poate observa cum arat` de aceast` dat` fi[ierul HTML: <HTML> <BODY> <APPLET CODE="Ap.class" ARCHIVE="arh.jar" </BODY> </HTML> WIDTH=300 HEIGHT=300> Dup` testare, vom transfera pe site fi[ierul HTML [i arhiva. P@n` acum, am prezentat pe scurt modul \n care se ata[eaz` un applet \n fi[ierul HTML. Am v`zut faptul c` pentru a realiza acest lucru, se folose[te elementul APPLET. Atributele acestuia sunt: CODE - numele fi[ierului care con]ine clasa ce extinde JApplet; HEIGHT, WIDTH - \n`l]imea [i l`]imea dreptunghiului care afi[eaz` applet-ul; ARCHIVE - numele fi[ierului care con]ine resursele utilizate de applet (clase [i fi[iere imagine); ALLIGN - alinierea applet-ului \n pagin`. Mai importante sunt valorile: - LEFT - aliniere st@nga; - RIGHT - aliniere dreapta; - TOP - \n partea de sus; HSPACE, VSPACE - spa]iul, \n pixeli, care trebuie p`strat \ntre dreptunghiul care \ncadreaz` applet-ul [i text sau alte componente ale aflate pe pagina WEB. (HSPACE, spa]iul l`sat pe orizontal`) [i VSPACE (spa]iul l`sat pe vertical`). 11.4. Redefinirea unor metode ale applet-ului Componentele de tip JApplet con]in [i metodele de mai jos, care pot fi redefinite: void init() - este prima care se apeleaz` atunci c@nd am definit un applet. Redefinit`, ea poate con]ine cod pentru anumite opera]ii care dorim s` fie efectuate la \nceput. Aceast` metod` se execut` o singur` dat`. Capitolul 11. Applet-uri 290 void start() - se apeleaz` atunci c@nd applet-ul devine activ, dar [i \n alte situa]ii, de exemplu, atunci c@nd a fost p`r`sit` pagina web [i se revine asupra ei. void stop() - se apeleaz` atunci c@nd se opre[te applet-ul sau c@nd a fost p`r`sit` pagina web care-l con]ine. void paint(Graphics ecr) - se apeleaz` de c@te ori este cazul. Prin intermediul ei se deseneaz` componenta. Ea este apelat` dup` metodele init() [i start(). void update(Graphics ecr) - spre deosebire de clasa Canvas, unde metoda mai \nt@i [tergea desenul, dup` care apela paint(), de aceast` dat`, metoda are corpul vid. Din acest motiv, nu mai este necesar` rescrierea ei pentru a elimina fenomenul de “p@lp@ire” a imaginii, dar dac` dorim ca ea s` [tearg` imaginea, atunci va trebui redefinit`, iar opera]ia de [tergere trebuie scris` de dezvoltatorul applet-ului. Exemplu: pentru a vedea cum func]ioneaz` metodele de mai sus, rula]i applet-ul urm`tor. Ini]ial, o cutie de dialog afi[eaz` „Init‟, apoi o alta afi[eaz` “Start” [i, dreptunghiul care reprezint` applet-ul devine ro[u: import java.awt.*; import javax.swing.*; public class Ap extends JApplet{ public void init() { JOptionPane.showMessageDialog (this, "Init");} public void start() { JOptionPane.showMessageDialog (this, "Start");} public void paint(Graphics g) { setBackground(Color.RED);} } 11.5. Afişarea imaginilor. Clasa URL Pentru a afi[a o imagine, mai \nt@i ea trebuie transferat` pe site (eventual cu WS_FTP). Pentru ca applet-ul s` aib` acces la ea, el va con]ine un obiect URL (Uniform Resource Locator). Aceast` clas` se g`se[te \n pachetul java.net. Clasa are constructorul: URL(String s) - unde s reprezint` adresa url a imaginii. |ntruc@t la acea adresa s-ar putea s` nu se g`seasc` resursa respectiv`, crearea unui obiect URL trebuie s` se fac` sub construc]ia try. Pentru a citi imaginea, se utilizeaz` metoda de mai jos a clasei JApplet: 291 Bazele programării în Java Image getImage(URL adr) - metoda returneaz` imaginea. |n rest, pentru a afi[a imaginea, vom utiliza metoda drawImage() a clasei Graphics, metod` pe care o cunoa[tem deja. De asemenea, pentru a putea folosi applet-ul cu dimensiuni diferite (scrise \n HTML, APPLET), se utilizeaz` dou` metode ale clasei JApplet: int getWidth() - returneaz` l`]imea dreptunghiului care con]ine applet-ul. int getHeight() - returneaz` \n`l]imea dreptunghiului care con]ine applet-ul. Exemplu: applet-ul urm`tor afi[eaz` o imagine pe \ntreaga sa suprafa]`: import java.awt.*; import javax.swing.*; import java.net.*; public class Ap extends JApplet{ Image im; int w,h; URL x; public void init() { try { x=new URL("http://www.xxxx.ro/imagine1.jpg");} catch (Exception e) { JOptionPane.showMessageDialog (this, "Imaginea?");} im=getImage(x); w=getWidth(); h=getHeight(); } public void paint (Graphics ecr) { ecr.drawImage(im,0,0,w,h,this);} } 11.6. Redarea sunetelor O component` de tip JApplet poate reda sunete. Fi[ierele pot fi de mai multe tipuri: .au, .aiff, .wav. Ini]ial, fi[ierul audio este transferat pe site. Pentru a lucra cu sunete se utilizeaz` interfa]a AudioClip (se g`se[te \n java.applet). Ea con]ine antetul a trei metode: void play() - red` sunetele din fi[ier o singur` dat`; void loop() - red` sunetele din fi[ier \n mod continuu; void stop() - opre[te redarea sunetelor din fi[ier. |n cazul \n care nu se utilizeaz` aceast` metod`, sunetele se redau [i dup` ce vizitatorul p`r`se[te pagina care con]ine applet-ul. Capitolul 11. Applet-uri 292 De asemenea, pentru a putea lucra cu fi[iere audio, vom utiliza [i metoda: AudioClip getAudioClip(URL url) AudioClip (o implementare a interfe]ei). - returneaz` un obiect Exemplu: applet-ul urm`tor afi[eaz` un dreptunghi ro[u, dar red` \n mod continuu un fi[ier audio: import import import import java.awt.*; javax.swing.*; java.net.*; java.applet.*; public class Ap extends JApplet{ URL adr; AudioClip muzica; public void init() { try {adr=new URL("http://www.ls-infomat.ro/spacemusic.au");} catch (Exception ex) { } muzica=getAudioClip(adr); } public void paint(Graphics ecr) { setBackground(Color.RED);} public void start() { muzica.loop();} public void stop() { muzica.stop();} } 11.7. Exemple de applet-uri 1. Applet-ul urm`tor afi[eaz` un text oarecare (vezi 8.10.2): import java.awt.*; import javax.swing.*; public class Ap extends JApplet{ Font f; public void init() { f=new Font("Arial",Font.BOLD, 20); setBackground(Color.YELLOW); } public void paint (Graphics ecr) { ecr.setFont(f); ecr.setColor(Color.BLACK); ecr.drawString("Un exemplu de applet",50, 150); } } 293 Bazele programării în Java 2. Applet-ul urm`tor afi[eaz` o imagine pe care am scris un mesaj ! import java.awt.*; import javax.swing.*; import java.net.*; public class Ap extends JApplet{ Image im; int w,h; URL x; Font f; public void init() { try { x=new URL("http://www.xxxxxx.ro/ fericire.jpg");} catch (Exception e) {} im=getImage(x); w=getWidth(); h=getHeight(); f=new Font("Arial",Font.BOLD, 30); } public void paint (Graphics ecr) { ecr.drawImage(im,0,0,w,h,this); ecr.setFont(f); ecr.drawString("Fericire generala!!!",50,270); } } 3. Pute]i realiza un applet care rote[te (cicleaz`) la nesf@r[it un [ir de caractere. Este o form` la care se apeleaz` de multe ori atunci c@nd se dore[te ca o anumit` pagin` s` aib` un con]inut informativ! Pentru a ob]ine acest efect am utilizat un fir de execu]ie. Practic, primul caracter al [irului afi[at se a[eaz` pe ultima pozi]ie, se a[teapt` un interval de timp, apoi primul caracter al [irului astfel ob]inut se a[eaz` pe ultima pozi]ie, se a[teapt`, etc. De vreme ce avem un fir de execu]ie, trebuie creat` o arhiv` care va fi pus` pe site. Arhiva va con]ine fi[ierele Ap.class [i Fir.class. import java.awt.*; import javax.swing.*; class Fir extends Thread { JTextField txt; Fir (JTextField txt) { this.txt=txt;} public void run() { while (true) { String s=txt.getText(); try { sleep(300); } catch (Exception e) {} s= s.substring(1)+s.substring (0,1); txt.setText(s); } } } Capitolul 11. Applet-uri 294 public class Ap extends JApplet{ JTextField txt; public void init() { Container x = getContentPane(); x.setLayout(new BorderLayout()); txt=new JTextField ("Acesta este un sir de caractere care se roteste pe durata de viata a applet-ului. Pentru a-l implementa avem nevoie de doua clase "); txt.setBackground(Color.YELLOW); Font f=new Font("Arial",Font.BOLD, 20); txt.setFont(f); x.add(txt,BorderLayout.NORTH); Fir fir=new Fir(txt); fir.start(); } } 4. Applet-ul urm`tor prezint` modul \n care se pot realiza anima]ii pe Internet. Mai \nt@i, au fost trecute pe site mai multe imagini (12). Apoi, printr-un mecanism asem`n`tor celui de la 10.14. (revede]i), s-a realizat anima]ia: import java.awt.*; import javax.swing.*; import java.net.*; class Fir extends Thread { Ap acesta; int i; Fir (Ap acesta) { this.acesta=acesta;} public void run() { while (true) { while (i!=11) { i++; acesta.afis(i); try { sleep(300); } catch (Exception e) {} } while (i!=0) { i--; acesta.afis(i); try { sleep(300); } catch (Exception e) {} } } } } public class Ap extends JApplet{ Image[] im =new Image[12]; URL[] url; int w,h,indice=0; String s=new String("http://www.xxxx.ro/Poza"); URL t=null; 295 Bazele programării în Java public void init() { for (int i=0;i<12;i++) { try { t=new URL(s+(i+1)+".jpg"); im[i]=getImage(t);} catch (Exception e) { } } w=getWidth(); h=getHeight(); Fir fir=new Fir(this); fir.start(); } public void paint (Graphics ecr) { ecr.drawImage(im[indice],0,0,200,200,this);} void afis(int i) { indice=i; repaint();} } 5. Efecte. Applet-ul urm`tor afi[eaz` un gradient ciclic dinamic (vezi 10.11.3). Efectul este deosebit. Analiza]i-l! import java.awt.*; import javax.swing.*; import java.awt.geom.*; class Fir extends Thread { Ap acesta; Fir (Ap acesta) {this.acesta=acesta; } public void run() { try { sleep(50); } catch (Exception e) { acesta.afis();} } } public class Ap extends JApplet{ int x1,y1,x2,y2; public void init() { Fir x=new Fir(this); x.start();} public void paint (Graphics ecr1) { Graphics2D ecr=(Graphics2D) ecr1; GradientPaint g=new GradientPaint(x1,y1, Color.YELLOW, x2,y2, Color.BLACK, true); ecr.setPaint(g); Rectangle2D.Float drept = new Rectangle2D.Float (0,0, getWidth(),getHeight()); ecr.fill(drept); } void afis() { x1=(int)Math.round(1+Math.ceil(Math.random()*50)); y1=(int)Math.round(1+Math.ceil(Math.random()*50)); x2=(int)Math.round(1+Math.ceil(Math.random()*50)); y2=(int)Math.round(1+Math.ceil(Math.random()*50)); repaint(); } } Capitolul 11. Applet-uri 296 6. Applet-ul urm`tor este un exemplu simplu de anima]ie. Practic, un cerc se “plimb`” la st@nga [i la dreapta. Observa]i faptul c`, de aceast` dat`, a fost necesar s` rescriem metoda update(), care va [terge cercul \nainte ca metoda paint() s`-l redeseneze: import java.awt.*; import javax.swing.*; import java.awt.geom.*; class Fir extends Thread { Ap acesta; Fir (Ap acesta) { this.acesta=acesta; } public void run() { int i; while (true) { for (i=0;i<100;i++) { try { sleep(200); } catch (Exception e) { acesta.afis(i);} for (;i>0;i--) { try { sleep(200); } catch (Exception e) { acesta.afis(i);} } } } } } public class Ap extends JApplet{ int x=100,y=100,r=100; public void init() { Fir f=new Fir(this); f.start(); } public void paint (Graphics ecr) { ecr.fillOval(x, y, 50, 50);} public void update(Graphics ecr) { ecr.setColor(getBackground()); ecr.fillRect(0,0,getWidth(),getHeight()); ecr.setColor(Color.BLACK); paint(ecr); } void afis(int i) { x=100+i; repaint(); } } 7. Applet-ul care “plimb`” acela[i cerc ca [i cel anterior, dar care nu [terge desenul (efectul se vede \n figura al`turat`). Sursa s-a ob]inut din cea anterioar` la care s-a [ters metoda update().