Top Banner
Univerzitet u Novom Sadu Fakultet tehničkih nauka Katedra za računarske nauke i informatiku Branko Milosavljević Milan Vidaković Java i Internet programiranje Materijal za predmet Sintetski praktikum iz računarstva Novi Sad, 2001.
175

Java i Internet Programiranje

Nov 22, 2015

Download

Documents

Muhedin Hadzic

Java i internet programiranje.pdf tutorijal
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
  • Univerzitet u Novom Sadu Fakultet tehnikih nauka Katedra za raunarske nauke i informatiku

    Branko Milosavljevi Milan Vidakovi

    Java i Internet programiranje

    Materijal za predmet

    Sintetski praktikum iz raunarstva

    Novi Sad, 2001.

  • Sadraj

    0. Namena i program kursa..........................................................................................1 0.1 Potrebno predznanje 1 0.2 Program kursa 2

    1. Uvod u programski jezik Java.................................................................................3 1.1 Java virtuelna maina 3 1.2 Programski jezik Java 4 1.3 Osnovni koncepti 4

    1.3.1 Tipovi podataka 4 1.4 Klase i objekti 5 1.5 Prevoenje i pokretanje programa 6 1.6 Reference na objekte 7 1.7 Operatori 9 1.8 Kontrola toka programa 9 1.9 Inicijalizacija objekata 10 1.10 Unitavanje objekata 10 1.11 Metode i njihovi parametri 11 1.12 Kljuna re final 13 1.13 Kljuna re static 14 1.14 Nizovi 14 1.15 Viedimenzionalni nizovi 15 1.16 Paketi, CLASSPATH i JAR arhive 17

    1.16.1 Paketi 17 1.16.2 CLASSPATH 19 1.16.3 JAR arhive 19 1.16.4 Podrazumevane komponente u CLASSPATH-u 20

    1.17 Zadatak: klasa Matrix 21 1.18 Nasleivanje 22 1.19 Modifikatori pristupa 22 1.20 Redefinisanje metoda 23 1.21 Apstraktne klase 23 1.22 Interfejsi 24 1.23 Unutranje klase 24 1.24 Polimorfizam 25

  • 1.25 Izuzeci 25 1.26 Klasa Object 28 1.27 Klasa String 28 1.28 Primeri nekih klasa iz standardne biblioteke 29

    1.28.1 Klasa java.util.Vector 30 1.28.2 Klasa java.util.Hashtable 30 1.28.3 Klasa java.util.StringTokenizer 31

    1.29 Konvencije davanja imena 31 1.30 Generisanje programske dokumentacije i javadoc 31 1.31 Zadaci: modifikacije klase Matrix 33

    2. Konkurentno programiranje u Javi......................................................................35 2.1 Kreiranje programskih niti 35 2.2 Daemon i non-daemon niti 36 2.3 Primer programa sa vie niti 37 2.4 Sinhronizacija niti 39 2.5 Dodatne metode za sinhronizaciju 40 2.6 Primer programa sa sinhronizacijom niti 40 2.7 Zadatak: problem pet filozofa 44

    3. GUI aplikacije i JavaBeans ....................................................................................45 3.1 AWT i Swing 45 3.2 Event-driven model 46 3.3 Osnovna struktura GUI aplikacije 46 3.4 Razlika u konstrukciji GUI-ja za Windows i Java aplikacije 47 3.5 Dodavanje komponenti na prozor 47 3.6 Prostorni raspored komponenti 48 3.7 Rukovanje dogaajima 50

    3.7.1 Dogaaji, oslukivai i komponente 50 3.7.2 Oslukivai kao unutranje klase 51

    3.8 Primeri korienja standardnih komponenti 53 3.9 Apleti 57

    3.9.1 Pojam apleta 57 3.9.2 Web itai i Java Plug-In 58 3.9.3. Apleti i komponente korisnikog interfejsa 59

    3.10. Aplet i aplikacija istovremeno 60 3.11. Korisniki definisane komponente 61 3.12. JavaBeans 63

    4. Mreno programiranje u Javi ................................................................................66 4.1. Osnovne karakteristike 66

    4.1.1. Pojam socket-a 66 4.2. Identifikacija vorova mree 67 4.3. Klasa Socket 67 4.4. Tipian tok komunikacije klijent strana 68 4.5. Klasa ServerSocket 69 4.6. Tipian tok komunikacije server strana 69 4.7. Server koji opsluuje vie klijenata 70 4.8 Primer klijent/server komunikacije 70

  • 4.9. Zadatak: klijent i server za listanje sadraja direktorijuma 74

    5. Veba: chat aplikacija .............................................................................................75 5.1. Uvodna razmatranja 76 5.2. Funkcije klijenta 76 5.3. Funkcije servera 78

    6. Rad sa bazama podataka JDBC..........................................................................81 6.1. Osnovne odrednice 81 6.2. JDBC drajveri 81 6.3. Uspostavljanje veze sa bazom podataka 82 6.4. Postavljanje upita 83 6.5. DML operacije 85 6.6. Uzastopno izvravanje istih SQL naredbi 85 6.7. Pozivanje uskladitenih procedura 87 6.8. Upravljanje transakcijama 90 6.9. Dodatak: inicijalizacija drajvera 91

    7. Uvod u vieslojne klijent/server sisteme............................................................93 7.1. Klasini klijent/server sistemi 93 7.2. WWW i Java kao platforma za klijente 94 7.3. Troslojni klijent/server sistemi 95

    8. Dinamiko generisanje HTML-a i servleti .........................................................99 8.1. HTTP protokol 99 8.2. Statiki i dinamiki Web sadraji 101 8.3. Servleti 101

    8.3.1. Metoda init 102 8.3.2. Metoda destroy 102 8.3.3. Metoda doGet 102

    8.4. Primer: elementarni servlet 102 8.5. Analiza zaglavlja HTTP zahteva 103 8.6. Konkurentni pristup servletu 104 8.7. Praenje sesije korisnika 105 8.8. Preuzimanje podataka sa HTML formi 108

    8.8.1 GET i POST zahtevi 109 8.9 Pristup bazama podataka iz servleta 111

    9. Java Server Pages ...................................................................................................114 9.1. JSP koncept 114 9.2. Vrste dinamikih elemenata 115

    9.2.1. Izrazi 115 9.2.2. Skriptleti 115 9.2.3. Deklaracije 117 9.2.4. Direktive 117

    9.3. Predefinisane promenljive 118 9.4. Skladitenje podataka i JavaBeans 119 9.5. Opseg vidljivosti JavaBean komponenti 120 9.6. Definisanje sopstvenih tagova 121

  • 10. Tehnologije distribuiranih objekata ...............................................................123 10.1. Osnovni koncepti 123 10.2. RMI 124

    10.2.1. Faze u pisanju RMI programa 124 10.2.2. RMI interfejs 125 10.2.3. RMI serverski objekat 126 10.2.4. RMI registry 126 10.2.5. RMI klijent 127 10.2.6. Primer RMI programa 127 10.2.7. RMI i multithreading 129

    10.3. CORBA 129 10.3.1. Osnovne odrednice 129 10.3.2. IDL 130 10.3.3. CORBA Naming Service 131 10.3.4. Proces pisanja CORBA programa 131 10.3.5. CORBA izuzeci 134 10.3.6. Pozivi unatrag 136 10.3.7. RMI i CORBA 137

    10.4. Enterprise JavaBeans 137 10.4.1. Session Beans 138 10.4.2. Entity Beans 139 10.4.3. Komunikacija klijenata sa EJB komponentama 140 10.4.4. Struktura EJB komponente 140

    11. Veba: Web shop aplikacija ..............................................................................144 11.1. Model podataka 144 11.2. Struktura Web sajta 145 11.3. Softverske komponente 147 11.4. Dodatna razmatranja 147

    11.4.1. Rukovanje konekcijama sa bazom podataka 147

    Literatura .....................................................................................................................152

    Prilozi ...........................................................................................................................154

  • 1

    Poglavlje 0

    Namena i program kursa

    Kurs Java i Internet programiranje ima za cilj upoznavanje polaznika sa programskim jezikom Java i arhitekturom vieslojnih Internet/intranet sistema i odgovarajuim Java tehnologijama za njihovu implementaciju. Nakon zavrenog kursa polaznici su osposobljeni da samostalno produbljuju znanja iz prikazanih oblasti i da uestvuju u razvoju softerskih sistema koji su predmet kursa.

    Kurs je predvien za izvoenje u laboratorijskim uslovima, na odgovarajuoj raunarskoj opremi. Materijal za kurs ine slajdovi koji se prikazuju u toku izlaganja, Web sajt koji sadri primere prikazane tokom izlaganja, zadatke za vebu, literaturu koja se preporuuje za detaljnije prouavanje materije i potreban softver koji je u javnom vlasnitvu. Ovaj praktikum je, takoe, sastavni deo tog materijala.

    0.1 Potrebno predznanje Za polaznike kursa je neophodno da poseduju znanja iz sledeih oblasti:

    objektno-orijentisano programiranje: poznavanje osnovnih pojmova i konce-pata (klasa, objekat, apstrakcija, nasleivanje, polimorfizam);

    konkurentno programiranje: pojmovi procesa i niti; rasporeivanje procesa, sinhronizacija procesa, nedeljive operacije;

    relacione baze podataka i SQL: poznavanje relacionog modela podataka, njegova implementacija u okviru sistema za upravljanje relacionim baza-ma podataka, upotreba jezika SQL za operacije nad bazom podataka;

    HTML: osnovni elementi strukture HTML dokumenata, rukovanje Web itaima;

    Za polaznike je poeljno, ali ne i obavezno, poznavanje jezika C++. Polaznici koji poznaju ovaj jezik mogu daleko bre usvajati materiju koja se izlae na poetku kursa.

    0.2 Program kursa Kurs se sastoji iz vie tema koje obuhvataju obradu nove materije i vebanja. U ovom odeljku dat je saet pregled sadraja kursa po odgovarajuim temama.

  • 2

    U prvom poglavlju, Uvod u programski jezik Java, govori se o osnovnim karakte-ristikama Jave, kao programskog jezika, i kao platforme za izvravanje pro-grama. Upoznaje se koncept Java virtuelne maine (JVM) i prenosivosti prevedenog Java koda. Zatim se vri pregled osobina Jave kao programskog jezika, i obrauju se jezike konstrukcije.

    Drugo poglavlje nosi naziv Konkurentno programiranje u Javi i donosi pregled jezikih koncepata koji omoguavaju pisanje konkurentnih programa.

    Tree poglavlje, GUI aplikacije i JavaBeans, predstavlja saeti prikaz pisanja aplikacija i apleta sa grafikim korisnikim interfejsom. Definie se struktura ovakvih aplikacija, nain reagovanja na dogaaje koje izaziva korisnik i navode primeri korienja brojnih komponenti za izgradnju korisnikog interfejsa.

    etvrto poglavlje, Mreno programiranje u Javi, definie pojmove koji se koriste prilikom pisanja programa koji komuniciraju preko mree, a zatim opisuje elemente jezika koji se koriste za pisanje ovakvih programa. Podrazumeva se rad preko TCP/IP mree.

    Peto poglavlje sadri vebu, iji je cilj konstrukcija mrene klijent/server aplikacije za chat preko TCP/IP mree. Konstrukcija ovakvog sistema obuhvata sve prethodno obraene teme.

    U estom poglavlju Rad sa bazama podataka JDBC dat je uvod u metode pri-stupa i korienja relacionih baza podataka iz Java programa. Podrazumeva se korienje sistema za upravljanje relacionim bazama podataka sa kojima se komunicira preko jezika SQL.

    Sedmo poglavlje, Uvod u vieslojne klijent/server sisteme, definie okvire u kojima se nalazi materija izloena u narednim poglavljima.

    Osmo poglavlje Dinamiko generisanje HTML-a i servleti prikazuje servlete, osnovnu Java tehnologiju za dinamiko generisanje Web sadraja i izgradnju Web sajtova.

    U narednom poglavlju, Java Server Pages, predstavljena je tehnologija za pisanje dinamikih Web stranica koja omoguava razdvajanje zadataka Web dizajnera i programera, pojednostavljujui tako razvoj Web-orijentisanih informacionih sistema.

    Deseto poglavlje, Tehnologije distribuiranih objekata, donosi saet prikaz tehno-logija namenjenih za pisanje distribuiranih objektno-orijentisanih aplikacija dostupnih iz programskog jezika Java.

    Poslednje poglavlje sadri vebu iji je cilj konstrukcija Web aplikacije za elektronsko poslovanje. Zadatak je napisati softver za Web sajt koji omoguava kupovinu putem Web-a.

  • 3

    Poglavlje 1

    Uvod u programski jezik Java

    1.1 Java virtuelna maina Specifikacija Jave obuhvata dve relativno nezavisne celine: specifikaciju pro-gramskog jezika Java i specifikaciju Java virtuelne maine (JVM). Specifikacija programskog jezika Java se ne razlikuje mnogo od slinih specifikacija za druge jezike sline namene. Meutim, JVM specifikacija predstavlja novinu u odnosu na druge rairene objektno-orijentisane programske jezike opte namene.

    Naime, JVM specifikacija predstavlja, zapravo, specifikaciju platforme za izvr-avanje Java programa u ijoj osnovi se nalazi programski model izmiljenog procesora. Programi napisani u programskom jeziku Java se prevode za ovakvu platformu za izvravanje. Samim tim, prevedeni programi se ne mogu pokretati direktno na nekoj konkretnoj raunarskoj platformi; potreban je poseban softver koji e takav prevedeni program da prilagodi konkretnoj maini i operativnom sistemu. Zapravo, potreban je odgovarajui interpreter.

    Kompanija koja je vlasnik jezika Java, Sun Microsystems, je stavila u javno vlasnitvo JVM interpreter, kompajler i skup drugih razvojnih alata grupisanih u paket pod nazivom Java Development Kit (JDK). U pitanju su alati koji se pokreu iz komandne linije i nude samo osnovni set funkcija za razvoj softvera. Sun je izdao JDK paket za nekoliko razliitih platformi: Windows, Solaris/ SPARC, Solaris/Intel i Linux/Intel.

    Kako je Java specifikacija (i sam jezik i JVM) javno dostupna, drugi proizvoai su proizveli svoje implementacije Jave za razliite platforme. Na primer, IBM nudi svoje verzije implementacije za veinu svojih hardversko/softverskih plat-formi, ali i za Linux na Intel mainama.

    Iako se najee programski jezik Java i Java virtuelna maina pominju u paru, kao dve komplementarne specifikacije, nema prepreka da se Java kod prevodi i za izvravanje na nekoj drugoj platformi (na primer, TowerJ paket generie Windows izvrni kod). Takoe, nema prepreka da se neki drugi jezici prevode za izvravanje u okviru Java virtuelne maine.

  • 4

    Kao posledica prethodno reenog, moe se rei da je Java kombinacija programskog jezika i platforme za izvravanje programa koja ima nekoliko vanih osobina:

    Projektovana je tako da to manje zavisi od karakteristika konkretnog raunarskog sistema na kome se izvrava.

    Jednom napisan i preveden program se moe pokretati na bilo kojoj platformi za koju postoji odgovarajui JVM interpreter. Dakle, preno-sivost programa je garantovana na nivou izvrnog (prevedenog) koda.

    Java je interpretirani jezik, to ima odgovarajui efekat na brzinu izvr-avanja programa.

    Proizvod prevoenja izvornog Java koda je program predvien za rad u okviru JVM, koji se esto naziva bajt-kod (byte-code).

    1.2 Programski jezik Java Iako je Java virtuelna maina sastavni deo specifikacije, o njoj se govori veoma retko; praktino je koriste samo autori kompajlera i JVM interpretera iza konkretne raunarske platforme. Sa druge strane, veina Java programera govori o drugom delu Java specifikacije, samom programskom jeziku Java, koji je i tema preostalog teksta u ovom poglavlju.

    Moe se rei da je Java objektno-orijentisani programski jezik opte namene, posebno pogodan za pisanje konkurentnih, mrenih i distribuiranih programa.

    Sva referentna dokumentacija za Javu nalazi se na jednom mestu sajtu firme JavaSoft (ogranak firme Sun Microsystems) http://java.sun.com.

    Knjiga Thinking in Java, (autor Bruce Eckel) se smatra za jednu od najboljih knjiga o samom jeziku, a dostupna je osim u klasinoj tampanoj formi i u elektronskom obliku koji je besplatan na http://www.bruceeckel.com.

    1.3 Osnovni koncepti Sintaksa Jave izuzetno podsea na sintaksu jezika C++, mada nije jednaka njoj. Sintaksna pravila nee biti posebno obraena, jer smatramo da su dovoljno oigledna iz primera koji slede.

    1.3.1 Tipovi podataka Java operie sa dve vrste tipova podataka: primitivnim tipovima i objektima. Primitivni tipovi su tipovi koji se sreu i u drugim jezicima, npr. celobrojni tip, karakter, itd. Tabela 1.1 sadri spisak svih primitivnih tipova sa njihovim osnovnim karakteristikama.

    Primitivni tip Veliina Minimum Maksimum boolean 1-bit - - char 16-bit Unicode 0 Unicode 216-1 byte 8-bit -128 +127 short 16-bit -215 +215-1 int 32-bit -231 +231-1 long 64-bit -263 +263-1

  • 5

    Primitivni tip Veliina Minimum Maksimum float 32-bit IEEE 754 IEEE 754 double 64-bit IEEE 754 IEEE 754 void - - -

    Tabela 1.1. Primitivni tipovi

    Iz tabele se vidi da Java raspolae primitivnim tipovima koji su na isti nain definisani i u drugim programskim jezicima. Jedini izuzetak je tip char, koji zauzima dva bajta, umesto uobiajenog jednog bajta. Radi se o tome da se tipom char moe predstaviti svaki karakter definisan Unicode standardom koji definie kodni raspored koji obuhvata praktino sve dananje jezike (ukljuujui indoevropske, dalekoistone, itd). To znai da su Java programi u startu osposobljeni da rade sa viejezinim tekstom, ili u naim uslovima, ravnopravno sa srpskom latinicom i srpskom irilicom.

    Treba primetiti da string, kao esto korien tip podatka, nema odgovarajui primitivni tip u Javi, slino jezicima C i C++.

    1.4 Klase i objekti Druga vrsta podataka sa kojima operie Java program su objekti. Objekti predstavljaju osnovni koncept objektno-orijentisane paradigme u modelovanju sistema. Svaki objekat realnog sistema koga posmatramo predstavljamo odgovarajuim objektom koji je sastavni deo modela sistema. Objekte koji zajednike osobine (ne moraju imati iste vrednosti tih osobina) moemo da opiemo klasom. U tom smislu, objekat je jedna instanca (primerak) svoje klase. Klasa, dakle, predstavlja model objekta, koji obuhvata atribute i metode.

    Sledi primer jedne Java klase: class Automobil { boolean radi; void upali() { radi = true; } void ugasi() { radi = false; } }

    (Plavom bojom su navedene kljune rei jezika). Klasa ima naziv Automobil, definie jedan atribut koji se zove radi i logikog je tipa (boolean), i definie dve metode koje se mogu pozvati nad objektima te klase, metode upali i ugasi.

    Kreiranje objekata koji predstavljaju instance (primerke) ove klase moe se obaviti na sledei nain:

    Automobil a = new Automobil(); Automobil b = new Automobil();

    Time su kreirana dva objekta klase Automobil, koji su nazvani a i b. Atributu radi objekta a moe se pristupiti pomou:

    a.radi

  • 6

    a poziv metoda upali i ugasi mogao bi da izgleda kao u sledeem primeru: a.upali(); b.ugasi();

    Ovo do sada reeno izuzetno podsea na C++. Neke od osobina Jave koje je bitno razlikuju u odnosu na C++ su:

    Nije mogue definisati promenljive i funkcije izvan neke klase. Samim tim, nije mogue definisati globalne promenljive, niti globalne funkcije ili procedure.

    Ne postoje odvojene deklaracija i definicija klase. Java poznaje samo definiciju klase. Prema tome, ne postoje posebni header fajlovi koji sadre deklaraciju klase.

    Kako Java ne doputa postojanje bilo ega to bi postojalo izvan neke klase, postavlja se pitanje odakle poinje izvravanje Java programa. C i C++ koriste funkciju main kao osnovnu funkciju od koje poinje izvravanje programa. Java takoe koristi funkciju main, samo to i ta funkcija mora biti metoda neke klase (u C++ terminologiji bi se reklo funkcija lanica). Izgled jedne klase koja sadri metodu main, i predstavlja primer jednog izvrivog Java programa dat je u sledeem primeru:

    class Hello { public static void main(String args[]) { System.out.println(Hello world!); } }

    (Trenutno nije bitno zato metoda main mora biti definisana kao public static void, ali mora biti tako.) Kompletan tekst ove klase smeten je u datoteku Hello.java. Treba obratiti panju na naziv ove datoteke: njena ekstenzija je obavezno .java, a ime mora biti jednako imenu klase, ukljuujui i razliku izmeu velikih i malih slova. Standardna preporuka je da se svaka klasa programa smeta u posebnu datoteku. Naziv datoteke mora odgovarati nazivu klase na prethodno opisani nain. Iako e neki prevodioci dopustiti smetanje teksta vie klasa u isti fajl, ta praksa se ne preporuuje. Dakle, svakoj Java klasi odgovara jedan fajl sa identinim nazivom i ekstenzijom .java.

    1.5 Prevoenje i pokretanje programa Svaka Java klasa se moe prevesti nezavisno od ostalih elemenata programa. Komanda kojom se klasa Hello iz prethodnog primera prevodi je

    javac Hello.java (Primeri za prevoenje i pokretanje opisuju korienje alata iz standardnog JDK paketa). Dakle, kompajler se poziva komandom javac, a kao parametri navode se imena onih datoteka koje elimo da prevedemo (moe ih biti vie, i moemo da koristimo doker-znake). Treba obratiti panju na to da je navoenje ekstenzije datoteke obavezno, iako je ekstenzija uvek .java.

  • 7

    Prevoenjem datoteke Hello.java dobija se datoteka Hello.class, koja sadri JVM bajt-kod koji pripada klasi Hello. Naziv te datoteke obavezno mora imati ekstenziju .class, i naziv mora biti jednak nazivu klase. Svaka klasa, data u odgovarajuem .java fajlu, kao rezultat prevoenja daje odgovarajui .class fajl. Treba obratiti panju da je kod prevoenja ovog primera neophodno pozicionirati se (u okviru DOS Prompt-a ili nekog shell-a na UNIX-u) u onaj direktorijum gde se nalazi .java fajl.

    Za pokretanje ovog programa dovoljan je dobijeni Hello.class fajl. Program emo pozvati iz komandne linije (ponovo se moramo nalaziti u istom direktorijumu gde i .class fajl) sledeom komandom:

    java Hello Ovog puta nije dozvoljeno navoenje ekstenzije .class prilikom pokretanja. U sluaju da se tako uini dobiemo poruku o greci.

    Sada sledi primer jednog programa koji se sastoji iz dve klase: Automobil.java class Automobil { boolean radi; void upali() { radi = true; } void ugasi() { radi = false; } } Test.java class Test { public static void main(String args[]) { Automobil a; a = new Automobil(); a.upali(); } }

    Ove dve klase su smetene u odgovarajuim datotekama Automobil.java i Test.java. Njihovim prevoenjem dobijaju se dva .class fajla, Automobil.class i Test.class. Program se pokree tako to se navodi ime one klase koja sadri metodu main, to bi u ovom primeru bilo

    java Test Nema nikakve prepreke da vie klasa koje ine program poseduju metodu main. Odakle e se poeti sa izvravanjem programa? To se odreuje prilikom pokretanja programa, tako to se navodi ime one klase iju metodu main elimo da pokrenemo.

    1.6 Reference na objekte Kada smo u prethodnom primeru, u metodi main, napisali:

    Automobil a; a = new Automobil();

    deklarisali smo promenljivu a tipa Automobil, a zatim kreirali objekat klase Automobil i vezali ga za tu promenljivu a.

  • 8

    Promenljiva a predstavlja, zapravo, referencu na objekat klase Automobil. Promenljiva a je lokalna promenljiva u metodi main, tako da se smeta na stek, na slian nain kako se to odvija u drugim jezicima, dok se memorija za objekat klase Automobil zauzima na heap-u programa. Slika 1.1 prikazuje tu situaciju.

    objekat klaseAutomobil

    aheap

    stek Slika 1.1. Referenca koja ukazuje na objekat

    U tom smislu kae se da je a referenca na objekat klase Automobil. Promenljiva a nije pointer u smislu kako ga definie C++, jer nije doputena nikakva aritmetika sa ovakvim promenljivama, niti dodeljivanje proizvoljnih vrednosti. Jedina vrednost koju referenca moe da sadri je adresa (namerno je pod navodnicima jer to nije prava adresa u memoriji) pravilno inicijalizovanog objekta na koga ukazuje.

    Sledei primer prikazuje kreiranje dva objekta klase Automobil i inicijalizaciju referenci tako da ukazuju na odgovarajue objekte. Reference se nalaze na steku programa, dok su objekti smeteni na heap.

    Automobil a = new Automobil(); Automobil b = new Automobil();

    Situacija koja se nakon ovoga nalazi u memoriji je prikazana na slici 1.2.

    objekat klaseAutomobil

    aheap

    stek

    b

    objekat klaseAutomobil

    Slika 1.2. Dve refence koje ukazuju na dva objekta

    Ako se sada izvri naredba b = a;

    u memoriji e biti sledea situacija (slika 1.3).

  • 9

    objekat klaseAutomobil

    aheap

    stek

    b

    objekat klaseAutomobil

    Slika 1.3. Situacija nakon kopiranja referenci

    Postavlja se pitanje ta se u ovoj situaciji deava sa objektom na koga je ukazivala referenca b: taj objekat vie nije dostupan ni na jedan nain, jer je jedina mogunost da se nekoj referenci dodeli vrednost dodela vrednosti postojee reference (tipa b = a) ili dodela vrednosti reference na novokreiran objekat (tipa a = new ...). Kako objekat vie nije dostupan, valjalo bi ga ukloniti iz memorije kako bi se izbeglo curenje memorije. Java ne poseduje posebnu jeziku konstrukciju kojom se memorija dealocira (poput operatora delete u jeziku C++). Za dealokaciju memorije zaduen je poseban pozadinski proces programa koji se naziva garbage collector (skuplja ubreta). O garbage collector-u e biti vie rei u odeljku 1.10.

    1.7 Operatori Operatori koji slue za gradnju Java izraza su operatori koji su, praktino, preuzeti iz jezika C++. Moemo ih grupisati u nekoliko grupa:

    aritmetiki operatori (+, -, *, /) relacioni operatori (==, , =, !=, >=,

  • 10

    if ... else switch for while do ... while break continue

    1.9 Inicijalizacija objekata Prilikom konstruisanja novog objekta, nakon alokacije potrebne memorije za smetaj objekta, bie pozvana specijalna metoda namenjena za inicijalizaciju objekta nazvana konstruktor. Konstruktor obavezno ima naziv jednak nazivu klase, i nema nikakav povratni tip, ak ni void. Sledi primer klase koja ima konstruktor.

    class A { A() { System.out.println("konstruktor"); } }

    U ovom primeru, konstruktor e biti pozvan prilikom kreiranja objekta klase A. Na primer:

    A varA = new A(); je deklaracija reference varA koja ukazuje na objekat klase A, pri emu se odmah vri i inicijalizacija ove reference na novokreirani objekat. U trenutku kada se izvri ovaj red (zapravo kreiranje objekta pomou new A()), na konzoli e se ispisati

    konstruktor to je rezultat izvravanja konstruktora.

    Ukoliko se unutar definicije klase ne navede nijedan konstruktor, kompajler e sam generisati tzv. podrazumevani konstruktor koji nema parametre i telo mu je prazno.

    1.10 Unitavanje objekata U odeljku 1.6 ve je bilo rei o problemu uklanjanja nedostupnih objekata iz memorije. Za taj posao zaduen je poseban pozadinski proces koji se naziva garbage collector (GC). Ovaj proces radi nezavisno od pokrenutog programa, u smislu da sam odluuje u kom trenutku e iz memorije osloboditi koji nedostupni objekat. Pored automatske dealokacije memorije, GC je zaduen i za automatsku defragmentaciju memorije.

    Za razliku od jezika C++, Java klase ne mogu imati destruktore. Destruktori su specijalne metode koje se pozivaju neposredno pre uklanjanja objekta iz memorije. Svu potrebnu dealokaciju memorije u Javi obavlja GC proces. U trenutku dealokacije podrazumeva se da je Java objekat oslobodio ostale resurse koje je koristio (otvorene datoteke, mrene konekcije, itd). Ukoliko je

  • 11

    neophodno obaviti neku operaciju neposredno pre nego to GC uniti objekat, ta operacija se moe implementirati u okviru specijalne metode finalize. Metoda finalize se poziva neposredno pre unitavanja objekta od strane GC-a.

    Ovde je vano naglasiti da metodu finalize ne treba koristiti za oslobaanje zauzetih resursa, jer se metoda finalize ne mora pozvati! Naime, GC sam odreuje kada e ukloniti objekat iz memorije, i lako se moe desiti da se to nikad ne dogodi: program je pokrenut, radio je neko vreme, raunar raspolae sa dovoljno radne memorije tako da GC nije poeo sa uklanjanjem objekata, i tako sve do zavretka rada programa; GC nije uklonio objekat, samim tim nije pozvao metodu finalize, i eventualno oslobaanje zauzetih resursa se nije ni desilo.

    Sledi primer klase koja implementira metodu finalize (pokretanjem ovog pro-grama sa java A verovatno e se demonstrirati mogunost da se GC nikad ne aktivira):

    class A { A() { System.out.println("Konstruktor"); } protected void finalize() throws Throwable { System.out.println("finalized"); } public static void main(String[] args) { A a = new A(); System.out.println("main running..."); } }

    1.11 Metode i njihovi parametri Sintaksa definisanja metoda (u smislu navoenja njihovog imena, liste parametara i tipa rezultata) je nalik sintaksi u jeziku C++. Sledi primer jedne metode koja prima tri parametra, sa tipovima String, int i boolean, a vraa vrednost tipa void (tj. ne vraa rezultat).

    void metoda(String name, int value, boolean test) { ... } Parametri metode mogu biti primitivni tipovi i reference na objekte; tip rezultata metode moe biti primitivni tip ili referenca na objekat.

    esto se postavlja se pitanje da li promena vrednosti parametra u okviru metode ima efekta na promenljivu koja je koriena kao parametar nakon povratka iz metode. Posmatrajmo sledeu metodu:

    void test(Automobil a) { a.radi = true; }

    U pitanju je metoda koja u okviru svog tela vri modifikaciju svog parametra a preko metode upali. (Koristi se klasa Automobil definisana u prethodnim primerima). U sluaju da se ova metoda pozove u sledeem segmentu koda:

    Automobil x = new Automobil();

  • 12

    x.radi = false; test(x); // da li je atribut radi ovde true ili false?

    vrednost atributa radi objekta x bie true. Slika 1.4 ilustruje ta se zapravo desilo: na steku je kreirana referenca x na objekat klase Automobil. Zatim je vrednost atributa radi ovog objekta postavljena na false (slika a). Nakon toga pozvana je metoda test, sa referencom x kao parametrom. Parametri metoda se, slino kao i u drugim programskim jezicima, smetaju na stek prilikom poziva metode (ovde je nebitno u kom redosledu). Tako je i referenca x iskopirana na stek jo jednom (slika b). U okviru tela metode test ova druga kopija reference x se koristi kao parametar metode i preko nje se pristupa istom onom objektu na koji ukazuje i originalna referenca x. Pristup objektu se u ovom sluaju svodi na promenu vrednosti atributa radi na true (slika c). Kod vraanja iz metode nazad, sa steka se uklanjaju parametri korieni prilikom poziva metode. Tako se sa steka uklanja druga kopija reference x i ostaje samo originalna referenca. Kada preko nje pristupimo atributu radi, videemo da je on promenio vrednost (slika d).

    x x

    xradi: false

    a)

    radi: false

    b)

    x

    x

    radi: true

    c)x

    radi: true

    d) Slika 1.4. Promena stanja objekta koji je parametar metode

    Nakon ovog primera moe se zakljuiti sledee: promene nad parametrima metode nainjene u okviru tela metode koji su reference na objekte su vidljive nakon povratka iz metode. Ili, kako se to sree u drugim programskim jezicima, efekat je isti kao kod prenosa parametara po adresi.

    Sa primitivnim tipovima stvari stoje upravo suprotno: oni se, kao parametri metoda ponaaju kao kod prenosa parametara po vrednosti. Sledi primer:

    void test(int a) { a = 1; } ... int a = 0; test(a); // koliko je ovde vrednost a?

    Slika 1.5 prikazuje ta se deava u ovom sluaju: deklarie se promenljiva a tipa int i odmah se inicijalizuje na vrednost 0. Lokalne promenljive primitivnog

  • 13

    tipa se smetaju na stek (trenutno stanje ilustruje slika a). Zatim se poziva metoda test sa parametrom a; parametar a se smeta na stek (zapravo, njegova vrednost se kopira jo jednom slika b). U okviru metode vrednost parametra se menja u 1, pri emu se menja druga kopija na steku (slika c). Nakon povratka iz metode, parametar se uklanja sa steka i na steku ostaje originalna vrednost promenljive a koja nije menjana (slika d).

    a = 0 a = 0

    a = 0

    a)

    a = 0

    a = 1

    c)

    a = 0

    d)

    b)

    Slika 1.5. Promena vrednosti parametra metode koji je primitivnog tipa

    Preklapanje metoda (method overloading) je u Javi doputeno. Preklopljene metode su metode koje imaju isto ime, ali se razlikuju po listi parametara. Kompajler ih smatra za sasvim razliite metode, bez obzira to imaju isto ime. Metode ne mogu da se razlikuju samo po tipu rezultata kojeg vraaju. Sledi primer klase sa tri preklopljene metode:

    class A { int metoda() { ... } int metoda(int i) { ... } int metoda(String s) { ... } }

    Preklapanje metoda se odnosi kako na klasine metode, tako i na konstruktore.

    1.12 Kljuna re final Kljuna re final se moe nai ispred definicije atributa ili metode unutar definicije klase. Ako se nae ispred atributa, oznaava atribut kome nije mogue promeniti vrednost. Drugim reima, final atribut predstavlja konstantu. Inicijalizacija prilikom deklaracije atributa je obavezna. Primer definicije jednog final atributa bio bi:

    final int size = 100; Kljuna re final ima drugo znaenje kod metoda: oznaava metode koje se ne mogu redefinisati prilikom nasleivanja date klase. O nasleivanju e vie biti rei u odeljku 1.18, a o redefinsanju metoda u odeljku 1.20. Primer jedne final metode glasi:

    final int metoda(int i) { ... }

  • 14

    1.13 Kljuna re static Kljuna re static se moe nai ispred definicije atributa ili metode, nezavisno od pojave kljune rei final. Kada se nae ispred definicije atributa, oznaava atribut koji pripada klasi, a ne objektima (kao instancama klase). Drugim reima, moe se rei da svi objekti date klase dele istu vrednost statikog atributa. Na primer, klasa StaticTest poseduje jedan statiki atribut:

    class StaticTest { static int i = 0; static void metoda() { i++; } }

    Tada e sledei programski segment izazvati promenu vrednosti atributa i u oba objekta:

    StaticTest a = new StaticTest(); StaticTest b = new StaticTest(); a.i++; // ovde je a.i == b.i == 1

    Statiki atribut je pridruen klasi, a ne njenim instancama. U tom smislu, moe mu se pristupiti i kada nije kreiran nijedna instanca klase. Tada se atributu pristupa tako to se navodi ime klase, pa zatim ime atributa, kao u sledeem primeru:

    StaticTest.i++; Statike metode su metode koje ne mogu biti pozvane nad objektima-instancama klase, ve nad klasom samom. U tom smislu, nije mogue pisati

    a.metoda(); nego samo

    StaticTest.metoda(); Statike metode imaju pristup samo statikim atributima klase.

    esto korieni primer upotrebe statikog atributa je ispisivanje na konzolu: System.out.println("Hello, world!");

    pri emu se poziva metoda println objekta out koji je statiki atribut klase System (out zapravo predstavlja standardni izlaz, slino kao stdout u jeziku C).

    1.14 Nizovi Nizovi se u Javi definiu vrlo slino kao u jeziku C++. Na primer, niz iji su elementi tipa int se definie na sledei nain:

    int[] a; ili int a[]; Ovim je samo definisana referenca na niz; niz se nakon toga mora kreirati na nain slian kreiranju objekata. Sledi primer gde se alocira niz od pet int elemenata:

    a = new int[5];

  • 15

    Prvi element niza ima indeks nula. Postoji i nain da se niz definie, alocira memorija za njega i odmah inicijalizuje, kao u sledeem primeru:

    int[] a = { 1, 2, 3, 4, 5 }; Treba voditi rauna o tome da se prilikom definicije niza referenca na niz uva na steku, dok se elementi niza uvaju na heap-u, slino kao i objekti. Slika 1.6 ilustruje ovu situaciju za niz definisan u prethodnom primeru.

    a heap

    1 2 3 4 5

    Slika 1.6. Inicijalizovan niz

    Kada je u pitanju niz iji su elementi primitivnog tipa, alokacija memorije za elemente niza se odvija automatski. To nije sluaj kada je u pitanju niz iji su elementi objekti neke klase. Na primer, niz od 5 elemenata klase Automobil se definie kao na primer:

    Automobil[] parking = new Automobil[5]; Ovim je zapravo definisan niz iji elementi su reference na objekte klase Automobil. Slika 1.7 ilustruje ovu situaciju.

    parking heap

    Slika 1.7. Niz objekata pri emu objekti nisu inicijalizovani

    Ovakav niz referenci na objekte se moe inicijalizovati, recimo, u odgovarajuoj for petlji, kao u primeru:

    for (int i = 0; i < parking.length; i++) parking[i] = new Automobil();

    (Svaki niz ima definisan atribut length koji predstavlja duinu alociranog niza). Sada e stanje u memoriji izgledati kao na slici 1.8.

    parking heapa1 a2 a3 a4 a5

    Slika 1.8. Niz inicijalizovanih objekata

    1.15 Viedimenzionalni nizovi Viedimenzionalni nizovi se predstavljaju kao nizovi nizova. Sintaksa je slina jeziku C++. Na primer, definicija

  • 16

    int[][] a = { {1, 2, 3}, {4, 5, 6} }; e kreirati niz od dva elementa koji su reference na nizove od tri elementa tipa int. Stanje u memoriji e nakon kreiranja ovakvog niza izgledati kao na slici 1.9.

    a heap1 2 3

    4 5 6

    Slika 1.9. Dvodimenzionalni niz

    Viedimenzionalni niz se moe kreirati na sledei nain: int[][] a = new int[2][3];

    pri emu e se izvriti potrebna alokacija memorije, ali ne i inicijalizacija vrednosti elemenata niza. Dvodimenzionalni niz se moe kreirati i postupno, kao u sledeem primeru:

    int[][] a = new int[2][]; for (int i = 0; i < a.length; i++) a[i] = new int[3];

    Prilikom kreiranja viedimenzionalnog niza iji su elementi objekti, a ne primitivnog tipa, potrebno je jo izvriti i dodatno kreiranje svakog od objekata. Na primer:

    Automobil[][] parking = new Automobil[2][]; for (int i = 0; i < parking.length; i++) { parking[i] = new Automobil[3]; for (int j = 0; j < parking[i].length; i++) parking[i][j] = new Automobil(); }

    Stanje u memoriji nakon kreiranja ovakvog niza izgledae kao na slici 1.10.

    parking heapa1a2 a3

    a4 a5 a6

    Slika 1.10 Viedimenzionalni niz iji elementi su objekti

    Viedimenzionalni niz objekata moe se inicijalizovati odmah prilikom definicije, slino kao kod viedimenzionalnog niza primitivnih tipova. Sledi primer:

    Automobil[][] a = { { new Automobil(), new Automobil() }, { new Automobil(), new Automobil() } };

  • 17

    1.16 Paketi, CLASSPATH i JAR arhive

    1.16.1 Paketi Java programi se sastoje iskljuivo iz klasa. Broj klasa koje ine program moe biti relativno velik, pa je uvoenje nekakve organizacije u takav skup klasa neophodno. Paketi su nain da se klase grupiu po nekom kriterijumu. Paketi mogu da sadre klase ili potpakete, analogno odnosu direktorijuma i datoteka u okviru fajl-sistema.

    Svaka klasa mora da pripada nekom paketu. Ako se ne navede kom paketu pripada data klasa, podrazumeva se da pripada tzv. korenskom ili implicitnom paketu. Taj korenski paket nema posebno ime. On moe da sadri klase i potpakete, koji sa svoje strane takoe mogu da sadre klase i potpakete. Slika 1.11 prikazuje strukturu paketa nekog programa.

    Slika 1.11 Struktura paketa u programu

    Paketi i klase su u okviru fajl-sistema zaista i organizovani kao direktorijumi i datoteke: paketi su predstavljeni direktorijumima, a klase se nalaze u odgovarajuim datotekama.

    Klasa koja se nalazi u nekom paketu (osim korenskog), mora u okviru svoje datoteke imati odgovarajuu deklaraciju, kao u sledeem primeru:

    package paket1; class Automobil { ... }

    Deklaracija package se mora nalaziti na samom poetku teksta datoteke, tj. nijedna druga deklaracija se ne sme nalaziti ispred nje. Datoteka Automobil.java mora biti smetena u direktorijum paket1 koji se nalazi u korenskom direkto-rijumu aplikacije. Naziv korenskog direktorijuma nije vaan, niti je vano gde se on nalazi u okviru fajl-sistema. Prevoenje klase Automobil se mora obaviti komandom:

    Vano je primetiti da se komanda za prevoenje poziva iz korenskog direktorijuma projekta i da se kao parametar navodi ime .java datoteke, zajedno sa relativnom putanjom do nje. Analogno tome, klasa Tocak koja se nalazi u paketu paket3 gornjeg primera, prevela bi se komandom:

    Tekst klase Tocak obavezno mora poeti odgovarajuom deklaracijom:

    package paket2.paket3; class Tocak { ... }

  • 18

    Vidimo da se za separaciju imena paketa u okviru Java programa koristi taka, a ne kosa crta ili obrnuta kosa crta.

    Ve je reeno da se prilikom pokretanja programa navodi ime one klase koja sadri metodu main. Prilikom navoenja imena ove klase mora se navesti njeno puno ime, ukljuujui i paket u kome se klasa nalazi. Na primer, ukoliko klasa Tocak poseduje metodu main, i elimo da odatle pone izvravanje programa, program moramo pokrenuti pomou sledee komande:

    Dakle, ponovo je vano sa kog mesta se poziva Java interpreter: to mora biti korenski direktorijum aplikacije. Svaka prevedena klasa se u okviru aplikacije vidi u okviru paketa ija je putanja jednaka relativnoj putanji do odgovarajueg direktorijuma. Separator naziva paketa je, kao to je ve reeno, taka, a ne kosa crta ili obrnuta kosa crta.

    Programski jezik Java stie sa velikim brojem klasa grupisanim u pakete. Te klase su dostupne kao i klase koje sami piemo (ak se moe dobiti i njihov izvorni kod). Recimo klasa Vector koja se nalazi u paketu java.util je u programima dostupna kao java.util.Vector. Kako bi svako pominjanje ove klase u tekstu programa zahtevalo navoenje pune putanje do nje (odnosno navoenje odgovarajueg paketa), to bi program uinilo manje itljivim. Zato je mogue na poetku teksta klase deklarisati da se koristi ta-i-ta klasa koja se nalazi u tom-i-tom paketu. Na primer:

    package paket1; import java.util.Vector; class Automobil { ... }

    Nadalje se u tekstu klase Automobil klasa Vector koristi samo navoenjem njenog imena, bez imena paketa u kome se nalazi. Treba obratiti panju na to da se import deklaracija mora nalaziti izmeu (opcione) package deklaracije i definicije klase.

    Ukoliko koristimo vie klasa iz istog paketa, moramo svaku od njih navesti u odgovarajuoj import deklaraciji. Drugi nain je da se importuju sve klase iz datog paketa pomou doker-znaka *:

    package paket1; import java.util.*; class Automobil { ... }

    Ovakav nain importovanja ne obuhvata i sve potpakete importovanog paketa! Niti je dozvoljeno korienje doker znakova kao u primeru:

    import java.util.Vec*; // nije dozvoljeno! Klase koje se nalaze u paketu java.lang nije potrebno importovati. Odgovarajua import deklaracija se podrazumeva.

  • 19

    1.16.2 CLASSPATH S obzirom na do sada izloeno, korienje klase Vector iz paketa java.util bi znailo da se odgovarajue stablo direktorijuma java\util\... koje sadri kompajlirane klase mora kopirati unutar strukture direktorijuma svake aplikacije koju piemo. Time se bespotrebno zauzima prostor i komplikuje odravanje softvera. Zato postoji nain da se paketi sa klasama koji se koriste iz vie aplikacija uvaju na jednom mestu, a sve aplikacije e pomou odgovara-jueg mehanizma te klase videti kao da je struktura direktorijuma iskopirana u okviru svake aplikacije. U pitanju je mehanizam slian korienju PATH pro-menljive okruenja (environment variable).

    Java interpreter za ovu svrhu koristi promenljivu okruenja koja se naziva CLASSPATH. Ona sadri listu direktorijuma u kojima treba traiti klase koje se koriste. Na primer, ukoliko je cela java\... hijerarhija paketa smetena u direktorijum C:\java\lib, vrednost CLASSPATH promenljive bi mogla da glasi:

    CLASSPATH=C:\java\lib ime bi sve klase smetene po svojim paketima unutar direktorijuma C:\java\lib bile vidljive za sve Java aplikacije. Ukoliko CLASSPATH treba da sadri vie direktorijuma, oni se navode jedan za drugim, sa takom-zarez kao separatorom. Na primer:

    CLASSPATH=C:\java\lib;D:\mojalib Na UNIX sistemima sintaksa navoenja vrednosti CLASSPATH promenljive se unekoliko razlikuje, time to se direktorijumi razdvajaju znakom dvotaka.

    Ukoliko u CLASSPATH dodamo direktorijum D:\temp\korenski paket iz pretho-dnih primera, na primer komandom:

    tada i na program moemo pokrenuti sa bilo kog mesta u okviru fajl sistema, jer e klase biti vidljive preko CLASSPATH-a. Na primer, komanda:

    e pokrenuti na program iako se ne nalazimo u direktorijumu D:\temp\korenski paket.

    1.16.3 JAR arhive Distribucija biblioteka klasa smetenih u svoje pakete nije preterano elegantna u sluaju veeg broja klasa i paketa, jer se poveava broj datoteka i direktorijuma koje treba instalirati i navesti u CLASSPATH-u. Zbog toga je omogueno arhiviranje biblioteka u tzv. JAR arhive. U pitanju su arhive koje sadre klase u svojim paketima arhivirane u klasinom Zip formatu. Podrazumevana ekstenzija im je .jar (mada moe biti i .zip). Ovakve arhive se mogu generisati alatkom jar koja je sastavni deo JDK paketa, ali mogu i bilo kojim drugim programom koji moe da generie Zip arhive (ekstenziju moemo sami promeniti kasnije). Sve klase iz osnovne Java biblioteke su, prilikom instalacije

  • 20

    JDK paketa, smetene u datoteku %JAVA_HOME%\jre\lib\rt.jar, gde je JAVA_HOME direktorijum gde je instaliran JDK paket. Ovu datoteku moemo otvoriti, recimo, programom WinZip, kao na slici 1.12.

    Slika 1.12. Arhiva rt.jar otvorena programom WinZip

    Na slici vidimo da se klasa Vector (zapravo, prevedena datoteka Vector.class) u okviru arhive nalazi u direktorijumu java\util, dakle onom koji odgovara paketu u kome se nalazi klasa.

    Umesto da u okviru CLASSPATH-a navodimo direktorijum u kome se nalazi raspakovan sadraj arhive rt.jar, moemo navesti samu datoteku rt.jar (sa svojom putanjom) i dobiemo isti efekat. Na primer:

    CLASSPATH=C:\jdk1.3\jre\lib\rt.jar Dakle, CLASSPATH moe da sadri nazive direktorijuma i Zip arhiva u kojima se nalaze deljene biblioteke. Korienje direktorijuma u arhiva je u ovom sluaju potpuno ravnopravno.

    1.16.4 Podrazumevane komponente u CLASSPATH-u U dosadanjim primerima je naglaavano da se prilikom pokretanja programa moramo nalaziti u korenskom direktorijumu aplikacije. To je, zapravo, posledica injenice da se tekui direktorijum u kome se nalazimo nalazi u CLASSPATH-u kada on nije definisan, kao da je

    CLASSPATH=. gde je taka (.) oznaka za tekui direktorijum. Ako se CLASSPATH promenljiva definie, tekui direktorijum se mora eksplicitno navesti u CLASSPATH-u. Jo jedna komponenta CLASSPATH-a se podrazumeva, a to je upravo biblioteka rt.jar o kojoj je bilo rei u prethodnom odeljku. Nju ne moramo navoditi ak ni kada definiemo promenljivu CLASSPATH. Dakle, svaki CLASSPATH uvek sadri ovu dve komponentu:

    CLASSPATH=C:\jdk1.3\jre\lib\rt.jar Ukoliko CLASSPATH uopte nije definisan, onda on obuhvata i tekui direktorijum, tako da se moe rei da CLASSPATH u tom sluaju glasi:

  • 21

    CLASSPATH=.;C:\jdk1.3\jre\lib\rt.jar Ovde treba obratiti panju da je ovaj podrazumevani skup komponenti CLASSPATH-a uveden tek od Java verzije 1.2. U starijim verzijama CLASSPATH nema podrazumevanih komponenti.

    Iako se u ovom tekstu u primerima poziva Java kompajlera koristi standardni javac, u praksi se umesto njega esto koristi IBM-ov kompajler jikes, koji je znatno bri. jikes nije deo standardne JDK instalacije i mora se instalirati posebno. Do svoje verzije 1.02 (tekua verzija u ovom trenutku) on se ponaa kao Java 1.1 kompajler, tako da nema podrazumevanih komponenti u CLASSPATH-u. Kako je prilino nezgodno menjati sadraj CLASSPATH promenljive naizmenino za kompajliranje jikes-om i pokretanje java-om, problem se moe prevazii korienjem promenljive okruenja JIKESPATH koju koristi iskljuivo jikes. Ona ima isto znaenje kao CLASSPATH do Java verzije 1.1. Dakle, ako CLASSPATH ima sadraj:

    CLASSPATH=.;D:\nekamojabibl.zip JIKESPATH bi trebalo da ima sledei sadraj:

    JIKESPATH=.;C:\jdk1.3\jre\lib\rt.jar;D:\nekamojabibl.zip

    1.17 Zadatak: klasa Matrix Zadatak 1. Napisati klasu Matrix datu na slici 1. Implementacija metoda je ostavljena kao zadatak. Namena svake metode je opisana odgovarajuim kometarom u tekstu klase.

    Napomena: u realizaciji izostaviti provere ispravnosti parametara (odgovarajue dimenzije matrica). class Matrix { /* Postavlja sadraj matrice. */ void setData(double[][] x) {...} /* Vraa sadraj matrice. */ int[][] getData() {...} /* Mnoi sadraj matrice objekta koji je pozvan (this) sa sadrajem matrice b (objekta koji je prosleen kao parametar). Rezultat mnoenja smeta u novi objekat koga vraa kao rezultat metode. */ Matrix multiply(Matrix b) {...} /* Mnoi sadraj dve date matrice i rezultat mnoenja vraa kao rezultat metode. Obratiti panju da je ovo statika metoda! */ static Matrix multiply(Matrix a, Matrix b){...} /* Mnoi sadraj matrice objekta koji je pozvan (this) sa sadrajem matrice b (objekta koji je prosleen kao parametar). Rezultat mnoenja se smesta u matricu objekta koji je pozvan. Metoda ne vraa nikakav rezultat! */ void multiply2(Matrix b) {...} /* Polazna taka programa. Slui za testiranje funkcionalnosti ostalih metoda klase. Za potrebe testiranja formirati nekoliko

  • 22

    viedimenzionalnih nizova. */ public static void main(String[] args) {...} /* Sadrzaj matrice */ double[][] data; /* Dimenzije matrice */ int n, m; }

    1.18 Nasleivanje Nasleivanje, kao jedan od osnovnih koncepata objektno-orijentisanog pro-gramiranja, postoji i u Javi. Kada jedna klasa nasleuje drugu, potrebno je to naglasiti u okviru teksta klase klazulom extends kao u sledeem primeru, gde klasa BorbeniAvion nasleuje klasu Avion:

    class Avion { Krilo levo, desno; void poleti() { ... } void sleti() { ... } } class BorbeniAvion extends Avion { Top top; Bomba[] bombe; void poleti() { ... } void pucaj() { ... } }

    Java ne doputa viestruko nasleivanje (onako kako je to definisano recimo u jeziku C++). Dakle klasa moe da nasledi najvie jednu klasu.

    1.19 Modifikatori pristupa U Javi postoje sledea tri modifikatora pristupa:

    public: oznaava da su atribut ili metoda vidljivi za sve klase u programu

    protected: atribut ili metoda su vidljivi samo za klase naslednice private: atribut ili metoda su vidljivi samo unutar svoje klase nespecificiran (tzv. friendly): atribut ili metoda su vidljivi sa klase iz istog

    paketa

    Modifikatori pristupa se navode ispred definicije metode ili atributa. Sledi primer:

    class Avion { protected Krilo levo, desno; public void poleti() { ... } public void sleti() { ... } }

    Na slian nain modifikatori pristupa se mogu primeniti i na celu klasu, na primer:

    public class Avion { ... }

  • 23

    1.20 Redefinisanje metoda Redefinisanje metoda (method overriding) je postupak kada klasa naslednica redefinie telo metode nasleene od roditeljske klase. U Javi se to specificira prostim navoenjem nove definicije metode u klasi naslednici. Sledi primer:

    class A { int metoda1() { System.out.println("metoda1 klase A"); } int metoda2() { System.out.println("metoda2 klase A"); } } class B extends class A { int metoda1() { System.out.println("metoda1 klase B"); } }

    U sluaju da se izvri sledei segment koda: A varA = new A(); B varB = new B(); varA.metoda1(); varB.metoda1(); varA.metoda2(); varB.metoda2();

    na konzoli e se ispisati: metoda1 klase A metoda1 klase B metoda2 klase A metoda2 klase A

    (metoda1 je redefinisana u klasi B, tako da je promenjen ispis na konzolu, dok metoda2 nije redefinisana, pa se za klasu B preuzima implementacija metode iz klase A).

    1.21 Apstraktne klase Apstraktne klase su klase koje ne mogu imati svoje instance (objekte). Razlog za to je to je implementacija neke od metoda izostavljena. U primeru

    public abstract class A { public void metoda1() { ... } public abstract void metoda2(); private int i; }

    metoda metoda2 je proglaena za apstraktnu korienjem kljune rei abstract. Njena implementacija nije navedena. Samim tim klasa je apstraktna pa se i za nju to mora navesti navoenjem kljune rei abstract ispred class. Dakle iskaz poput:

    A x = new A();

  • 24

    nije doputen.

    1.22 Interfejsi Interfejsi su poseban koncept u Javi: nisu u pitanju klase, ali interfejsi mogu da sadre deklaracije apstraktnih metoda, konstanti i statikih atributa. Sledi primer:

    interface Instrument { void sviraj(); void nastimaj(); }

    Vidimo da interfejsi podseaju na apstraktne klase. Veza izmeu klasa i interfejsa je sledea: kae se da klasa implementira (a ne nasleuje) interfejs. Klasa moe da implementira vie interfejsa istovremeno, to nije sluaj sa nasleivanjem. Nema prepreke da klasa koja nasleuje drugu klasu implementira i neke interfejse. Jedan interfejs moe da nasledi drugi interfejs. Sledi primer:

    class Klarinet implements Instrument { void sviraj() { ... } void nastimaj() { ... } }

    Time to je klasa implementirala interfejs zapravo se obavezala da e implementirati sve njegove metode. Kompajler nee dopustiti prevoenje klase koja implementira interfejs a nije redefinisala sve njegove metode.

    1.23 Unutranje klase Od Java verzije 1.1 klasa moe, osim atributa i metoda, da poseduje i tzv. unutranje klase (inner classes). Sledi primer:

    class Spoljasnja { void metoda() { ... } class Unutrasnja { int metoda2() { ... } } }

    Klasa Unutrasnja je, u principu, vidljiva samo unutar klase Spoljasnja, mada se to moe promeniti modifikatorima pristupa na uobiajen nain. Instanca unutranje klase se moe kreirati i izvan nje, ali samo preko instance spoljanje klase, kao u sledeem primeru:

    Spoljasnja s = new Spoljasnja(); Spoljasnja.Unutrasnja u = s.new Unutrasnja();

    Sledei izraz (pokuaj konstrukcije instance inutranje klase bez instance spoljanje klase) nije dozvoljen:

    Spoljasnja.Unutrasnja u = new Spoljasnja.Unutrasnja(); Koncept unutranjih klasa se najvie koristi prilikom izgradnje grafikog korisnikog interfejsa, o emu e vie rei biti u poglavlju 3.

  • 25

    1.24 Polimorfizam Polimorfizam je koncept koji omoguava objektima da ispolje razliito ponaanje, zavisno od njihove klase, bez obzira to se oni koriste kao instance nekog zajednikog roditelja. Posmatrajmo sledee tri klase:

    abstract class Instrument { abstract void sviraj(); } class Violina extends Instrument { void sviraj() { ... } } class Klarinet extends Instrument { void sviraj() { ... } }

    Dakle, primer definie tri klase: klasa Instrument je apstraktna klasa (njena metoda sviraj je apstraktna), a klase Violina i Klarinet nasleuju klasu Instrument i, naravno, implementiraju (zapravo, redefiniu) apstraktnu metodu. Posma-trajmo sada klasu Muzicar:

    class Muzicar { void sviraj(Instrument i) { i.sviraj(); } }

    Vidimo da klasa Muzicar ima metodu sviraj koja kao parametar ima instancu klase Instrument; sa druge strane, znamo da klasa Instrument ne moe imati instance, jer je apstraktna. Ova metoda e ipak biti upotrebljiva, jer se njoj kao parametar moe proslediti instanca neke klase koja nasleuje klasu Instrument u ovom sluaju instance klasa Violina i Klarinet. Iskaz

    Muzicar m = new Muzicar(); m.sviraj(new Klarinet());

    e izazvati pozivanje metode sviraj klase Klarinet (iako se to nigde eksplicitno ne navodi u metodi sviraj klase Muzicar). Iskaz

    m.sviraj(new Violina()); e izazvati pozivanje metode sviraj klase Violina po istom principu. Dakle, poziv metode sviraj klase Muzicar e imati razliite efekte zavisno od toga koji objekat prosledimo kao parametar. Odreivanje koja metoda e se pozvati se obavlja u toku izvravanja programa.

    U primeru se vidi da ovo specijalno ponaanje metoda nije niim naglaeno u tekstu programa. Ovakav efekat se u jeziku C++ postizao korienjem tzv. virtuelnih funkcija lanica, a u Javi je ovo podrazumevano (i jedino mogue) ponaanje. Dakle, moemo rei, u terminologiji jezika C++, da su sve metode u Javi virtuelne, pa se ta osobina ne mora naglaavati posebno u programu.

    1.25 Izuzeci Izuzeci su mehanizam za kontrolu toka programa koji se koristi za obradu greaka nastalih u toku izvravanja programa. Segment programskog koda za

  • 26

    koji smatramo da moe da izazove izuzetak moemo da smestimo u tzv. try/catch blok, kao u sledeem primeru:

    try { // kod koji moe da izazove izuzetak } catch (Exception ex) { System.out.println("Desio se izuzetak: " + ex); }

    Izuzetak moe biti, na primer, deljenje nulom, pristup elementu niza koji je izvan granice niza, itd. Ukoliko se prilikom izvravanja koda koji se nalazi u try bloku desi izuzetak, tok izvravanja programa se automatski prebacuje na poetak catch bloka. Nakon izvravanja koda u catch bloku, program dalje nastavlja rad.

    U okviru catch bloka informacije o samom izuzetku koji se dogodio su dostupne preko objekta klase Exception ili neke njene naslednice. U primeru je to objekat ex.

    Razliite vrste izuzetaka su predstavljene razliitim exception klasama, na primer: svi izuzeci prilikom izvravanja aritmetikih operacija (deljenje nulom, overflow, itd.) su predstavljene klasom ArithmeticException, pristup elementu iji je indeks izvan granice niza je predstavljen klasom ArrayIndexOutOfBounds-Exception, itd. Klasa Exception je zajedniki predak svim exception klasama.

    Jedan try blok moe imati vie sebi pridruenih catch blokova, kao u sledeem primeru:

    try { // kod koji moe da izazove // izuzetak } catch (ArithmeticException ex) { System.out.println("Deljenje nulom"); } catch (ArrayIndexOutOfBoundsException ex) { System.out.println("Pristup van granica niza"); } catch (Exception ex) { System.out.println("Svi ostali izuzeci"); } finally { // kod koji se izvrava u svakom sluaju }

    Kada se dogodi izuzetak, niz catch blokova se sekvencijalno obilazi i ulazi se u onaj catch blok ija klasa odgovara izuzetku koji se dogodio. Re odgovara u ovom sluaju znai: u pitanju je klasa kojoj exception objekat pripada, ili njen predak. Kada poslednji catch blok hvata izuzetak klase Exception, to znai da e svi izuzeci biti obraeni, jer je klasa Exception zajedniki roditelj.

    Blok finally se ne mora navesti. On sadri blok koda koji e se izvriti u svakom sluaju, desio se izuzetak ili ne.

  • 27

    Kao to postoje odgovarajue klase koje opisuju razliite vrste izuzetaka, mogue je definisati i nove vrste izuzetaka definicijom odgovarajue klase. Na primer, moemo da definiemo novu vrstu izuzetka predstavljenog klasom MojException koja je data u primeru:

    public class MojException extends Exception { public MojException() { super(); } public MojException(String msg) { super(msg); } }

    Klasa MojException ima dva konstruktora koji pozivaju odgovarajue konstruktore roditeljske klase Exception. Pisanje ovakvih konstruktora nije obavezno, ali je obavezno naslediti klasu Exception (ili nekog njenog potomka).

    Ovakav korisniki izuzetak moe biti izazvan samo programski, pomou kljune rei throw, kao u sledeem primeru:

    if (errorCheck()) throw new MojException("Houston, we have a problem.");

    Programski kod koji sadri ovakvu throw naredbu mora biti smeten unutar try bloka koji hvata izuzetak MojException na to e nas naterati kompajler. Dakle, ovo bi moglo da izgleda na sledei nain:

    try { if (errorCheck()) throw new MojException("Houston, we have a problem."); } catch (MojException ex) { System.out.println("Exception: " + ex); }

    Drugi nain da obradimo nastanak ovakvog izuzetka je da metodu u kojoj se nalazi throw naredba oznaimo kao metodu u kojoj moe da nastane izuzetak date vrste. Na primer:

    public void metoda() throws MojException { ... if (errorCheck()) throw new MojException("Houston, we have a problem."); ... }

    Sada poziv ovakve metode mora biti u odgovarajuem try bloku, ili metoda u kojoj sadri ovaj poziv mora isto biti oznaena da moe da izazove izuzetak. Dakle:

    public void m1() { try { metoda(); } catch (MojException ex) { System.out.println("Exception: " + ex); } }

  • 28

    ili: public void m1() throws MojException { metoda(); }

    Na ovaj nain odgovornost za obradu izuzetka moe propagirati sve do metode main od koje poinje izvravanje programa!

    1.26 Klasa Object Klasa Object predstavlja osnovnu klasu u hijerarhiji Java klasa, u smislu da sve klase nasleuju klasu Object. Za klase za koje se navede da ne nasleuju nijednu klasu (izostavljanjem extends klauzule) podrazumeva se da nasleuju klasu Object. Klasa Object nije apstraktna, tako da je mogue kreirati objekat ove klase. Ona definie neke metode koje se relativno esto koriste, poput ovih koje su opisane u nastavku ovog odeljka.

    public boolean equals(Object o); Koristi se prilikom poreenja objekata; poreenje tipa (a == b) je zapravo poreenje referenci. Poreenje (a.equals(b)) vraa rezultat zavisno od implementacije metode equals klase kojoj pripada objekat a. Klasa Object definie podrazumevano poreenje objekata koje se svodi na poreenje referenci.

    public int hashCode(); Izraunava hash vrednost za dati objekat. Koristi se najvie u hash-tabelama.

    public String toString(); Vraa string reprezentaciju objekta. Ukoliko se ne redefinie, poziva se implementacija iz klase Object koja vraa prilino nerazumljiv rezultat. Ova metoda ima donekle specijalan tretman od strane kompajlera, o emu e vie rei biti u sledeem odeljku.

    1.27 Klasa String Klasa String se nalazi u paketu java.lang i predstavlja string kao tip podatka (seamo se da stringovi nemaju odgovarajui primitivni tip u Javi). U tom smislu, klasa String je kao i svaka druga Java klasa osim to ima donekle specijalan tretman od strane kompajlera.

    1. Vrednosti primitivnih tipova se mogu predstaviti u Java programu odgova-rajuim konstantama. Na primer, 16 je vrednost tipa int, vrednost 16L oznaava vrednost tipa long, 'x' je vrednost tipa char, itd. Objektima se ne moe pridruiti vrednost koja se moe predstaviti literalom, osim u sluaju objekata klase String. U tom smislu, "tekst" u Java programu predstavlja objekat klase String ija je vrednost inicijalizovana na dati tekst. Zbog toga je sasvim ispravno pisati

    String x = "tekst"; to ima isti efekat kao i

  • 29

    String x = new String("tekst"); 2. Java ne omoguava redefinisanje operatora (kao to je to mogue u jeziku C++). Meutim, operator + moe da se upotrebi za konkatenaciju stringova. Kada naie na izraz poput

    "ime" + "prezime" ili x + "prezime" ili x + y kompajler e generisati kod koji e izvriti konkatenaciju stringova i vratiti rezultat u obliku novokreiranog objekta klase String. Konkatenacija moe da obuhvati i primitivne tipove ili objekte drugih klasa. Na primer, iskaz

    int a = 10; String x = "vrednost: " + a;

    rezultira kreiranjem novog String objekta iji sadraj je "vrednost: 10". U sluaju konkatenacije stringa sa objektom neke druge klase, kao na primer:

    Automobil a = new Automobil(); String x = "Moj auto je: " + a;

    bie pozvana metoda toString klase Automobil, pa e se zatim izvriti konkatenacija stringova pomou dobijenog stringa.

    3. Metoda koja kao parametar ima tip String, moe u svom pozivu da primi i objekat neke druge klase, pri emu e kompajler automatski generisati kod koji poziva metodu toString() objekta, i zatim taj rezultat prosleuje metodi koja se poziva. Na primer, posmatrajmo metodu

    public void handleMessage(String message) { ... } i njen poziv

    handleMessage(new Automobil()); Ovaj poziv metode handleMessage bie, u stvari, preveden u sledei poziv:

    handleMessage(new Automobil().toString()); 4. Za razliku od svih ostalih parametara, parametri metoda tipa String se ponaaju kao da se prenose po vrednosti a ne po referenci, iako su u pitanju objekti, a ne primitivni tipovi. Na primer, poziv sledee metode

    public void handleMessage(String message) { message += "xxx"; }

    nee izazvati promenu objekta koji je prosleen kao parametar, jer e se u telu metode, prilikom konkatenacije, generisati novi String objekat koji e biti dodeljen lokalnoj kopiji reference message. Po povratku iz metode unitava se promenjena lokalna kopija reference, i ostaje samo originalna referenca koja i dalje ukazuje na stari String objekat.

    1.28 Primeri nekih klasa iz standardne biblioteke Namena ovog odeljka je da ilustruje korienje nekih od klasa koje su sastavni deo standardne Java biblioteke, a koriste se esto u praksi. Prednost postojanja ovako bogate standardne biblioteke je i u tome to se sa sigurnou zna da su

  • 30

    ove klase dostupne u svakoj Java instalaciji, pa se klase iz biblioteke mogu slobodno koristiti, bez bojazni da ih nee biti na raunaru gde softver instalira, ili ak, u sluaju Jave 1.2, da ih nee biti u CLASSPATH-u.

    1.28.1 Klasa java.util.Vector Klasa Vector slui kao kontejnerska klasa koja uva kolekciju objekata kao sekvencu. Elementima sekvence se moe pristupati po indeksu, a elementi se mogu dodavati i uklanjati na proizvoljnom mestu. Klasa je pisana tako da radi sa Object objektima, tako da je u stanju da prihvati sve objekte koje joj prosledimo.

    Sledi primer u kome se u jednom Vector objektu uva niz String-ova. Za doda-vanje elemenata u vektor koristi se metoda addElement, a za pristup objektima koristi se metoda elementAt. Iako ovaj primer demonstrira smetanje objekata iste klase u vektor, to ne mora biti sluaj. Nema prepreke da se u isti vektor smetaju objekti razliitih klasa.

    import java.util.Vector; class VectorTest { public static void main(String args[]) { Vector v = new Vector(); v.addElement("Ovo"); v.addElement("je"); v.addElement("probni"); v.addElement("tekst"); for (int i = 0; i < v.size(); i++) System.out.print((String)v.elementAt(i) + " "); } }

    1.28.2 Klasa java.util.Hashtable Klasa Hashtable implementira hash-tabelu koja mapira kljueve na vrednosti (i kljuevi i vrednosti su predstavljeni odgovarajuim objektima). Parovi (klju, vrednost) se u metodu smetaju metodom put. Vrednost se u tabeli trai pomou svog kljua metodom get. Sledei primer predstavlja generisanje 10000 sluajnih celih brojeva u opsegu [0, 19] i brojanje koliko se puta koji broj pojavio pomou hash-tabele. Tabela kao klju koristi generisani broj, a vrednost je objekat klase Counter koji slui kao broja pojava odgovarajueg broja.

    class Counter { int i = 1; public String toString() { return Integer.toString(i) + "\n"; } } import java.util.*; class Statistics { public static void main(String args[]) { Hashtable ht = new Hashtable(); for (int i = 0; i < 10000; i++) { Integer r =

  • 31

    new Integer((int)(Math.random() * 20)); if (ht.containsKey(r)) ((Counter)ht.get(r)).i++; else ht.put(r, new Counter()); } System.out.println(ht); } }

    1.28.3 Klasa java.util.StringTokenizer Klasa StringTokenizer je namenjena za parsiranje stringova oko datih delimitera. Za dati string i delimitere, generiu se tokeni u odgovarajuem redosledu. Metoda hasMoreTokens vraa true ako nije iscrpljena lista tokena dobijenih parsiranjem. Metoda nextToken vraa string koji predstavlja tekui token u parsiranju. Dati primer prikazuje parsiranje teksta oko blanko-znakova i ispisivanje dobijenih tokena na konzolu.

    import java.util.*; class TokenizerTest { public static void main(String args[]) { String text = "Ovo je probni tekst"; StringTokenizer st = new StringTokenizer(text, " "); while (st.hasMoreTokens()) { System.out.println(st.nextToken()); } } }

    1.29 Konvencije davanja imena Ovaj odeljak navodi neke od opteprihvaenih konvencija za davanje imena identifikatorima u Java programima.

    1. Nazivi klasa se piu malim slovima, osim to poinju velikim slovom (npr. Automobil, Vector). Ne postoji nikakav prefiks (kao CVector ili TVector). Ukoliko se naziv klase sastoji iz vie rei, rei se spajaju, a svaka od njih poinje velikim slovom (npr. StringTokenizer, ArrayIndexOutOfBoundsException).

    2. Nazivi metoda i atributa se piu malim slovima (npr. size, width). Ako se sastoje od vie rei, rei se spajaju, pri emu sve rei poevi od druge poinju velikim slovom (npr. setSize, handleMessage).

    3. Nazivi paketa se piu iskljuivo malim slovima. Ukoliko se sastoje iz vie rei, rei se spajaju (npr. mojpaket, velikipaket.malipaket).

    Detaljan opis konvencija nalazi se na adresi http://java.sun.com/docs/codeconv/-index.html.

    1.30 Generisanje programske dokumentacije i javadoc Standardna JDK distribucija sadri i alat javadoc namenjen generisanju programske dokumentacije. Kao izvor informacija za generisanje dokumen-

  • 32

    tacije koriste se specijalni komentari u izvornom kodu, koji poinju sa /** i zavravaju sa */ (za razliku od klasinih komentara /* ... */). Rezultat rada javadoc alata je skup HTML dokumenata koji opisuju dati program.

    Specijalni komentar koji se nalazi neposredno ispred definicije klase smatra se opisom klase koji se smeta na odgovarajue mesto u dokumentaciji. Slino tome, specijalni komentar koji se nalazi neposredno ispred definicije metode ili atributa smatra se opisom te metode ili atributa.

    Unutar specijalnih komentara mogu se koristiti HTML tagovi za formatiranje teksta. Dostupne su takoe i sledee posebne oznake (tzv. doc tags): @param Opisuje parametar metode.

    @param ime opis @return Opisuje rezultat metode.

    @return opis @throws Opisuje izuzetak koji moe da izazove metoda.

    @throws puno-ime-klase opis @see Referenca na neku drugu klasu, metod ili atribut.

    @see ime-klase @see puno-ime-klase @see puno-ime-klase#ime-metode

    @author Podaci o autoru. @author author-info

    @version Opis verzije. @version version-info

    @since Navodi od koje verzije nekog objekta dati kod moe da radi. Obino se koristi da oznai minimalnu potrebnu verziju JDK paketa. @since since-info

    @deprecated Oznaava zastarelu mogunost koja moe biti napu-tena u sledeim verzijama. Kompajler e generisati upozorenje ako se koriste ovakve metode ili atributi.

    Primer jedne Java klase koja sadri odgovarajue javadoc komentare dat je u nastavku. /** Klasa namenjena za rad sa matricama * @author Branko Milosavljevi * @version 1.0 */ public class Matrix { /** Konstruktor * @param n Broj redova matrice * @param m Broj kolona matrice * @throws MathException U sluaju da je neka od * dimenzija manja od 1 */ public Matrix(int n, int m) throws MathException { ... } /** Postavlja sadraj matrice. * @param x Nova vrednost matrice * @throws MathException U sluaju da je neka od

  • 33

    * dimenzija manja od 1, ili je vrednost parametra * null */ public void setData(double[][] x) throws MathException { ... } /** Vraa sadraj matrice. * @return Tekua vrednost matrice */ public double[][] getData() { ... } /** Mnoi sadraj matrice objekta koji je pozvan (this) sa * sadrajem matrice b (objekta koji je prosleen kao * parametar). Rezultat mnoenja smeta u novi objekat koga * vraa kao rezultat metode. * @param b Druga matrica u mnoenju * @return Rezultat mnoenja * @throws MathException U sluaju neispravnih dimenzija matrica */ public Matrix multiply(Matrix b) throws MathException { ... } /** Mnoi sadraj dve date matrice i rezultat mnoenja * vraa kao rezultat metode. Obratiti panju da je ovo * statika metoda! * @param a Prvi inilac poizvoda * @param b Drugi inilac proizvoda * @return Rezultat mnoenja * @throws MathException U sluaju neispravnih dimenzija matrica */ public static Matrix multiply(Matrix a, Matrix b) throws MathException { ... } /** Mnoi sadraj matrice objekta koji je pozvan (this) sa * sadrajem matrice b (objekta koji je prosleen kao * parametar). Rezultat mnoenja se smeta u matricu objekta * koji je pozvan. Metoda ne vraa nikakav rezultat! * @param b Drugi inilac proizvoda * @throws MathException U sluaju neispravnih dimenzija matrica */ public void multiply2(Matrix b) throws MathException { ... } /** Vraa string reprezentaciju objekta. * @return String reprezentacija objekta */ public String toString() { ... } /** Sadraj matrice */ private double[][] data; /** Dimenzije matrice */ private int n, m; }

    1.31. Zadaci: modifikacije klase Matrix Zadatak 2. Proiriti zadatak 1 tako da se u okviru metoda klase Matrix vri provera dimenzija matrice na odgovarajui nain. Signalizaciju greke reali-zovati pomou mehanizma izuzetaka. Napisati sopstvenu klasu MathException za obradu izuzetaka ove vrste.

  • 34

    Zadatak 3. Napisati klasu TestMatrix sa metodom main iz klase Matrix. Metodu main ukloniti iz klase Matrix. Klase Matrix i MathException smestiti u paket vta.math, a klasu TestMatrix u implicitni (korenski) paket. Prevesti i pokrenuti program.

    Zadatak 4. a) Isprobati pokretanje klase TestMatrix iz nekog drugog direktorijuma; modifikovati sistemsku varijablu CLASSPATH na odgovarajui nain. b) Paket vta.math spakovati u JAR arhivu vta.jar. Arhivu dodati u CLASSPATH i pokrenuti klasu TestMatrix.

  • 35

    Poglavlje 2

    Konkurentno programiranje u Javi

    Java je programski jezik koji sadri koncepte potrebne za pisanje konkurentnih programa. Izvravanje ovakvih programa zavisi, naravno, od koriene Java virtuelne maine, operativnog sistema, i hardverske platforme, ali su te zavisnosti sklonjene od Java programera. Drugim reima, isti konkurentni program se moe izvravati na razliitim raunarskim platformama bez modifikacija. Pisanje konkurentnih programa obino zahteva korienje odgovarajuih funkcija operativnog sistema, to takve programe ini teko prenosivim na razliite operativne sisteme.

    Svaki Java program je, zapravo, konkurentan program: garbage collector, o kome je bilo rei u prethodnom poglavlju, se izvrava kao posebna nit programa. Na izvravanje garbage collector-a nemamo velikog uticaja, a u pisanju konkurentnih programa moemo zanemariti injenicu da je garbage collector aktivan u okviru posebne niti.

    2.1 Kreiranje programskih niti Programska nit (thread) se u Javi predstavlja objektom klase Thread ili njene naslednice. Klasa Thread je, u sutini, roditeljska klasa koju je potrebno naslediti prilikom definisanja nove programske niti.

    Sam programski kod koji definie rad niti je smeten unutar metode run ovakve klase. Sledi primer novodefinisane niti:

    public class MojThread extends Thread { public void run() { // programski kod niti je ovde } }

    (U primerima e crvenom bojom biti naglaeni elementi programskog koda na koje se eli skrenuti posebna panja). Kreiranje instance ovakve klase nije dovoljno da bi se nit pokrenula. Za pokretanje niti potrebno je pozvati metodu start. Ne treba pozivati metodu run direktno, jer to nee izazvati potreban efekat. Metoda start (koja se obino ne redefinie) e obaviti potrebnu inicijalizaciju i pozvati metodu run. Dakle, pokretanje nove niti klase MojThread moe da se obavi sledeim segmentom koda:

  • 36

    MojThread mt = new MojThread(); mt.start();

    Od ove take nadalje, na program se sastoji iz dve niti: osnovne niti programa koja poinje svoje izvravanje od metode main, i novostvorene niti koja je opisana u metodi run klase MojThread. Slika 2.1 ilustruje ovu situaciju.

    osnovna nit

    MojThread mt = new MojThread();mt.start();mt

    Slika 2.1 Pokretanje nove niti

    Drugi nain za kreiranje programske niti je implementacija interfejsa Runnable. Ovaj postupak se obino koristi kada nije mogue naslediti klasu Thread (zato to nova klasa ve nasleuje neku klasu, a viestruko nasleivanje nije dozvoljeno). Implementiranje interfejsa Runnable se svodi na implementiranje metode run koja ima istu funkciju kao i u prethodnom sluaju. Na primer, klasa MojaNit u ovom sluaju je definisana tako da implementira interfejs Runnable.

    public class MojaNit implements Runnable { public void run() { // programski kod niti je ovde } }

    Pokretanje ovakve niti se unekoliko razlikuje od prethodnog sluaja. Evo kako se to radi:

    MojaNit mn = new MojaNit (); Thread t = new Thread(mn); t.start();

    Ukoliko je programski kod metode run jednak u oba sluaja, obe varijante su funkcionalno ekvivalentne.

    2.2 Daemon i non-daemon niti Java programi razlikuju dve vrste programskih niti: tzv. daemon i non-daemon niti. Nit se proglaava za daemon-nit tako to se pozove metoda setDaemon(true), a non-daemon-nit tako to se pozove setDaemon(false). Sutinska razlika izmeu ove dve vrste niti je u tome to e se Java program zavriti kada se okonaju sve njegove non-daemon niti. Inicijalno program startuje sa jednom non-daemon niti koja poinje svoje izvravanje metodom main. Daemon-niti su namenjene za obavljanje zadataka u pozadini, ije kompletno izvravanje nije od znaaja za rad programa.

  • 37

    2.3 Primer programa sa vie niti Posmatrajmo sledei program koji se sastoji iz klasa PrviThread i ThreadTest: public class ThreadTest { /** Broj niti koje ce se pokrenuti */ public static final int THREAD_COUNT = 10; /** Pokrece sve niti i zavrsava sa radom */ public static void main(String[] args) { for (int i = 0; i < THREAD_COUNT; i++) new PrviThread(i).start(); System.out.println("Threads started."); } } public class PrviThread extends Thread { /** Konstruktor * @param threadID Identifikator niti */ public PrviThread(int threadID) { this.threadID = threadID; counter = 10000; } /** Nit: na svaki 1000-ti prolaz petlje ispisi poruku na konzolu. */ public void run() { while (counter > 0) { if (counter % 1000 == 0) System.out.println("Thread[" + threadID + "]: " + (counter/1000)); counter--; } } /** Brojac petlje unutar niti */ private int counter; /** ID niti */ private int threadID; } Klasa ThreadTest sadri metodu main odakle poinje izvravanje programa. U okviru ove metode kreira se deset novih niti klase PrviThread. Treba primetiti da se u telu petlje u istom redu kreira novi objekat klase PrviThread (sa new PrviThread(i)) i nad tim objektom odmah poziva metoda start. Nigde se ne uva referenca na ovaj objekat, jer ona nije ni potrebna. Nakon izlaska iz petlje ispisuje se poruka da je kreiranje niti zavreno i tu je kraj metode main.

    Klasa PrviThread ima konstruktor koji prima identifikator niti kao parametar (identifikator smo sami definisali). U konstruktoru se inicijalizuje i vrednost brojake promenljive counter. U okviru metode run izvrava se petlja od 10000 iteracija (pomou brojaa counter) i u svakom hiljaditom prolazu ispisuje se poruka na konzolu. Nakon izlaska iz petlje nit se zavrava.

  • 38

    Posmatrajmo poetak jedne mogue varijante izvravanja ovog programa prikazane na slici 2.2.

    Slika 2.2. Izvravanje programa ThreadTest

    Na slici vidimo da je prva ispisana poruka zapravo poruka koju ispisuje metoda main kada zavrava sa radom. To znai da je u ovom sluaju, prilikom pokretanja programa, osnovna nit programa stigla da izvri celokupan svoj programski kod pre nego to su druge niti dobile priliku da zauzmu procesor. Samim tim, ovo je ilustracija sluaja gde zavravanje osnovne niti programa ne predstavlja i zavravanje celog programa: postoji jo deset non-daemon niti koje nisu zavrile svoj rad. Ova situacija bi se grafiki mogla predstaviti kao na slici 2.3.

    osnovna nit

    new PrviThread(0).start();

    new PrviThread(1).start();new PrviThread(2).start();

    ...

    new PrviThread(9).start();

    x

    x

    xx

    x

    Slika 2.3. Grafika predstava izvravanja programa ThreadTest

  • 39

    2.4 Sinhronizacija niti Prethodni primer predstavlja program u kome izvravanje jedne niti ne utie na izvravanje ostalih niti (osim to ta nit konkurie za zauzee procesora). Konkurentni programi ovakve vrste su relativno retki. Kada je potrebno da dve niti komuniciraju, komunikacija se mora obaviti putem zajednikog (deljenog) resursa. U Javi je u pitanju zajedniki objekat kojem obe niti mogu da pristupe.

    Kako niti dobijaju deo procesorskog vremena na osnovu odluke Java virtuelne maine i operativnog sistema, ne moemo biti sigurni da jedna nit u toku pristupa deljenom objektu nee biti prekinuta i kontrola biti predata drugoj niti koja isto tako moe poeti da pristupa deljenom objektu i izazvati greke prilikom nastavka izvravanja prve niti (koja u objektu zatie drugaije stanje u odnosu na trenutak kada je bila prekinuta).

    Zbog toga je neophodno koristiti mehanizam zakljuavanja objekata koji obezbeuje da najvie jedna nit moe da pristupa deljenom objektu u nekom periodu vremena. Ovaj mehanizam je u Javi implementiran pomou tzv. synchronized blokova. Synchronized blok izgleda kao u sledeem primeru:

    synchronized (obj) { // obj je deljeni objekat; // imamo ekskluzivno pravo pristupa njemu // unutar ovog bloka }

    Poetak synchronized bloka predstavlja zakljuavanje objekta od strane niti. Kraj bloka predstavlja oslobaanje objekta. Kada hronoloki prva nit pokua da ue u synchronized blok, dobie pravo pristupa i zakljuae objekat (acquire lock). Sve dok ta nit ne oslobodi objekat (release lock), druge niti nee moi da mu pristupe. Ako neka druga nit pokua da ue u svoj synchronized blok, bie blokirana u toj taki sve dok prva nit ne oslobodi objekat. Tada e druga nit dobiti pravo pristupa, zakljuati objekat i ui u svoj synchronized blok. Slika 2.4 ilustruje ovu situaciju.

    obj

    nit A nit B

    1) lock

    sync {

    }

    4) unlock

    2) locked?

    3) yes5) lock

    6) unlock

    wait

    sync {

    }

    Slika 2.4. Pristup deljenom objektu iz dve niti

    Drugi nain za implementaciju mehanizma zakljuavanja objekata su tzv. synchronized metode. Synchronized metoda se definie kao u sledeem primeru:

    public synchronized void metoda() { ... }

  • 40

    Poziv ovakve metode se ponaa kao ulazak u synchronized blok: za vreme izvravanja metode samo nit koja je pozvala metodu ima prava pristupa objektu.

    2.5 Dodatne metode za sinhronizaciju Nekad je potrebno da nit saeka na neki dogaaj, iako se nalazi unutar synchronized bloka. To ekanje moe da traje proizvoljno dugo, pa bi u tom sluaju pristup zakljuanom objektu bio nemogu u proizvoljno dugakom intervalu vremena.

    Metoda wait (nasleena iz klase Object, tako da je dostupna u svim klasama) radi sledee: oslobaa zauzeti objekat i blokira izvravanje niti sve dok neka druga nit ne pozove metodu notify nad istim objektom.

    Metoda notify (takoe nasleena iz klase Object) obavetava nit koja je (hronoloki) prva pozvala wait da moe da nastavi sa radom. Nit koja je ekala u wait metodi nee odmah nastaviti izvravanje, nego tek nakon to nit koja je pozvala notify ne izae iz svog synchronized bloka (slika 2.5).

    Metoda notifyAll obavetava sve niti koje ekaju u wait da mogu da nastave sa radom. Nakon izlaska iz synchronized bloka sve te niti e konkurisati za procesorsko vreme.

    obj

    nit A nit B

    sync {

    }

    sync {

    }

    wait();

    notify();

    waitingfor

    notify

    notify

    waitingfor

    lock

    Slika 2.5. Mehanizam wait/notify

    Ove tri metode mogu biti pozvane samo unutar synchronized bloka i to nad objektom nad kojim se vri sinhronizacija.

    2.6 Primer programa sa sinhronizacijom niti Posmatrajmo dve niti, jednu koja proizvodi podatke i drugu koja ih troi. One komuniciraju preko deljenog objekta koji je zapravo bafer za podatke. Potrebno je omoguiti da se punjenje i pranjenje bafera odvijaju u paralelnim nitima (slika 2.6).

    Bafer predstavlja klasinu implementaciju krunog bafera. Nit proizvoa e puniti bafer (osim ako ve nije pun, tada mora da eka), a nit potroa e

  • 41

    prazniti bafer (osim ako nije prazan, tada mora da eka). U naem primeru nit proizvoa je implementirana klasom Producer, a nit potroa klasom Consumer.

    public class Consumer extends Thread { public Consumer(Buffer buffer, int count) { this.buffer = buffer; this.count = count; } public void run() { for (int i = 0; i < count; i++) buffer.read(); } private Buffer buffer; private int count; } public class Producer extends Thread { public Producer(Buffer buffer, int count) { this.buffer = buffer; this.count = count; } public void run() { for (int i = 0; i < count; i++) buffer.write((int)Math.round(Math.random() * 100)); } private Buffer buffer; private int count; }

    Vidimo da klase Consumer i Producer ne poseduju nikakav programski kod koji vri sinhronizaciju pristupa. Sinhronizacija je obavljena na nivou metoda read i write klase Buffer. Objekti klasa Consumer i Producer preko svojih konstruktora primaju bafer sa kojim e raditi i broj podataka koje treba da proitaju, odnosno upiu u bafer.

    Klasa Buffer sadri sve to je potrebno za sinhronizaciju niti. Sledi programski kod klase Buffer. /** Implementacija krunog bafera */ public class Buffer { /** Konstruktor * @param size Veliina krunog bafera */ public Buffer(int size) { this.size = size; data = new int[size]; readPos = 0; writePos = 0;

  • 42

    } /** Upisuje novu vrednost u bafer. * @param value Nova vrednost koja se upisuje */ public synchronized void write(int value) { if (isFull()) { System.out.println("Waiting to write..."); try { wait(); } catch (Exception ex) { ex.printStackTrace(); } } data[writePos] = value; if (++writePos == size) writePos = 0; notify(); System.out.println("Written: "+value); } /** ita narednu vrednost iz bafera. * @return Proitana vrednost */ public synchronized int read() { if (isEmpty()) { System.out.println("Waiting to read..."); try { wait(); } catch (Exception ex) { ex.printStackTrace(); } } int retVal = data[readPos]; if (++readPos == size) readPos = 0; System.out.println("Read: "+retVal); notify(); return retVal; } /** Ispituje da li je bafer prazan. * @return Vraa true ako je bafer prazan */ public synchronized boolean isEmpty() { return readPos == writePos; } /** Ispituje da li je bafer pun. * @return Vraca true ako je bafer pun */ public synchronized boolean isFull() { return readPos == (writePos + 1) % size; } /** Veliina krunog bafera */ private int size; /** Sadraj krunog bafera */ private int[] data; /** Naredna lokacija za itanje */ private int readPos; /** Naredna lokacija za pisanje */

  • 43

    private int writePos; } Konstruktor klase Buffer prima kao parametar veliinu bafera. U konstruktoru se alocira memorija za bafer, i inicijalizuju se indeksi lokacije za itanje iz bafera i lokacije za pisanje u bafer.

    Metoda isEmpty slui za testiranje da li je bafer prazan, a metoda isFull za testiranje da li je bafer pun. Smatra se da je bafer prazan ako su indeksi pozicija lokacija za itanje i pisanje jednaki. Bafer je pun ako je indeks pozicije za itanje za jedan manji od lokacije za pisanje ili je indeks lokacije za itanje jednak nuli, a indeks lokacije za pisanje jednak indeksu poslednjeg elementa niza koga koristi bafer. Slika 2.6 ilustruje ove situacije.

    writePos readPos writePos readPos

    writePos readPos writePosreadPos

    writePosreadPos

    a)

    b)

    c)

    Slika 2.6. a) Sluajevi kada je bafer prazan; b) sluajevi kada je bafer pun;

    c) sluajevi kada bafer nije ni prazan ni pun

    Metoda read je namenjena za itanje podataka i njihovo uklanjanje iz bafera. Metoda je definisana kao synchronized, tako da obezbeuje ekskluzivno pravo pristupa baferu onoj niti koja je pozove. U okviru metode, prvo se proveri da li je bafer prazan; ako nije, prvi podatak koji je na redu za itanje se uklanja iz bafera i vraa se kao rezultat metode. Ako je bafer prazan, poziva se wait metoda, ime se izvravanje ove niti suspenduje sve dok proizvoa nit ne upie novi podatak u bafer; tada e se, u okviru metode write, pozvati metoda notify, ime e se potroa nit ponovo aktivirati.

    Metoda write je namenjena za pisanje podataka u bafer. Takoe je definisana kao synchronized. Njeno funkcionisanje je simetrino metodi read. U okviru metode prvo se proverava da li je bafer pun; ako nije, novi podatak se upisuje u bafer. Ako je bafer pun, poziva se metoda wait, ime se nit suspenduje sve dok potroa nit ne proita podatak iz bafera, ime e se proizvoa nit ponovo aktivirati.

    Klasa Test je namenjena za pokretanje programa. Sadri samo metodu main u okviru koje se kreira bafer, proizvoa nit, potroa nit i niti se pokrenu.

    public class Test { public static final int BUFFER_SIZE = 100;

  • 44

    public static final int PRODUCE_COUNT = 100; public static void main(String[] args) { Buffer buffer = new Buffer(BUFFER_SIZE); Producer p = new Producer(buffer, PRODUCE_COUNT); Consumer c = new Consumer(buffer, PRODUCE_COUNT); p.start(); c.start(); } }

    2.7 Zadatak: problem pet filozofa Zadatak 5. Napisati program koji simulira problem pet filozofa.

    Objanjenje: Posmatra se okrugli sto za kojim sedi pet filozofa. Izmeu njihovih tanjira nalazi se pet tapia za jelo. Kako su za obedovanje potrebna dva tapia, nije mogue obezbediti da svih pet filozofa obeduje istovremeno. Svaki od filozofa e zauzeti jedan od njemu potrebnih tapia im ovaj bude slobodan. Ovaj problem moe da ilustruje nastanak deadlock-a. Slika 2.7 prikazuje ovaj problem.

    Slika 2.7. Ilustracija problema pet filozofa

  • 45

    Poglavlje 3

    GUI aplikacije i JavaBeans

    3.1 AWT i Swing Programski jezik Java je, u svojoj inicijalnoj verziji, posedovao biblioteku komponenti za izgradnju grafikog korisnikog interfejsa (GUI) zvanu Abstract Window Toolkit (AWT). U pitanju je biblioteka koja se zasniva na korienju komponenti korisnikog interfejsa koje su dostupne na platformi na kojoj se program pokree (Windows, Motif, Macintosh, itd). To znai da je implementacija AWT komponenti razliita za svaki operativni sistem. Java klase koje pred-stavljaju AWT komponente koriste su u velikoj meri native programski kod koji je vrio interakciju sa operativnim sistemom. Na primer, AWT klase u Windows distribuciji Java virtuelne maine koriste awt.dll d