Uvod

Računar je složen sistem koji se sastoji iz puno komponenata. Najvažnija komponenta je centralna procesorska jedinica. U pitanju je jedan čip čiji je posao da izvršava programe. Program je lista nedvosmislenih instrukcija koje računar mehanički izvršava. Računar može da izvršava instrukcije koje su napisane u tzv. mašinskom jeziku. Svaki tip računara ima svoj mašinski jezik i može da direktno izvršava samo programe koji su pisani u tom jeziku. (Programe koji su pisani u drugim jezicima može da izvršava samo ako se prevedu u mašinski jezik tog računara.) Mašinski jezik se sastoji od vrlo jednostavnih isntrukcija koje CPU tog računara može direktno da izvršava. Sa druge strane, skoro svi programi se pišu u programskim jezicima višeg nivoa, kao što su Java, Pascal ili C++. Program koji se napiše u nekom od ovih jezika ne može da se direktno izvršava na nekom računaru. On mora da se prvo prevede u mašinski jezik. Ovo radi poseban program, kompajler. Kompajler uzima program napisan u jeziku višeg nivoa i prevodi ga u izvršni program u mašinskom jeziku. Ako program treba da se izvrši na nekom drugom računaru, mora da se prevede u taj drugi mašinski jezik uz upotrebu drugog kompajlera, koji odgovara tom drugom tipu računara. Postoji i alternativa za kompajliranje programa pisanog u jeziku višeg nivoa. Umesto da se koristi kompajler koji odjednom prevodi program, možete da koristite interpreter, koji prevodi instrukciju po instrukciju. Interpreter je program koji se ponaša slično kao CPU, odnosno postoje ciklusi važenja instrukcija i njihovog izvršavanja. Interpreter radi u petlji koja stalno čita instrukcije iz programa, odlučuje da li je potrebno da se ona izvrši i ako je potrebno obavlja odgovarajuđu komandu iz mašinskog jezika. Postoje interpreteri koji izvršavaju jezike višeg nivoa. Na primer, programski jezik LISP radi preko interpretera, a ne preko kompajlera. Dizajneri Jave su odlučili da koriste kombinaciju kompilacije i interpretacije. Programi koji su pisani u Javi se kompajliraju u mašinski jezik, ali je u pitanju mašinski jezik za računar koji ne postoji u stvarnosti. U pitanju je virtuelni računar, poznat kao Java virtuelna mašina. Mašinski kod za JVM se naziva bajtkod. Nema nijednog razloga zašto Java bajtkod ne bi mogao da se koristi kao mašinski jezik za pravi računar. Sun Microsystems su i napravili takav računar, odnosno procesor. Sa druge strane, jedna od najvažnijih stvari u Javi je da se Java program može da izvršava na bilo kom računaru. Sve što na tom računaru treba da postoji je interpreter za Java bajtkod. Za svaki računar treba da postoji drugi Java bajtkod interpreter, ali kad računar jednom ima taj interpreter, on može da izvršava bilo koji program pisan u Javi. Isti Java program se može da izvrši na bilo kom računaru koji ima takav interrpreter. Ovo je i jedna od najvažnijih karakteristika Jave, Isti program može da se izvršava na različitim računarima.

1

Zašto biste koristili Java bajtkod? Zašto se ne bi distribuisao originalni Java program, koji bi se kasnije kompajlirao u odgovarajući mašinski jezik. Postoji više razloga. Prvo, kompajler mora da razume Javu, koja je složeni jezik visokog nivoa. Sam kompajler je složeni program. Interpreter za bajtkod je sa druge strane prilično jednostavan program. Lako je napisati interpterer bajtkoda za svaki tip računara, nakon čega taj interpreter može da izvrši bilo koji Java program. Bilo bi mnogo teže napisati Java kompajler za svaki tip računara. Još jedan razlog je sigurnost. Puno Java programa se preuzimaju preko mreže. Ne biste želeli da preuzmete program koji će oštetiti Vaš računar. Interpreter bajtkoda se ponaša kao bafer između Vas i programa koji ste preuzeli. Vi u suštini pokrećete interpreter, koji indirektno izvršava preuzeti program. Interpreter može da Vas zaštiti od potencijalno opasnih akcija, koje su deo tog programa. Java i Java bajtkod ne moraju obavezno da budu povezani. Program napisan u Javi bi mogao da se kompajlira i u neki drugi mašinski jezik, realnog računara. Programi pisani u drugim programskim jezicima bi mogli da se kompajliraju u Java bajtkod. Ipak, kombinacija Jave i Java bajtkoda je ono što daje nezavisnost platforme, sigurnost i kompatibilnost.

Objektno orijentisano programiranje
Objektno orijentisano programiranje je odgovor na softversku krizu iz devedesetih godina pro{log veka. Tada dolazi do nagle ekspanzije primene ra~unara u svim oblastima. Programi postaju sve ve}i i slo`eniji. U njihovom razvoju u~estvuje sve ve}i broj programera. Tradicionalni algoritamski na~in programiranja ne mo`e da odgovori izazovima koji se tada javljaju. Ovde se pre svega misli na mogu}nost kasnijeg odr`avanja softvera. Programi imaju vi{e hiljada linija koda u kojima se treba sna}i. Odgovor je bio u objektno orijentisanom programiranju. [ta su objekti? Sve mo`e biti objekat. Objekti su svuda oko nas. Objektni mogu predstavljati realne ili apstraktne stvari. Objekat je va{ pas, sto, knjiga, bicikla sve {to nas okru`uje. Objekti iz realnog sveta imaju dve karakteristike, a to su stanje i pona{anje. Stanje Va{eg psa predstavlja njegova boja, ime, rasa i sl. Pona{anje nam govori da li on laje, da li je gladan i sl. Softverski objekti su sli~ni ovim objektima iz realnog sveta po tome {to imaju stanje i pona{anje. Stanje softverskog objekta se izra`ava njegovim atributima, koji se opisuju preko promenljivih. Pona{anje softverskog objekta se implementira preko metoda. Metodi su funkcije (potprogrami) koji su pridru`eni jednom objektu. Objekti iz realnog sveta mogu da se predstave softverskim objektima. Na primer u programu za kontrolu rada elektronske bicikle, se bicikla mo`e predstaviti softverskim objektom, bicikl. Pored realnih objekata softverski objekti se mogu koristiti i za predstavljanje apstraktnih stvari. Tako na primer, u programiranju GUI-ja (grafi~ki korisni~ki interfejs) se za predstavljanje doga|aja mo`e koristiti objekat. Doga|aj mo`e biti klik mi{em, ili pritisak nekog tastera na tastaturi.

Sve {to jedan softverski objekat zna (stanje) i mo`e da uradi (pona{anje) se predstavlja atributima i metodima koji se u njemu nalaze. Na primer, bicikla iz realnog sveta ima svoje atribute, koji se odnose na trenutnu brzinu (10 km/h), broj zup~anika (5) i sl. 2

Objektni dijagrami pokazuju da atributi objekta ~ine njegovo jezgro. Metodi okru`uju to jezgro i sakrivaju ga od ostatka programa. Pakovanje atributa objekta i njihova za[tita putem metoda se naziva u~aurenjem. Objekat se prema tome, sastoji od jezgra, koje ~ine njegovi atributi i membrane, koju ~ine njegovi metodi, preko koje se tom jezgru pristupa. U~aurenje promenljivih i metoda je ideja koja programerima pru`a dve osnovne prednosti: Modularnost: Izvorni kod objekta se mo`e napisati i kasnije se mo`e odr`avati nezavisno od drugih objekata i njihovog koda. Objekat se tako|e mo`e lako proslediti izvan granica sistema. mo`ete nekom dati svoju biciklu i ona }e i dalje da radi. Skrivanje informacija: Objekat ima javni interfejs koji drugi objekti koriste za komunikaciju sa njim. Objekat mo`e da odr`ava svoje privatne informacije i metode koji se mogu u bilo kom trenutku promeniti, a da to ne uti~e na objekte oko njega. Ne morate da poznajete detalje u vezi mehanizma sa zup~anicima bicikle, da biste mogli da je koristite. ^emu ova pri~a o objektima? Java je ~ist objektno orijentisani jezik. To zna~i da u Javi nijedno par~e koda ne mo`e da postoji ako nije deo objekta. U C++-u koji je tako|e objektno orijentisani jezik, mogu da postoje i delovi koda koji nisu objektno orijentisani. Ne samo da mogu, nego uvek postoji takav kod, jer uvek mora da postoji funkcija main, koja ozna~ava glavni program, a koja nije deo nijedne klase.

Java aplikacije
Svaka aplikacija pisana u Javi mora da sadr`i klasu, koja defini{e metod po imenu main(). Klasa mo`e da ima proizvoljno ime, ali metod koji se u aplikaciji prvi pokre}e je metod po imenu main(). Obi~no se iz ovog metoda pozivaju druge metode te ili drugih klasa. Prva Java aplikacija Prva aplikacija je ona koju }ete videti na po~etku rada s abilo kojim programskim jezikom, aplikacija koja }e ispisati tekst “Zdravo”. Evo kako izgleda kod:
/** * Klasa ZdravoApp implementira aplikaciju koja na * standardnom izlazu prikazuje tekst zdravo */ public class ZdravoApp { public static void main(String[] args) { System.out.println("Zdravo!"); //Prikazuje string } }

Program sadr`i definiciju klase ZdravoApp. U ovoj klasi postoji samo jedan metod, metod main(). Prva linija definicije ovog metoda je uvek: public static void main(String[] args) U metodu postoji samo jedan izvr{ni iskaz: System.out.println("Zdravo!"); 3

Klju~na re~ public u definiciji metoda main ozna~ava da tom metodu mo`e da se globalno pristupi. Klju~na re~ static osigurava pristup ~ak i kada ne postoji objekat (instanca) klase ZdravoApp. Klju~na re~ void ozna~ava da ovaj metod ne vra}a nikakvu vrednost. System je standardna klasa koja podr`ava unos preko tastature i prikazivanje izlaza na ekranu. Ova klasa se nalazi u paketu java.lang i mo`e joj se pristupiti samo preko imena klase, System. Objekat out predstavlja standardni izlazni tok, u ovom slu~aju ekran monitora. Ovaj objekat je ~lan klase System. Ovaj metod je deklarisan kao static, {to zna~i da mu se mo`e pristupati i kada ne postoji instanca klase System. println je metod koji pripada objektu out i on {tampa tekst koji se nalazi u zagradama na ekran. Program se kompajlira komandom: javac ZdravoApp.java a izvr{ava komandom java ZdravoApp Kada se program izvr{i na ekranu treba da se prika`e tekst Zdravo Komentari u kodu Postoji nekoliko mogu}ih vrsta definisanja komentara. Jedan od na~ina je da se se upotrebe dve kose crte //. Sve {to sledi iza ovih znakova, a nalazi se u istom redu, smatra se komentarom i to kompajler zanemaruje prilikom prevo|enja. // ovo je komentar u jednom redu Alternativa je da se po~etak komentara ozna~i sa /*, a kraj komentara sa */. Sve {to se nalazi izme|u po~etka i kraja komentara kompajler zanemaruje prilikom prevo|enja. Tekst komentara se na ovaj na~in mo`e da pro{iri na vi{e redova. /* ovo je komentar u u vi{e redova */ Komentari koji slu`e za generisanje dokumentacije po~inju znacima /**, a zavr{avaju se kao i obi~an komentar sa */. Ovakve komentare zatim ~ita poseban program, javadoc, koji od nje pravi dokumentaciju sa hiperlinkovima. Sva dokumentacija koju nalazite na sajtovima vezanim za Java kod, je napravljena na ovaj na~in. U okviru ove dokumentacije mogu se koristiti razli~ite HTML oznake. Na primer: @version - ozna~ava verziju programa @author - ozna~ava autora itd.

Osnove jezika Java
Podaci i promenljive Promenljiva je imenovani deo memorije koji se koristi za sme{tanje informacija u programu. Svaki deo memorije kome ste dali ime mo`e da primi sa odre|eni tip podatka. Svaka promenljiva ima svoje ime i tip. Preko imena pristupate podatku na koji ta promenljiva ukazuje. tip odre|uje {ta u toj promenljivoj mo`e da se na|e i koje su peracije dozvoljene. Kada se jednom defini{e tip promenljive u tom delu memorije mogu da se sme{taju samo podaci tog tipa (ceo broj, realan broj, niz karaktera, objekat i sl.) Na osnovu zadatog tipa kompajler kasnije mo`e da proverava da ste toj promenljivoj 4

poku{ali da zadate neki drugi tip podatka. Ime i tip se promenljivoj zadaju preko deklaracije. Op{ti oblik deklaracije je: tip ime Pored imena i tipa svaka promenljiva ima i svoj domen. Domen promenljive je deo koda u kome se ta promenljiva mo`e da koristi. Domen se implicitno defini{e na osnovu mesta gde se nalazi deklaracije promenljive. Osnovni tipovi promenljivih Celobrojne vrednosti Postoje ~etiri tipa promenljivih koji se mogu koristiti za celobrojne vrednosti. Svaki od njih mo`e da ima predznak, {to zna~i da mogu da sadr`e pozitivne i negativne brojeve. Ovi tipovi se razlikuju po opsegu vrednosti koje mogu da se sme{taju. Evo koji su to tipovi: byte - vrednosti mogu biti od -128 do +128 i u memoriji zauzimaju 1 bajt (8 bitova) short - vrednosti mogu biti od -32768 do 32767 i u memoriji zauzimaju 2 bajta (16 bitova) int - vrednosti mogu biti o -2147483648 do +2147483647 i u memoriji zauzimaju 4 bajta (32 bita) long - vrednosti mogu biti od -9223372036854775808 do +9223372036854775807 i u memoriji zauzimaju 8 bajtova (64 bita) Evo kako izgledaju deklaracije ovih tipova: byte najmanjaVrednost; short brojac; int br; long najvecaVrednost; U jednom iskazu se mo`e deklarisati i vi{e promenljivih: int a, b; Prilikom deklaracije se mo`e izvr{iti i inicijalizacija promenljive. int a = 1; Tipovi sa pokretnim zarezom Slu`e za sme{tanje realnih brojeva. Postoje dva tipa, float i double. float - vrednosti mogu biti od-3.4x1038 do 3.4x1038 i u memoriji zauzimaju 4 bajta. Vrednosti se predstavljaju sa ta~no{}u od 7 cifara. double - vrednosti mogu biti od -1.7x10308 do 1.7x10303 i u memoriji zauzimaju 8 bajtova. Vrednosti se predstavljaju sa ta~no{}u od 17 cifara. Primer: float a = 1.5; double b = 1.67; Znakovne promenljive Promenljiva tipa char zauzima u memoriji dva bajta. Vrednost ovakve promenljive je jedan karakter, kao {to je A, * , x ili belina (blanko karakter). Vrednost mo`e biti i neki specijalni karakter, kao {to je tabulator, ili neki od Unicode karaktera koji dolaze iz razli~itih jezika. Kada se 5

karakter unosi u program on se mora uokviriti jednostrukim navodnicima ‘A’, ‘*’. Navodnici nisu deo vrednosti i ne sme{taju se u promenljivu. U pitanju je samo konvencija. char c = ‘a’; Promenljive tipa boolean Promenljive ovog tipa mogu da imaju samo dve vrednosti: true (ta~no) i false (neta~no). boolean t = false; boolean p = true; Primer:
public class MaxVariablesDemo { public static void main(String args[]) { // celi brojevi byte najveciByte = short najveciShort int najveciInteger long najveciLong =

Byte.MAX_VALUE; = Short.MAX_VALUE; = Integer.MAX_VALUE; Long.MAX_VALUE;

// realni brojevi float najveciFloat = Float.MAX_VALUE; double najveciDouble = Double.MAX_VALUE; // ostali pritimitivni tipovi char c = 'S'; boolean b = true; // prikazivanje System.out.println("Najveca System.out.println("Najveca System.out.println("Najveca System.out.println("Najveca

vrednost vrednost vrednost vrednost

tipa tipa tipa tipa

byte je " + najveciByte); short je " + najveciShort); int je " + najveciInteger); long je " + najveciLong);

System.out.println("Najveca vrednost tipa float je " + najveciFloat); System.out.println("Najveca vrednost tipa double je " + najveciDouble); if (Character.isUpperCase(c)) { System.out.println("Karakter " + c + " je veliko slovo."); } else { System.out.println("Karakter " + c + " je malo slovo."); } System.out.println("Vrednost za promenljivu b je " + b); } }

Operatori i zrazi Aritmeti~ki operatori U tabeli koja sledi su prikazani tipovi i opis aritmeti~kih operatora: Operator
+ -

Upotreba
op1 + op2 op1 - op2

Opis Sabira op1 i op2 Oduzima op2 od op1

6

* / %

op1 * op2 op1 / op2 op1 % op2

Mno`i op1 sa op2 Deli op1 sa op2 Ra~una ostatak deljenja op1 sa op2

Sledi primer AritmetikaDemo u kome se defini{u dve celobrojne promenljive i dva realna broja sa dvostrukom precizno{}u i sa njima se obavljaju razli~ite aritmeti~ke operacije.
public class ArithmeticDemo { public static void main(String[] args) { //nekoliko brojeva int i = 37; int j = 42; double x = 27.475; double y = 7.22; System.out.println("Vrednosti System.out.println(" i = " System.out.println(" j = " System.out.println(" x = " System.out.println(" y = "

promenljivih su..."); + i); + j); + x); + y);

//sabiranje brojeva System.out.println("Sabiranje..."); System.out.println(" i + j = " + (i + j)); System.out.println(" x + y = " + (x + y)); //oduzimanje brojeva System.out.println("Oduzimanje..."); System.out.println(" i - j = " + (i - j)); System.out.println(" x - y = " + (x - y)); //Mno`enje brojeva System.out.println("Mnozenje..."); System.out.println(" i * j = " + (i * j)); System.out.println(" x * y = " + (x * y)); //deljenje brojeva System.out.println("Deljenje..."); System.out.println(" i / j = " + (i / j)); System.out.println(" x / y = " + (x / y)); //Deljenje po modulu System.out.println("Deljenje po modulu..."); System.out.println(" i % j = " + (i % j)); System.out.println(" x % y = " + (x % y)); //mesanje tipova System.out.println("Mesanje tipova..."); System.out.println(" j + y = " + (j + y)); System.out.println(" i * x = " + (i * x)); } }

Izlaz iz ovog programa je:
Vrednosti promenljivih su... i = 37 j = 42 x = 27.475

7

y = 7.22 Sabiranje... i + j = 79 x + y = 34.695 Oduzimanje... i - j = -5 x - y = 20.255 Mnozenje... i * j = 1554 x * y = 198.37 Deljenje... i / j = 0 x / y = 3.8054 Deljenje po modulu... i % j = 37 x % y = 5.815 Mesanje tipova... j + y = 49.22 i * x = 1016.58

Kada se kao operandi u jednoj aritmeti~koj operaciji koriste zajedno ceo broj i realan broj, rezultat je realan broj. Ceo broj se implicitno konvertuje u realan broj pre samog izra~unavanja. U tabeli koja sledi su prikazani tipovi podataka koji se vra}aju iz aritmeti~kih operacija, na osnovu tipova operanada. Potrebne konverzije se vr{e pre {to se obavi operacija. Tip podatka za rezultat
long

Tipovi podataka za operande Nijedan od operanada nije float ili double (artiemtika celih brojeva), a najmanje jedan od operatora je tipa long. Nijedan od operanada nije float ili double (aritmetika celih brojeva). Nijedan operand nije long. Najmanje jedan operand je tipa double. Najmanje jedan operand je tipa float. Nijedan nije tipa double.

int double float

Postoje i dva operanda koji omogu}avaju skra}eno izra~unavanje. To su operator ++ koji operand pove}ava za 1 i operator -- koji operand smanjuje za 1. Oba operatora mogu da se pojave ispred operanda (prefiks) i iza operanda (postfiks). Kod verzije prefiks, ++op/--op se prvo operand pove}ava za 1, pa se taj rezultat koristi dalje u izrazima. Kod verzije postfix se prvo operand primeni u izrazu (stara vrednost), a tek posle se ta vrednost promeni. public class Voce { public static void main(String[] args) { //deklaracija i inicijalizacija tri promenljive int brojNarandzi = 5; int brojJabuka = 10; int brojVocaka = 0; // povecava se broj narandzi i racuna zbir vocaka brojVocaka = ++brojNarandzi + brojJabuka; System.out.println(“Ukupan broj vocaka u programu”); System.out.println(“Broj narandzi je “ + brojNarandzi); System.out.println(“Ukupan broj vocaka je “ + brojVocaka); 8

} } Ukupan broj vo}aka je sada 16. Razlog je {to se broj narand`i prvo pove}ao za 1, pa je taj broj u{ao u sabiranje. Ako se iskaz sabiranja promeni na: brojVocaka = brojNarandzi++ + brojJabuka; ukupni broj vo}aka je 15, po{to je u sabiranje u{la stara vrednost za broj narand`i, koja je tek naknadno pove}ana. Relacioni i uslovni operatori Relacioni operator poredi dve vrednosti i odre|uje vrednost izme|u njih. Na primer, != vra}a ta~no ako dva operanda nisu jednaki. U tabeli koja sledi su dati relacioni operatori: Operator
> >= < <= == !=

Upotreba
op1 > op2 op1 >= op2 op1 < op2 op1 <= op2 op1 == op2 op1 != op2

Vra}a true(ta~no) ako je
op1 ve}e op2 op1 ve}e ili jednako od op2 op1 manje op2 op1 manje ili jednako op2 op1 i op2 su jednaki op1 i op2 su razli~iti

U primeru koji sledi smo definisali tri cela broja i poredili ih pomo}u relacionih operatora.
public class RelacioniDemo { public static void main(String[] args) { //Nekoliko brojeva int i = 37; int j = 42; int k = 42; System.out.println("Vrednosti System.out.println(" i = " System.out.println(" j = " System.out.println(" k = "

promenljivih..."); + i); + j); + k);

//vece od System.out.println("Vece od..."); System.out.println(" i > j = " + (i > j)); System.out.println(" j > i = " + (j > i)); System.out.println(" k > j = " + (k > j)); //vece ili jednako System.out.println("Vece ili System.out.println(" i >= System.out.println(" j >= System.out.println(" k >= //manje od System.out.println("Manje System.out.println(" i System.out.println(" j System.out.println(" k

//false //true //false, oni su jednaki

jednako..."); j = " + (i >= j)); i = " + (j >= i)); j = " + (k >= j));

//false //true //true

od..."); < j = " + (i < j)); < i = " + (j < i)); < j = " + (k < j));

//true //false //false

9

//manje ili jednako System.out.println("Manje System.out.println(" i System.out.println(" j System.out.println(" k

ili jednako..."); <= j = " + (i <= j)); <= i = " + (j <= i)); <= j = " + (k <= j));

//true //false //true

//jednako System.out.println("Jednako..."); System.out.println(" i == j = " + (i == j)); System.out.println(" k == j = " + (k == j)); //razlicito System.out.println("Razlicito..."); System.out.println(" i != j = " + (i != j)); System.out.println(" k != j = " + (k != j)); } }

//false //true

//true //false

Evo kako izgleda izlaz iz ovog programa:
Vrednosti promenljivih... i = 37 j = 42 k = 42 Vece od... i > j = false j > i = true k > j = false Vece ili jednako... i >= j = false j >= i = true k >= j = true Manje od... i < j = true j < i = false k < j = false Manje ili jednako... i <= j = true j <= i = false k <= j = true Jednako... i == j = false k == j = true Razlicito... i != j = true k != j = false

Relacioni operatori se ~esto koriste zajedno sa logi~kim operatorima, ~ime se dobijaju slo`eni izrazi. U Javi postoje slede}i logi~ki operatori: Operator
&&

Upotreba
op1 && op2

Vra}a true(ta~no)ako je i op1 i op2 imaju vrednost true. op2 se izra~unava samo ako je potrebno. ili op1 ili op2 ima vrednost true (ta~no). op2 se izra~unava samo ako je potrebno.
op ima vrednost false (neta~no)

|| !

op1 || op2 ! op

10

& | ^

op1 & op2 op1 | op2 op1 ^ op2

i op1 i op2 imaju vrednost ta~no. Uvek se izra~unava i op1 i op2. Ili je op1 ili je op2 true (ta~no). Uvek se izra~Unava i op1 i op2. ako su op1 i op2 razli~iti, odnosno ako jedan ima vrednost true, ali ne oba.

Koja je razlika izme|u operatora && i &? Razlika je u brzini izvr{avanja programa. Sa operatorom & se vrednost drugog operatora uvek izra~unava, dok se sa operatorom && izra~unava vrednost prvog operanda, a ako je to dovoljno da se izra~una vrednost celog izraza, drugi operand se ne izra~unava. Operatori dodele Osnovni operator dodele je operator =, kojim se jedna vrednost dodeljuje drugoj. U Javi postoje i operatori dodele kojim se odjednom izvr{ava vi{e operacija. Pretpostavimo da `elite da saberete vrednost promenljive sa nekim brojem i da rezultat dodelite istoj promenlivoj. Napisali biste: i = i + 2; Skra}eno se ovo mo`e napisati pomo}u operatora += na slede}i na~in: i += 2; Prethodna dva izraza su ekvivalentna. U tabeli koja sledi su dati neki od operatora ovog tipa: Operator
+= -= *= /= %= &= |= ^=

Upotreba
op1 += op2 op1 -= op2 op1 *= op2 op1 /= op2 op1 %= op2 op1 &= op2 op1 |= op2 op1 ^= op2

Ekvivalentno sa
op1 = op1 + op2 op1 = op1 - op2 op1 = op1 * op2 op1 = op1 / op2 op1 = op1 % op2 op1 = op1 & op2 op1 = op1 | op2 op1 = op1 ^ op2

Ostali operatori U tabeli koja sledi su dati ostali operatori koji postoje u Javi. Operator
?: []

Opis Skra}eni iskaz if-else Koristi se za deklarisanje nizova, za kreiranje nizova, i za pristup elementima niza. 11

. ( params ) ( tip ) new

Koristi se za formiranje kvalifikovanih imena. Defini{e se lista parametara. Vrednosti se odvajaju zarezima. Konvertuje se jedan tip u neki drugi. Kreira se novi objekat ili niz.

instanceof Odre|uje se da li je prvi operator instanca (primerak) drugog

Operator ?: Ovaj operator vra}a op2, ako op1 ima vrednost true (ta~no) ili vrednost op3 ako op1 ima vredcnost false (neta~no).
op1 ? op2 : op3

Pretpostavimo da imamo dve celobrojne promenljive tipa int, mojeGodine i tvojeGodine. @elimo da tre}oj promenljivoj, stariji, dodelimo ve}u od ove dve vrednosti. Evo kako izgleda iskaz: stariji = tvojeGodine > mojeGodine ? tvojeGodine : mojeGodine Prvi argument ovog operatora je logi~ki izraz tvojeGodine > mojeGodine. Ako taj izraz ima vrednost true (ta~no), promenljiva stariji dobija vrednost tvojeGodine, a ako je prvi izraz ocenjen kao false (neta~no) promenljiva stariji dobija vrednost mojeGodine. Operator [] Ovaj operator se koristi za deklarisanje nizova i za pristupanje elementima niza. float [] realniNiz = new float[10]; Ovaj izraz deklari{e niz realnih brojeva sa deset elemenata. Sedmom ~lanu niza mo`ete da pristupite na slede}i na~in: realniNiz[6] Operator . Ovaj operator se koristi za pristup ~lanovima klase. Vi{e o njemu kada se bude govorilo o klasama. Operator () Koristi se prilikom deklarisanja i poziva metoda klase. Vi{e o njemu kada se bude govorilo o klasama. Operator (tip) Vrednost se konvertuje u odre|eni tip. (double) a a se pretvara u tip double. Operator new Koristi se za kreiranje novog objekta ili niza. Integer a = new Integer(10); U ovom primeru se kreira novi objekat klase Integer. Operator instanceof Ovaj operator testira da li prvi operator predstavlja priemrak klase koja je data drugim operatorom. 12

op1 instanceof op2 op1 mora biti objekat, a op2 mora biti ime klase. Objekat je instanca klase ako je primrak ba{ te klase ili neke klase koja je iz nje izvedena. Prioritet operatora Ako se u izrazu na|e vi{e operatora oni se izvr{avaju odre|enim redosledom. U tabeli koja sledi je dat prioritet operatora. Operatori sa najvi{im prioritetom su navedeni prvi, a zatim slede oni sa ni`im prioritetom. Ako `elite da promenite prioritet operatora, treba da koristite zagrade. postfiks operatori unarni operatori

[] . (params) expr++ expr-++expr --expr +expr -expr ~ !

operatori kreiranja i kovenrzije new (type)expr mno`enje sabiranje pomeranje relacioni jednakost bitovsko I bitovsko isklju~ivo ILI bitovsko uklju~ivo ILI Logi~ko I logi~ko ILI uslovni dodela Logi~ki izrazi Osnovni element svih programa je dono{enje odluka. Morate biti u stanju da izaberete izme|u razli~itih mogu}nosti, na primer, “Ako imam para na ra~unu kupi}u nov auto, a ako nemam kupi}u mese~nu kartu za autobus.”. Programski se dono{enje odluka realizuje pomo}u relacionih operatora i odgovaraju}ih logi~kih izraza. Iskaz if Iskaz if je elementarni logi~ki izraz. Njegov najjednostavniji oblik je: if (izraz) iskaz; Izraz mo`e biti bilo koji izraz koji daje vrednost true (ta~no) ili false (neta~no). Ako je vrednost izraza true, onda se izvr{ava iskaz koji sledi, u suprotnom ne. Primer: 13
* / % + << >> >>> < > <= >= instanceof == != & ^ | && || ? : = += -= *= /= %= &= ^= |= <<= >>= >>>=

if(broj % 2 != 0) ++broj;

//proverava se da li je broj neparan //ako je neparan, neka postane paran

Ovaj iskaz se mo`e napisati i na neki drugi na~in, ali se preporu~uje ovakva forma. if(broj %2 != 0) ++broj; //ovako ne bi trebalo, mada je mogu}e Ako je potrebno da se kao rezultat iskaza if izvr{i vi{e iskaza, a ne samo jedan kao u prethodnom primeru, mogu se uporebiti viti~aste zagrade. if(izraz){ iskaz1; iskaz2; … } Primer: if(broj % 2 != 0){ //proverava se da li je broj neparan ++broj; //ako je neparan, neka postane paran System.out.println(“Broj je pretvoren u paran i njegova vrednost je sada “ + broj); } Ako je izraz ocenjen kao ta~an, izvr{avaju se svi iskazi izme|u viti~astih zagrada, a ako nije, ne izvr{ava se nijedan. Klauzula else Osnovni iskaz if mo`e da se pro{iri klauzulom else. if(izraz) iskaz1; else iskaz2; Iskaz ili iskazi koji slede iza klauzule elese se izvr{avaju samo u slu~aju da izraz u klauzuli if nije ta~an. Ako je potrebno da se u klauzuli else izvr{i vi{e iskaza tako|e se mogu uporebiti viti~aste zagrade. if(izraz){ iskaz1; … }else{ iskaz2; … } Klauzula else if Ukoliko prilikom dono{enja oluke postoji vi{e mogu}nosti, mo`e se upotrebiti klauzula else if. if(izraz1) iskaz1; else if(izraz2) iskaz2; else if(izraz3) iskaz3; else iskaz4;

14

Ako je vrednost izraza izraz1 ocenjena kao ta~na, izvr{ava se iskaz1. Ako izraz nema vrednost true, proverava se vrednost izraza izraz2. Ako je njegova vrednost ta~na, izvr{ava se iskaz iskaz2. Posle izvr{enja iskaza iskaz2 program se nastavlja kodom koji sledi iza celog iskaza if. Ako vrednost izraza izraz2 nije true, proverava se vrednost izraza izraz3 itd. Ako nijedan od izraza u klauzulama else if nije ocenjen kao ta~an (true), izvr{ava se iskaz (iskazi) iza klauzule else, ako ona postoji. Primer:
public class IfElseDemo { public static void main(String[] args) { int rezultatTesta = 76; char ocena; if (rezultatTesta >= 90) { ocena = 'A'; } else if (rezultatTesta >= 80) { ocena = 'B'; } else if (rezultatTesta >= 70) { ocena = 'C'; } else if (rezultatTesta >= 60) { ocena = 'D'; } else { ocena = 'F'; } System.out.println("Ocena = " + ocena); } }

Izlaz iz programa je: Ocena = C; Kao {to vidite vrednost promenljive rezultatTesta mo`e da zadovolji vi{e od jednog uslova, jer je 76 >= 70, a tako|e je i rezultatTesta >= 60. Ocena je ipak C, zato {to se izvr{ava samo prvi blok koda koji pripada izrazu rezultatTesta >= 70. Kada se izvr{i taj blok, kontrola programa prelazi na kod iza iskaza if, u ovom slu~aju na iskaz System.out… Izrazi koji slede iza izraza koji je bio zadovoljen se ne proveravaju, a samim tim se i ne izvr{ava pripadaju}i kod. Iskazi if mogu biti ugne`deni. U okviru jednog if iskaza mo`e da se na|e drugi, u okviru tog drugog, tre}i itd. Evo kako to izgleda: if(izraz1){ if(izraz1-1){ if(izraz1-1-1) iskaz1-1-1; }else iskaz1-1; } Iskaz switch Ovaj iskaz se koristi za uslovno izvr{avanje iskaza na bazi vrednosti celobrojnog izraza. U primeru koji sledi je upotrebljen iskaz switch koji na osnovu celobrojne vrednosti mesec {tampa ime meseca, na koji promenljiva ukazuje.
public class SwitchDemo { public static void main(String[] args) { int mesec = 8; switch (mesec) { case 1: System.out.println("Januar"); break; case 2: System.out.println("Februar"); break;

15

case case case case case case case case case case } } }

3: 4: 5: 6: 7: 8: 9: 10: 11: 12:

System.out.println("Mart"); break; System.out.println("April"); break; System.out.println("Maj"); break; System.out.println("Jun"); break; System.out.println("Jul"); break; System.out.println("Avgust"); break; System.out.println("Septembar"); break; System.out.println("Oktobar"); break; System.out.println("Novembar"); break; System.out.println("Decembar"); break;

Rezultat ovog programa je Avgust. Isti efekat se mogao posti}i i pomo}u iskaza if:
int mesec = 8; if (mesec == 1) { System.out.println("Januar"); } else if (month == 2) { System.out.println("Februar"); } …… itd.

Stvar je li~nog izbora koji }ete od ovih metoda koristiti. Prilikom dono{enja odluke treba imati u vidu iskaz switch odluku mo`e da donese samo na osnovu celobrojne vrednosti, dok se u iskazu if mogu da koriste razli~iti uslovi. Verovatno ste u prethodnom kodu primetili prisustvo iskaza break. Ovaj iskaz se naj~e{}e koristi zajedno sa iskazom switch, jer se bez njega kontrola toka programa, nakon izvr{enja pravog iskaza, prenosi na slede}i iskaz u switch bloku. Ako se doda iskaz break, onda se kontrola toka, nakon {to se izvr{i pravi iskaz, prenosi na kod koji sledi iza iskaza switch. Na~in kontrole toka programa u iskazu switch (bez iskaza break) mo`e ponekad i da bude od koristi. Evo primera u kome smo to iskoristili:
public class SwitchDemo2 { public static void main(String[] args) { int mesec = 2; int godina = 2000; int brojDana = 0; switch (mesec) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: brojDana = 31; break; case 4: case 6: case 9: case 11: brojDana = 30; break; case 2: if ( ((godina % 4 == 0) && !(godina % 100 == 0)) || (godina % 400 == 0) ) brojDana = 29; else brojDana = 28; break;

16

} System.out.println("Broj dana je " + brojDana); } }

Izlaz iz programa je:
Broj dana je 29

Ovaj program izra~unava broj dana u mesecu za zadatu godinu i mesec. Kao {to vidite svi meseci koji imaju 31 dan su bez iskaza break, koji postoji samo kod poslednjeg u nizu. Isto va`i i za mesec koji imaju 30 dana (i oni su grupisani i postoji samo jedan iskaz break). Ako `elite da se neki iskazi izvr{e u slu~aju da nijedan od case iskaza nije zadovoljen, mo`ete da upotrebite klauzulu default. Iskazi koji slede iza ove klauzule se izvr{avaju ako nijedan slu~aj (case) nije zadovoljen. Evo kako izgleda prepravljen program iz prvog primera, sada sa dodatom klauzulom default:
public class SwitchDemo { public static void main(String[] args) { int mesec = 8; switch (mesec) { case 1: System.out.println("Januar"); break; case 2: System.out.println("Februar"); break; case 3: System.out.println("Mart"); break; case 4: System.out.println("April"); break; case 5: System.out.println("Maj"); break; case 6: System.out.println("Jun"); break; case 7: System.out.println("Jul"); break; case 8: System.out.println("Avgust"); break; case 9: System.out.println("Septembar"); break; case 10: System.out.println("Oktobar"); break; case 11: System.out.println("Novembar"); break; case 12: System.out.println("Decembar"); break; default: System.out.println("Niste uneli ispravan broj za mesec");break; } } }

Petlje Petlje se koriste za izvr{avanje dela koda koji se ponavlja. U Javi postoje tri vrste petlji: while, do while i for. Petlja while Ova petlja se koristi za ponovljeno izvr{avanje bloka iskaza sve dok je uslov ta~an. Evo kako izgleda ta petlja: while(izraz){ iskazi.. } Prvo se izra~unava vrednost izraza. Ta vrednost mora biti tipa boolean. Ako je vrednost izraza true (ta~no), izvr{avaju se iskazi koji pripadaju petlji. Posle izvr{avanja iskaza, ponovo se proverava vrednost izraza, i ako je ta vrednost true, ponovo se izvr{avaju iskazi. Ovo se ponavlja sve dok je vrednost izraza ocenjena kao ta~na (true). U primeru koji sledi se pomo}u petlje while ide kroz string. Ovo se ponavlja sve dok se ne nai|e na karakter g. Svaki karakter koji nije g se dodaje u objekat StringBuffer. Na kraju se rezultuju}i string {tampa.
public class WhileDemo {

17

public static void main(String[] args) { String kopirajOdMene = "Kopiraj ovaj string sve dok se ne " + " dodje do slova 'g'."; StringBuffer kopirajUMene = new StringBuffer(); int i = 0; char c = kopirajOdMene.charAt(i); while (c != 'g') { kopirajUMene.append(c); c = kopirajOdMene.charAt(++i); } System.out.println(kopirajUMene); } }

Izlaz iz ovog programa je: Kopiraj ovaj strin Petlja do-while Ova petlja je sli~na sa petljom while. Sintaksa za petlju do-while je: do{ iskazi.. }while(izraz); Razlika u odnosu na petlju while je u tome da se kod petlje while uvek prvo proveri vrednost izraza, pa se tek u zavisnosti od rezultata izvr{ava telo petlje. Kod petlje do-while se telo petlje uvek izvr{ava makar jednom, a tek posle prvog izvr{enja se proverava vrednost izraza. Evo kako izgleda prethodni primer, ali sa petljom do-while:
public class DoWhileDemo { public static void main(String[] args) { String kopirajOdMene = "Kopiraj ovaj string sve dok se ne " + " dodje do slova 'g'."; StringBuffer kopirajUMene = new StringBuffer(); int i = 0; char c = kopirajOdMene.charAt(i); do { kopirajUMene.append(c); c = kopirajOdMene.charAt(++i); } while (c != 'g'); System.out.println(kopirajUMene); } }

Petlja for Op{ti oblik ove petlje je: for(inicijalizacija; uslov_petlje; izraz petlje){ iskazi… } Deo ozna~en sa inicijalizacija se izvr{ava jednom pre pokretanja petlje. Tu se obi~no inicijalizuje broja~ petlje. Izvr{avanje petlje se nastavlja sve dok se uslov_petlje izra~unava kao ta~an. Ovaj izraz se proverava na po~etku svakog izvr{enja petlje. Kada njegova vrednost bude false (neta~no), 18

program se nastavlja kodom koji sledi iza petlje. Izraz ozna~en sa izraz_petlje se izvr{ava na kraju petlje. Obi~no se tu pove}ava ili smanjuje broja~ petlje za neku zadatu vrednost. Primer:
Public class ForPetlja{ public static void main (String[] args){ int limit = 20; // Trazi se suma od 1 do ove vrednosti int sum = 0; // vrednost sume for(int i = 1; i <= limit’ i++) sum += i; System.out.println(“suma = “ + sum); } }

Broja~ petlje mo`e biti i realan broj. Petlje mogu da se ugne`davaju. Prvo se izvr{ava unutra{nja petlja, pa tek onda spolja{nja. Iskazi continue i break kao delovi petlje Ako `elite da se u nekom prolazu kroz petlju presko~i neki njen deo i da se izvr{enje nastavi od po~etka petlje, mo`ete upotrebiti iskaz continue. Primer: for(int i = 1; i <= limit’ i++){ if(i % 3 == 0) continue; // preskace se ostatak iteracije sum += i; } Iskaz break se mo`e upotrebiti za trenutni prekid petlje. Program se iskazom break nastavlja kodom koji sledi iza petlje. Sledi primer u kome se pronalaze prosti brojevi. Prost broj je onaj koji nije deljiv bez ostatka ni sa jednim drugim brojem (osim sa 1).
public class ProstiBrojevi{ public static void main (String[] args){ int nVrednost = 50; // maksimalna vrednost koja se proverava boolean prostBroj = true; // tacno ako je prost broj // provera svih vrednosti od 2 do nVrednost for(int i = 2; i <= nVrednost; i++){ prostBroj = true; // pretpostavka da je trenutna vrednost prost broj for(int j = 2; j < i; j++){ if(i % j == 0){ //tacno ako j deli bez ostatka prostBroj = false; // ako smo dospeli do ovde, postojalo je deljenje bez ostatka, sto znaci da nije prost broj break; } } // ispisivanje prostih brojeva if(prostBroj) // da li je to prost broj System.out.println(i); // u pitanju je prost broj pa se ispisuje } } }

Ispisuju se prosti brojevi od 1 do nVrednost (u ovom slu~aju 50). Spolja{nja petlja ide kroz sve brojeve koje treba proveriti. Broja~ te petlje je i. Za svako i, unutra{nja petlja proverava da li postoji neki broj sa kojim se to i mo`e da podeli bez ostatka. Ako mo`e, to zna~i da nije u pitanju prost broj i da treba napustiti unutra{nju petlju (za to slu`i iskaz break). Na kraju se svi prona|eni prosti brojevi {tampaju.

19

Nizovi i stringovi Niz je struktura podataka koja se sastoji od zadatog broja stavki, pri ~emu su sve stavke (elementi) istog tipa. ^lanovi niza se u Javi uvek numeri{u po~ev od 0. Jedan niz, na primer, mo`e da sadr`i 100 celobrojnih vrednosti, koje su numerisane od 0 do 99. Niz se deklari{e na slede}i na~in: int[] niz; Ovo je deklaracija niza. U ovom trenutku niz jo{ uvek nema dodeljenu memoriju. U trenutku kreiranja niza se defini{e njegova du`ina i dodeljuje se potrebna memorija. Nizovi u Javi su objekti pa se u skladu sa time kreiraju pomo}u operatora new. Iskaz koji sledi zauzima dovoljno memorije za niz od deset celobrojnih vrednosti i zatim taj niz dodeljuje promenljivoj niz, koju smo ranije deklarisali. niz = new int[10]; Pristup elementima niza Elementima niza se pristupa preko imena niza, iza kojeg u uglastim zagradama sledi indeks elementa, kome se pristupa. Na primer, iskaz niz[4] pristupa petom elementu niza. Java proverava da li element niza kome pristupate postoji. Ako poku{ate da pristupite nepostoje}em elementu niza javi}e se izuzetak tipa IndexOutOfBoundsException. Veli~ina (du`ina) niza Veli~inu niza }ete dobiti na slede}i na~in: imeNiza.length Sledi primer koji pokazuje kako se pristupa elementima niza i kako se odre|uje njegova veli~ina.
for (int i = 0; i < niz.length; i++) { niz[i] = i; System.out.print(niz[i] + " "); }

Inicijalizacija nizova Elementima niza se mogu odmah u toku definisanja dodeliti vrednosti. Evo kako se to radi:
boolean[] answers = { true, false, true, true, false };

Veli~ina niza je u ovom slu~aju odre|ena brojem elemenata. Ako zadajete inicijalne vrednosti niza, morate da ih zadate za sve elemente. U primeru koji sledi je pokazano kako se odre|uje element niza sa najve}om vredno{}u.
public class MaxNiz{ public static void main (String[] args){

double[] A = {2., 5., 3., 12.5, 5.3, 17.5}; double max = A[0]; for (int i = 1; i < A.length; i++) { if (A[i] > max) max = A[i]; } System.out.println("Maksimum je " + max);
} }

20

Kopiranje niza Kopiranje niza se vr{i tako {to se u novi niz kopira svaki novi element niza zasebno. Iskazi:
double [] A = {1.,4..6.}; double [] B = A;

ne dovode do kopiranja niza A u niz B. U ovom slu~aju je samo napravljena nova promenljiva B, koja ukazuje na isti niz kao i promenljiva A. Ako se `eli kopiranje treba napisati:
double[] B = new double[A.length]; //Pravi se novi niz, iste velicine kao A for (int i = 0; i < A.length; i++) B[i] = A[i]; // Kopira se svaki element iz A u B.

Vi{edimenzionalni nizovi Niz kao elemente mo`e da ima druge nizove. Pretpostavimo da `elite da pratite vremenske prilike na 10 razli~Itih geografskih lokacija, tokom jedne godine. Ho}ete da merite temperaturu na svakoj od ovih lokacija u toku svakog dana u godini. Ovo mo`ete da ostvarite pomo}u niza od 10 elemenata, ~iji je svaki element drugi niz od 365 ~lanova. Ovakav niz bi se deklarisao na slede}i na~in: float [] [] temperatura = new float [10] [365]; Ovaj niz ima dve dimenzije, pa je zna~i u pitanju dvodimenzionalan niz. Prva dimenzija se kre}e od 0 do 9 i odnosi se na geografsku lokaciju, a druga se kre}e od 0 do 364 i odnosi se na temperature. Ako `elite da uka`ete na temperaturu u toku stotog dana na {estoj lokaciji mo`ete da napi{ete: temperatura [5] [99] U primeru koji sledi }emo vrednosti za temperaturu generisati po slu~ajnom principu. Uzima}emo nasumi~ne vrednosti izme|u -10 i +35 stepeni Celzijusa.
public class Vreme { public static void main(String[] args) { float[][] temperatura = new float[10][365]; // generisanje temperature for(int i = 0; i < temperatura.length; i++) for(int j = 0; j < temperatura[i].length; j++) temperatura [i][j] = (float) (45.0 * Math.random() - 10.0); //izracunavanje prosecne vrednosti za temperaturu for(int i = 0; i < temperatura.length; i++){ float prosek = 0.0f; // prosecna vrednost for(int j = 0; j < temperatura[i].length; j++) prosek += temperatura[i][j]; //prikaz prosecne temperature za trenutnu lokaciju System.out.println("Prosecna temperatura na lokaciji " + (i+1) + " je " + prosek/(float) temperatura[i].length); } } }

Nizovi nizova promenljive du`ine Kada su elementi jednog niza drugi nizovi, oni ne moraju biti iste du`ine. Niz se mo`e deklarisati na slede}i na~in:
float primer [] [];

Ovim se deklari{e niz primer tipa float. Broj elemenata u prvoj dimenziji se mo`e zadti izrazom:
primer = new float [6] []; // definicija sest elemenata, od kojih je svaki niz

21

Sada imamo dodeljenih {est elemenata od kojih svaki mo`e da sadr`i jednodimenzionalni niz. Ti nizovi se dalje mogu definisati pojedina~no:
primer[2] = new float [6]; primer[5] = new float[10];

Ukoliko bismo hteli da niz primer ima trougaoni oblik, odnosno da prvi element bude niz sa jednim elementom, drugi niz sa dva elementa, tre}i niz sa tri elementa itd., mogli biste da napi{ete: for(int i = 0; i < primer.length; i++) primer[i] = new float[i+1]; Niste ograni~eni na dve dimenzije. Niz mo`e da ima i vi{e dimenzija. Na primer niz sa tri dimenzije se mo`e deklarisati na slede}i na~in: int [] [] [] triDim= new int[3] [] []; // tri dvodimenzionalna niza Svaki od ova tri elementa u prvoj dimenziji niza mo`e da sadr`i razli~it dvodimenzionalni niz, tako da mo`ete da napi{ete: triDim[0] = new int[4] []; triDim[1] = new int[2] []; triDim[2] = new int[5] []; Dalje bismo mogli da napi{emo: triDim[0][1] = new int[3]; //itd Nizovi karaktera Nizovi koje smo dosada pominjali su bili numeri~ki nizovi. Mnogo ~e{}e od numeri~kih nizova }ete koristiti nizove znakova (karaktera). Mo`ete na primer, da deklari{ete promenljivu niza tipa char, sa 50 ~lanova:
char[] poruka = new char[50];

Sa nizovima karaktera se obi~no ne radi preko ovakvih nizova. U Javi postoji posebna klasa koja se koristi specijalno za rad sa karakterima. To je klasa String. U pitanju je standardna klasa koja dolazi zajedno sa Javom. String literali Do sada smo ve} vi{e puta koristili String literale. Skoro svaki put kada smo koristili iskaz println, kao argument smo koristili i string literal. String literal je bilo koja vrednost napisana izme|u dvostrukih navodnika: “Ovo je string literal” Ovo je konstantan objekat klase String, koji kompajler pravi za upotrebu u programu. Ako u okviru Stringa `elite da ubacite i neki specijalni karakter, kao {to je znak za novi red, ili tabulator morate da koristite escape sekvencu. Iskaz System.out.println(“Ovo je \n String konstanta”); Dodaje novi red kod {tampanja. Znak \n je oznaka za novi red. Ovaj kod daje slede}i izlaz: Ovo je String konstanta

22

Objekti tipa string Promenljiva tipa String je u stvari objekat klase String. Ova promenljiva se deklari{e sli~no kao i ostale promenljive osnovnih tipova. Ako je potrebno ova promenjiva se mo`e inicijalizovati odmah prilikom deklaracije: String mojString = “Moj prvi string”; Promenljiva mojString sadr`i referencu na deo memorije u kome se ~uva sam string. Mo`ete da napi{ete: mojString = “Ovo je drugi string”; Promenljiva mojString sada ukazuje na drugi deo memorije, sa drugim stringom, a prvi se odbacuje. Objekti klase String su nepromenljivi. Ako `elite da promenite sadr`aj stringa morate da odbacite staru referencu i da napravite novu. O izbacivanju starog stringa brine sama Java preko skuplja~a otpada. To je mehanizam koji objekte i promenljive koji vi{e nisu potrebni, posle izvesnog vremena izbacuje iz memorije. Promenljiva tipa string mo`e da se inicijalizuje i na null vrednost. Iskaz String mojString = null; deklari{e promenljivu mojString koja ne ukazuje ni na jedan string. Dobra programerska praksa je da stringove kojima `elite da vrednost dodelite kasnije, uvek inicijalizujete na ovaj na~in. Operacije nad stringovima Spajanje stringova Spajanje dva stringa se mo`e ostvariti putem operatora +. mojString = “Prvi string se spaja “ + “ sa drugim”; Operacijom spajanja stringova preko operatora + se pravi potpuno novi objekat tipa String koji je nezavisan od operanada. Na taj novi objekat ukazuje promenljiva mojString. Za spajanje stringova mo`ete da upotrebite i operator +=: String fraza = “Spajanje je “ ; fraza += “moguce izvrsiti i ovako”; Ovim se ne menja string “Spajanje je “. String na koji promenljiva fraza ukazuje posle nakon izvr{enja drugog iskaza je potpuno novi objekat. Primer:
public class StringProba { public static void main(String[] args) { String prviString = "Puno "; String drugiString = "ruku "; String treciString = "olaksavaju posao"; String mojString; // promenljiva za smestaj rezultata mojString = prviString + drugiString + treciString; System.out.println(mojString); // konverzija celih brojeva u string i spajanje sa dva stringa int brojRuku = 99; mojString = brojRuku + " " + drugiString + treciString; System.out.println(mojString); //kombinacija stringa i celih brojeva mojString = "pedeset pet je " + 5 + 5; System.out.println(mojString);

23

// kombinacija celih brojeva i stringa mojString = 5 + 5 + " je deset"; System.out.println(mojString); } }

Prvo spajanje je jednostavno i spaja tri stringa. Tri promenljive prviString, drugiString i treciString se spajaju i sme{taju u ~etvrtoj promenljivoj mojString. Drugo spajanje stringova se odnosi na spajanje celog broja 99 i stringa “ “. Ovde pre samog spajanja dolazi do konverzije numeri~ke vrednosti brojRuku u String, nakon ~ega se to spaja sa stringom “ “. Razlog je u tome {to je operator + levo asocijativan, pa se parovi kod spajanja uskla|uju sa leve strane. Ovo je bitno kod slede}a dva spajanja. Iskazi izgledaju sli~no, ali u jednom slu~aju 5 + 5 daje 55, a u drugom 10. Razlika je u tome da kod prvog iskaza prilikom sabiranja uvek postoji makar jedan operand tipa string, tako da se uvek radi o spajanju stringova. U drugom iskazu je prva operacija matemati~ko sabiranje, a rezultat se konvertuje u String da bi se omogu}ilo spajanje sa literalom “je 10”. Pore|enje stringova Osnovni tipovi se porede pomo}u operatora ==. Za objekte tipa String (ili bilo koje druge objekte) ovo ne va`i. Iskaz string1 == string2 }e proveriti da li ove dve promenljive ukazuju na isti string. Ako referenciraju (ukazuju) na razli~Ite stringove, bez obzira na to da li je sadr`aj tih stringova identi~an, ovaj iskaz vra}a false (neta~no). Drugim re~ima, ovaj iskaz ne poredi same stringove, ve} reference na stringove. Primer:
public class PoredjenjeStringova { public static void main(String[] args) { String string1 = "Suvise " ; String string2 = "kolacica"; String string3 = "Suvise kolacica"; string1 += string2; System.out.println("Test 1"); System.out.println("string3 je sada: " + string3); System.out.println("string1 je sada: " + string1); if(string1 == string3){ System.out.println("string1 == string3 je tacno " + "string1 i string3 referenciraju na isti string"); }else{ System.out.println("string1 == string3 je netacno " + "string1 i string3 ne referenciraju isti string"); } // sada string1 i string3 referenciraju na iste stringove string3 = string1; System.out.println("Test 2"); System.out.println("string3 je sada: " + string3); System.out.println("string1 je sada: " + string1); if(string1 == string3){ System.out.println("string1 == string3 je tacno " + "string1 i string3 referenciraju na isti string"); }else{

24

System.out.println("string1 == string3 je netacno " + "string1 i string3 ne referenciraju isti string"); } } }

Na po~etku su definisane i inicijalizovane tri promenljive tipa String. Nakon iskaza dodele sadr`aj promenljivih string1 i string3 }e biti identi~an, ali pore|enje po jednakosti ipak vra}a false, po{to promenljive ukazuju na dva razli~ita stringa. Nakon toga smo promenili promenljivu string3, tako da ukazuje na isti objekat kao i string1. U tom slu~aju iskaz if se ocenjuje kao ta~an, po{to string1 i string3 ukazuju na isti objekat. Ako `elite da uporedite dve promenljive tipa String i da utvrdite da li je njihov sadr`aj identi~an, koristi}ete metod equal, klase String. Ovaj metod poredi stringove sa pravljenjem razlike izme|u malih i velikih slova. Dva stringa su jednaka ako su iste du`ine, ako imaju isti broj znakova i ako je svaki znak u jednom stringu identi~an odgovaraju}em znaku u drugom. Ako ne `elite da se pravi razlika izme|u malih i velikih slova, mo`ete da koristite metod equalIgnoreCase(). Primer:
public class PoredjenjeStringova1 { public static void main(String[] args) { String string1 = "Suvise " ; String string2 = "kolacica"; String string3 = "Suvise kolacica"; string1 += string2; System.out.println("Test 1"); System.out.println("string3 je sada: " + string3); System.out.println("string1 je sada: " + string1); if(string1.equals(string3)){ System.out.println("string1.equals(string3) string3 su jednaki"); }else{ System.out.println("string1.equals(string3) string3 nisu jednaki"); } // razlikuje se velicina slova string3 = "SUVISE kolacica"; System.out.println("Test 2"); System.out.println("string3 je sada: " + string3); System.out.println("string1 je sada: " + string1); if(string1.equals(string3)){ System.out.println("string1.equals(string3) je tacno " + "string1 string3 su jednaki"); }else{ System.out.println("string1.equals(string3) je netacno " + "string1 string3 nisu jednaki"); }

je

tacno

"

+

"string1

i

je

netacno

"

+

"string1

i

i

i

if(string1.equalsIgnoreCase(string3)){// poredjenje uz zanemarivanje malih i velikih slova System.out.println("string1.equalsIgnoreCase(string3) je tacno " + "string1 i string3 su jednaki, ali ako se ne pravi razlika izmedju malih i velikih slova"); }else{ System.out.println("string1equalsIgnoreCase(string3) je netacno " + "string1 i string3 nisu jednaki");

25

} } }

Pre nego {to se pozabavimo primerom objasni}emo sintaksu koja je vezana za objekte. U iskazu if smo pozvali metod equals(), objekta string1. To je ista sintaksa koju smo koristili i za poziv metode println, objekta out. Sintaksa za pozivanje metoda nekog objekta je: imeObjekta.imeMetoda(lista argumenata odvojenih zarezima) Metod equals() zahteva jedan argument, tipa String. U pitanju je string koji se poredi sa originalnim objektom. Metod vra}a true (ta~no) ako je vrednost koja mu je prosle|ena (u ovom primeru string3) identi~na sa stringom ~iji je metod equals() pozvan. Va`i i obrnuto: string3.equals(string1) pri ~emu se dobija isti rezultat. Metod equalsIgnoreCase() poredi stringove, ali se pri tome zanemaruje razlika izme|u malih i velikih slova. U skladu sa tim rezultat poslednjeg pore|enja je true (ta~no) jer se stringovi razlikuju samo po velikim i malim slovima. Po~etak i kraj stringa Metod startsWith() klase String omogu}ava proveru da li neki string po~inje odre|enom kombinacijom znakova. Ako je string1 = “Suvise kolacica”; onda iskaz string1.startsWith(“Suv”) vra}a true. Prilikom pore|enja se vodi ra~una o malim i velikim slovima, tako da iskaz string1.startsWith(“sUV”) vra}a false. Ako `elite da proverite da li se string zavr{ava nekom kombinacijom karaktera, koristi}ete metod endsWith(), klase String. Iskaz string1.endsWith(“ica”) vra}a true. I ovde se pravi razlika izme|u malih i velikih slova. Pristup pojedinim znakovima u stringu Vrlo ~esto se javlja potreba za pristupom odre|enom znaku ili znacima koji su deo stringa. Odre|enom karakteru u stringu se pristupa preko celobrojnog indeksa, koji ozna~ava poziciju znaka u stringu, ra~unaju}i od po~etka. Prvi znak u stringu je na poziciji 0, drugi na poziciji 1 itd. Po{to je String objekat, to se i karakterima koji ga ~ine pristupa preko odre|enog metoda. U pitanju je metod charAt(). Ovaj metod prihvata argument koji predstavlja poziciju karaktera u stringu, odnosno indeks. Ako poku{ate da upotrebite indeks koji je manji od 0 ili ve}i od du`ine niza, desi}e se gre{ka u programu. Da bi se izbegle gre{ke ovakvog tipa potrebno je poznavati du`inu stringa. U tu svrhu se koristi metod length() objekta tipa String. U primeru koji sledi je dat program koji analizira odre|eni tekst i odre|uje broj samoglasnika, razmaka i slova koji ga ~ine. Primer:
public class KarakteriStringa { public static void main(String[] args) { // string koji se analizira

26

String tekst = "Ovo je tekst koji sluzi za vezbu prilikom pristupanja elementima stringa."; int razmaci = 0, samoglasnici = 0, slova = 0;// broj razmaka, samoglasnika i slova u tekstu int duzinaTeksta = tekst.length(); for (int i = 0; i < duzinaTeksta; i++){ char ch = Character.toLowerCase(tekst.charAt(i)); // provera da li je samoglasnik if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') samoglasnici++; // provera da li je slovo if(Character.isLetter(ch)) slova++; // provera da li je razmak if(Character.isWhitespace(ch)) razmaci++; } System.out.println("Tekst sadrzi: samoglasnika - " + samoglasnici + "\n" + " suglasnika - " +(slova-samoglasnici) + "\n" + " razmaka - " + razmaci); } }

Metod charAt(i) se koristi za odre|ivanje znaka na i-oj poziciji u stringu. Karakter koji se dobija se pretvara u malo slovo, radi lak{eg ispitivanja da li je u pitanju samoglasnik. Karakter se u pretvara u malo slovo pomo}u metoda toLowerCase() klase Character. Ovo je klasa koja je u Javi unapred definisana i slu`i za rad sa karakterima. Kasnije se u kodu pomo}u metoda isLetter(), klase Character, proverava da li je u pitanju slovo i pomo}u metoda isWhiteSpace() iste klase, da li je u pitanju razmak (blanko karakter). Ako `elite da ceo string pretvorite u mala ili velika slova mo`ete uporebiti metode toLowerCase() i toUpperCase(), klase String. U tom slu~aju se ceo string pretvara u tekst sa samo malim, odnosno samo velikim slovima.
String tekst = “Ovo su me{ovita slova?”; String tekstMala = tekst.toLowerCase(); // ovo su samo mala slova String testVelika = tekst.toUpperCase(); // ovo su samo velika slova

Pretra`ivanje stringova u potrazi za odre|enim karakterima Ako `elite da u okviru stringa prona|ete odre|eni karakter koristi}ete metode indexOf() i lastIndexOf(), koji pripadaju klasu String.
int indeks = 0; indeks = tekst.indexOf(‘a’);

U prethodnom iskazu se pretra`uje sadr`aj stringa tekst i to po~ev{i od po~etka. Vra}a se pozicija indeksa prvog karaktera ‘a’ na koji se nai|e. Ako slovo ‘a’ ne postoji u stringu, vrati}e se -1. Oba pomenuta metoda vra}aju ili indeks pojavljivanja karaktera koji se tra`i ili -1, ako karakter nije prona|en. Zato je va`no da se uvek proverava da li je vrednost koju vra}aju -1 i da se u zavisnosti od toga izvr{avaju dalje akcije. Ako `elite da prona|ete poslednje pojavljivanje karaktera ‘a’ u nizu tekst napisa}ete:
indeks = tekst.lastIndexOf(‘a’);

Ako `elite da prona|ete poziciju znaka koji nije ni na po~etku ni na kraju, mo`ete da koristite varijaciju ovih metoda. U ovom slu~aju se metodima {alju dva argumenta. Pored karaktera koji se tra`i, zadaje se i pozicija od koje treba da se tra`i. indeks = tekst.index(‘a’, startIndeks); 27

Ovde se tra`i karakter koji je zadat kao prvi argument, ali po~ev od pozicije koja je zadata kao drugi argument. U primeru koji sledi se pronalazi prvo pojavljivanje karaktera ‘b’, ali iza prvog pojavljivanja karaktera ‘a’.
int aIndeks = -1; int bIndeks = -1; aIndeks = tekstIndexOf(‘a’); if(aIndeks >= 0) bIndeks = tekst.indexOf(‘b’, ++aIndeks);

Ako napi{ete indeks = tekst.lastIndexOf(‘b’, aIndeks); onda tra`ite poslednje pojavljivanje karaktera ‘b’ u stringu tekst, ali po~ev od indeksa aIndeks. Pretra`ivanje stringova u potrazi za odre|enim potstringovima Postoje i verzije metoda indexOf() i lastIndexOf() koje kao argumente prihvataju znakovni podniz. U tom slu~aju se tra`i ceo zadati podniz, a ne samo jedan karakter. U svemu ostalom ovi metodi rade potpuno isto kao verzije koje smo pomenuli u prethodnom odeljku. indeks = tekst.indexOf(“ovo je”); U ovom slu~aju se vra}a pozicija prvog pojavljivanja podstringa “ovo je” u okviru stringa tekst. U primeru koji sledi se pretra`uje zadati string u potrazi za svim pojavljivanjima zadatog podstringa. Vra}a se broj pojavljivanja podstringa u okviru glavnog stringa. Primer:
public class PodstringoviStringa { public static void main(String[] args) { // string koji se analizira String tekst = "Ovo je string koji sluzi za probu. " + "U njemu treba proveriti koliko puta se pojavljuje kombinacija 'je'"; int brojac = 0;// broj pojavljivanja int indeks = -1; // trenutna pozicija indeksa String pod = "je"; pretraga unapred po je indeks = tekst.indexOf(pod); while(indeks >= 0){ brojac++; indeks += pod.length(); // prelaz na poziciju iza poslednjeg slova prvog pojavljivanja podstringa indeks = tekst.indexOf(pod, indeks); } System.out.println("Kombinacija je se u nizu pojavljuje " + brojac + " puta"); } } //

Preraditi program, tako da se pretra`ivanje vr{i unazad, pomo}u metoda lastIndexOf(). Izdvajanje podstringova iz zadatog stringa U klasi String postoji metod substring() koji iz niza izdvaja zadati podstring. Postoje dve verzije ovog metoda. Jedna iz zadatog stringa vadi podstring, po~ev od zadate pozicije, a kod druge treba zadati po~etnu i krajnju poziciju. String grad = “Novi Sad”; String poslednjaRec = mesto.substring(5); String poslednjaRec nakon izvr{enja ovog iskaza sadr`i tekst “Sad”. Brojanje indeksa po~inje od 0, a u novom podstringu se nalazi i karakter sa te po~etne pozicije. 28

Druga verzija ovog metoda tra`i dva argumenta. String segment = mesto.substring(3,6); String segment posle izvr{enja ovog iskaza sadr`i tekst “i S”. Podstring se zavr{ava na jednoj poziciji ispred indeksa koji je zadat kao kraj (6-1=5). Za razliku od metoda indexOf() kod koje zadavanje indeksa koji je izvan dozvoljenog opsega vra}a -1, kod metoda substring, zadavanje indeksa koji je van granica samog stringa, dovodi do pojave gre{ke. U primeru koji sledi se pomo}u metoda indexOf() i substring() zadati tekst razdvaja na pojedine re~i. Primer:
public class SubstringPrimer { public static void main(String[] args) { String tekst = "Ovo je string koji sluzi za probu. " + "U njemu treba izdvojiti pojedine reci"; int count = 0; char separator = ' '; //odredjivanje broja podnizova int indeks = 0; do{ ++count; ++indeks; // pomera se na mesto iza poslednje pozicije indeks = tekst.indexOf(separator, indeks); }while(indeks != -1); //izdvajanje podnizova u niz String[] subStr = new String[count];// dimenzija odre\ena indeks = 0; int endIndeks = 0; for(int i = 0; i < count; i++){ endIndeks = tekst.indexOf(separator, indeks);

niza

je

prethodno

if(endIndeks == -1) //ako ne postoji znak separator subStr[i] = tekst.substring(indeks); // izdvaja se do kraja else // ako postoji separator subStr[i] = tekst.substring(indeks, endIndeks); indeks = endIndeks + 1; // pocetak za sledeci ciklus } // prikaz podnizova, odnosno reci for(int i = 0; i < subStr.length; i++){ System.out.println(subStr[i]); } } }

U prvom delu programa smo izbrojili broj reci u zadatom stringu i taj broj kasnije upotrebili za definisanje niza. U drugom delu smo, pomo}u metoda substring, vadili iz stringa jednu po jednu re~. Objekti klase StringBuffer Objekti klase String se ne mogu menjati. Ako se `eli da izvede spajanje stringova, da se postoje}i string pro{iri ili skrati i sl., treba koristiti klasu StringBuffer. Ove operacije se mogu izvesti i pomo}u klase String, ali je zbog nepromenljivosti ovih objekata cena ve}a. Ve}a cena se ogleda u sporijem radu i ve}em zauzimanju memorije. 29

Objekat klase StringBuffer se mo`e napraviti na slede}i na~in: StringBuffer primer = new StringBuffer(“String za inicijalizaciju”); Prethodni iskaz kreira objekat klase StringBuffer i inicijalizuje ga stringom “String za inicijalizaciju”. Objekat StringBuffer se mora kreirati uz pomo} klju~ne re~i new. Mogu}e je napisati i slede}e: StringBuffer mojString = null; mojString = new StringBuffer(“Novi string”); Kapacitet objekata StringBuffer Objekti klase String imaju dodeljeno onoliko memorije koliko je potrebno za sme{tanje karaktera koji se nalaze u tom stringu. Memorija dodeljena ovom objektu se vi{e ne mo`e menjati. Za razliku od ovog, memorija koju zauzima objekat klase StringBuffer se mo`e menjati. Kada se objekat StringBuffer pravi na osnovu postoje}eg stringa, njegov kapacitet je za 16 ve}i du`ine stringa. Kapacitet se ovde izra`ava u karakterima koji mogu da stanu u taj objekat. Kapacitet objekta StringBuffer nije fiksan. Prilikom kreiranja ovog objekta mo`ete da eksplicitno zadate njegov kapacitet: StringBuffer buf = new StringBuffer(50); Ovaj objekat mo`e da uskladi{ti 50 znakova. Ako se prilikom deklaracije izostavi kapacitet, onda se koristi podrazumevani kapacitet od 16 znakova. Ne treba brinuti o tome da li objekat StringBuffer ima dovoljan kapacitet da primi va{ string, jer se njegov kapacitet automatski prilago|ava veli~ini stringa koji u njega treba da se smesti. Sa druge strane kapacitet objekta StringBuffer je bitan jer uti~e na upotrebu resursa koji se koriste za skladi{tenje i modifikaciju stringova. Ako je po~etni kapacitet suvi{e mali i ako `elite da tu ubacite neki ve}i string, onda mora da se zauzme dodatna memorija (da se pove}a kapacite objekta StringBuffer), {to se odra`ava na produ`eno vreme procesa. Efikasnije je, ako je mogu}e, da se kapacitet objekta unapred podesi na dovoljnu vrednost, tako da kasnije nisu potrebne promene. Dodavanje u objekat klase StringBuffer Ako `elite da ne{to dodate na kraj postoje}eg objekta klase StringBuffer koristi}ete metod append.
StringBuffer buf = new StringBuffer(“Novi bufer”); buf.append(“ ovo je dodatak”);

U objektu se nakon ovog nalazi tekst “Novi buffer ovo je dodatak”. Metod append vra}a pro{ireni objekat StringBuffer. Postoje razli~ite varijacije metoda append, koje omogu}avaju da se u objekat dodaju i drugi osnovni tipovi. Na primer, iskazi
StringBuffer buf = new StringBuffer(“Proba “); buf.append(2.3);

u objekat buf dodaju tekst 2.3. Argument koji se prosle|uje metodu je tipa double, ali se on pre dodavanja pretvara u string i kao takav se dodaje. Sli~ni metodi postoje i za ostale osnovne tipove (int, char, boolean). Po{to metod append vra}a isti objekat StringBuffer, to je mogu}e koristiti i slede}i iskaz: buf.append(“dodatak “).append(2.13).append(“ i ovo je dodatak”); Umetanje stringova u objekat klase StringBuffer Metod append koji smo pomenuli se koristi za dodavanje sadr`aja na kraj bafera. Postoji mogu}nost da se novi sadr`aj ubaci i negde u sredinu postoje}eg objekta klase StringBuffer. U tu svrhu se 30

koristi metod insert, klase StringBuffer. Na primer ako se u baferu buf, nalazi tekst “Ovo je bafer” i ako izvr{ite iskaz buf.insert(7, “dodati “); onda se u baferu nalazi tekst “Ovo je dodati bafer”. Drugi argument metoda insert mo`e biti i neki od osnovnih tipova, isto kao kod metoda append. I ovde se prilikom upotrebe nekog od osnovnih tipova prvo vr{i konverzija tog podatka u string, a tek onda se taj podatak ubacuje u bafer. Ostali metodi klase StringBuffer Klasa StringBuffer ima metod charAt() koji radi na isti na~in kao i kod klase String, koji smo ve} upoznali. U klasi StringBuffer postoji i metod setCharAt(), kojim se menja znak na zadatoj poziciji u baferu. Metod prima dva argumenta. Prvi je indeks karaktera koji treba zameniti, a drugi je novi karakter. buf.setCharAt(3, ‘z’); Prethodni iskaz menja ~etvrti karakter u baferu i na njegovo mesto stavlja slovo z. Postoji i metod za okretanje bafera, odnosno stringa koji se u njemu nalazi. U pitanju je metod reverse, koji preokre}e string, po~ev od poslednjeg prema prvom karakteru. StringBuffer buf = new StringBuffer(“provera”); buf.reverse(); Iskaz buf.reverse() vra}a bafer sa sadr`ajem “arevorp”. Vrlo ~esto }e se za same operacije sa nekim stringom koristiti objekat StringBuffer, ali }e na kraju biti potrebno da od sadr`aja tog bafera napravimo string. Mo`e biti u pitanju {tampanje ili neka druga operacija koja tra`i objekat tipa string. Objekat StringBuffer (kao i svi drugi objekti u Javi) sadr`i metod toString, koji vra}a sadr`aj tog bafera, ali sada kao objekat klase String. StringBuffer buf = new StringBuffer(“proba”); String izlazIzBafera = buf.toString();

31

Klase i objekti
Java je programski jezik koji ima puno sli~nosti sa jezikom C++. Ipak Java je jezik koji je vi{e objektno orijentisan. C++ sadr`i mnoge elemente koji su tu samo zbog kompatibilnosti sa jezikom C, a koji nisu u skladu sa objektnim pristupom. Java je sa druge strane potpuno objektno orijentisana. Ako radite u Javi pretpostavlja se da `elite da koristite samo objektno orijentisano programiranje. U skladu sa ~injenicom da je pravljena kao ~isto objektno orijentisani jezik, to je koncepte vezane za objektno programiranje u Javi lak{e nau~iti i prihvatiti. Svaki programski jezik ima svoje zna~enje pojma manipulacija podacima. Ponekad program mora da stalno vodi ra~una o tome kakva je manipulacija u pitanju. Da li se radi direktno sa objektom ili se radi sa nekom vrstom indirektne predstave (kao pokaziva~i u C++-u) koja ima specijalnu sintaksu. U Javi je ovo mnogo jednostavnije. Sve se tretira kao objekat, Koristi se jedinstvena sintaksa. Iako se sve tretira kao objekat, identifikator kojim manipuli{ete u stvari predstavlja “referencu” na objekat. Zamislite situaciju kada sedite pred svojim televizorom (objekat) i u ruci dr`ite daljinski upravlja~ (referenca). Dokle god dr`ite referencu imate vezu sa objektom (televizorom). Kada neko zatra`i da promenite kanal, ili da smanjite ton, vi manipuli{ete referencom, koja dalje menja sam objekat. Ako `elite da se {etate sobom, a da i dalje kontroli{ete objekat, sa sobom nosite referencu (daljinski), a ne sam objekat (televizor). Referenca mo`e da postoji i nezavisno od samog objekta. Takva referenca, sa druge strane ne mo`e da se koristi. Ako napi{ete String s; vi ste napravili samo referencu na neki objekat klase String, ali jo{ uvek niste toj referenci pridru`ili sam objekat. Da biste mogli da ovu referencu koristite dalje u programu, morate da joj pridru`ite neki objekat. s = “ovo je sada objekat”; Da biste u programu mogli da koristite neki objekat morate da pre toga imate njegovu definiciju. Definicija objekta se naziva klasom. Kada se jednom defini{e klasa, koja opisuje osobine i pona{anje nekog objekta, mogu se praviti konkretni primerci te klase. Ovi primerci se ~esto nazivaju instancama. U definiciji klase mogu da se na|u samo dve stvari: polja - promenljive koje skladi{te podatke i koje omogu}avaju da s enapravi razlika izme|u dva primerka iste klase. metodi - operacije koje se mogu izvoditi sa tom klasom. Metodi obi~no rade sa poljima, odnosno promenljivima klase. Promenljive u definiciji klasa U okviru klase mogu da postoje dve vrste promenljivih. To su promenljive instance i promenljive klase. Napomenuli smo da klasa predstavlja definiciju objekta, a da se na osnovu te definicije prave razli~ite instance (primerci) te klase. Promenljive instance su one promenljive koje su vezane za instance klase. Svaka instanca ima svoje vrednosti ovih promenljivih. Ove promenljive razlikuju jedan objekat od drugog. Ako biste na primer, imali klasu osoba, sa osobinama visina, te`ina i sl., 32

svaka instanca te klase, odnosno svaka konkretna osoba bi imali svoje vrednosti za visinu, te`inu i ostale sli~ne osobine. Promenljive klase je pridru`ena klasi. Ovakve promenljive pripadaju svim instancama te klase. U primeru koji sledi se deklari{e klasa Sfera, koja opisuje sferu.
public class Sfera { //promenljive klase static final double PI=3.14; static int brojac = 0; // promenljiva klase za brojanje objekata //promenljive instance double xCentar; double yCentar; double zCentar; double radijus; … }

Klasa se u Javi defini{e preko klju~ne re~i class iza koje sledi ime klase. Sama definicija klase, odnosno metodi i atributi, moraju biti u okviru zagrada koje slede iza imena klase. Klju~na re~ public na po~etku prethodnog primera ka`e da se ovoj klasi mo`e da pristupi bilo sa kog mesta u programu. Kod koji se odnosi na konkretnu klasu treba da bude u datoteci sa istim imenom i ekstenzijom .java. Konstanta PI je u prethodnom primeru promenljiva klase. Promenljive klase se deklari{u preko klju~ne re~i static. Ako ne `elite da se vrednost neke promenljive kasnije u programu menja, odnosno ako `elite da to kompajler proverava i zabranjuje, mo`ete tu promenljivu deklarisati sa final, {to je i ura|eno u prethodnom primeru. To zna~i da svaki naredni iskaz koji bi poku{ao da promeni vrednost za promenljivu PI, ne bi bio ispravan. Ovo bi trebalo koristiti za sve konstante koje imate u programu. Slede}a promenljiva je tako|e definisana kao promenljiva klase (static). Ovo je promenljiva koju }emo koristiti za brojanje koliko je instanci te klase napravljeno u programu. Svi objekti klase Sfera }e imati samo jednu kopiju promenljivih PI i brojac. Naredne ~etiri promenljive su promenljive instance. Svaka instanca te klase }e imati svoje primerke promenljivih xCentar … Metodi klase Promenljive klase opisuju stanje objekta, ali nisu dovoljne za funkcionisanje same klase. Mora postojati neki na~in da se sa tom klasom ne{to i uradi, a to se ~ini preko metoda. Metoda je blok koda koji ima svoje ime i koja se mo`e izvr{avati vi{e puta sa razli~itih mesta u programu. Pomo}u metoda mo`ete da slo`ene stvari razlo`ite na zbir manjih, kojima je lak{e rukovati. Metoda se poziva preko njenog imena i mo`e, ali ne mora da vrati vrednost. Osnovna struktura metode je:
povratni_tip imeMetode(arg1, arg2, .. argn){ }

Za metodu se mo`e definisati povratni tip koji se vra}a posle njenog izvr{enja. Ako ne `elite da metoda vra}a vrednost, onda njen povratni tip treba zadati kao void. Metodi se mogu proslediti odre|eni argumenti, koji se u telu metode koriste za neka izra~unavanja. Metoda mo`e, ali ne mora da ima argumente. Broj argumenata je proizvoljan. Povratna vrednost iz metode Povratna vrednost se iz metoda vra}a preko iskaza return. Na primer, iskaz 33

return povratnaVrednost;

vra}a vrednost promenljive povratnaVrednost. Nakon izvr{enja iskaza return, program nastavlja sa radom tamo odakle je metoda pozvana. Metode koje vra}aju vrednost moraju da u telu metode imaju iskaz return. U metodi mo`e da postoji vi{e iskaza return, naravno ako to zahteva logika samog programa. Klju~na re~ return mo`e da se upotrebi i sama, bez ikakve promenljive. Ovo se koristi u metodama koje ne vra}aju vrednost. Lista argumenata Izme|u zagrada koje slede iza imena metode se nalazi lista argumenata. Svaki argument mora da ima svoj tip. Ovo su vrednosti koje se metodi prosle|uju u trenutku njenog poziva i koje ona dalje interno koristi.
public class mojaKlasa(){ public int mojaMetoda(int a, double b){ int c; … return c; } }

Argumenti koji se prosle|uju metodi mogu imati neki od osnovnih tipova (int, float, double…), ali mogu biti i drugi objekti. Ako se radi o osnovnim tipovima, onda se argumenti prosle|uju po vrednosti. To zna~i da se za promenljivu koja se prosle|uje metodi u trenutku poziva, pravi nova kopija, sa kojom dalje ta metoda manipuli{e. To dalje zna~i da metoda ne mo`e da promeni vrednost promenljive u programu koji je tu metodu pozvao. Na primer, ako negde u kodu ka`ete
int c = 3; double d = 5.; mojaMetoda(c, d);

onda {ta god radili sa argumentom a u samoj metodi, to ne mo`e da promeni vrednost promenljive c u programu koji je tu metodu pozvao. Ovo ne va`i za objekte koji se prosle|uju meetodama. Objekti se prosle|uju po referenci, tako da metoda mo`e da promeni objekat, a to se vidi u u programu iz kojeg je metoda pozvana. Kao {to postoje dve vrste promenljivih u klasi, tako postoje i dve vrste metoda. To su metode klase (deklarisane preko klju~ne re~i static) i metode instance. Ako se vratimo na klasu Sfera koju smo ranije po~eli da defini{emo:
public class Sfera{ // definicija kao i ranije public static int getBrojac(){ return brojac; } }

Ovo je metoda klase. Za sve instance te klase, postoji samo jedan primerak ove metode, {to i jeste cilj, jer ta metoda vra}a broj instanci klase koji je napravljen. U okviru metoda static ne mo`ete da pristupate nijednoj od promenljivih instanci, jer ta metoda postoji dok jo{ nije napravljen nijedan objekat, tako da ne mora da postoji nijedna promenljiva instance. Pristupanje ~lanu (atributu) klase u metodi U metodu instance mo`ete da pristupite bilo kom podatku koji je ~lan te klase. Pro{iri}emo malo klasu Sfera, tako {to }emo dodati metodu za izra~unavanje zapremine.
public class Sfera { //promenljive klase

34

static final double PI=3.14; static int brojac = 0; // promenljiva klase za brojanje objekata //promenljive instance double xCentar; double yCentar; double zCentar; double radijus; // staticka metoda klase koja vraca broj napravljenih objekata public static int getBrojac(){ return brojac; } // metoda instance koja racuna zapreminu double zapremina(){ return 4.0/3.0 * PI * radijus* radijus* radijus; } }

Metoda zapremina je metoda instance. Ona nema ulazne argumente, ali vra}a vrednost tipa double, u ovom slu~aju zapreminu sfere. U metodu se za izra~unavanje zapremine koristi promenljiva instance radijus. Promenljiva this Svaka metoda instance ima promenljivu this, koja se odnosi na trenutni objekat za koji je metoda pozvana. Kompajler implicitno koristi ovu promenljivu kada se pristupa promenljivim instance te klase. Na primer, iskaz za vra}anje zapremine u definiciji klase Sfera bi mogao da izgleda ovako:
return 4.0/3.0 * PI * this.radijus* this.radijus* this.radijus;

Stvar je va{eg izbora da li }ete koristiti promenljivu this ili ne u svojim metodima. Lokalne promenljive Ako u samoj metodi zadate neke promenljive koje se koriste samo u njoj, te promenljive su lokalne za tu metodu. @ivotni vek tih promenljivih je `ivotni vek metode. Kada se napusti metoda te promenljive prestaju da postoje. Skuplja~ otpada u Javi brine o tome da se oslobodi memorija koju su te promenljive zauzimale. Ako biste na primer, definisali funkciju za promenu radijusa sfere, ona bi mogla da izgelda ovako:
void promenaRadijusa (double radijus){ this.radijus = radijus; }

Promenljiva this.radijus ukazuje na promenljivu radijus u instanci, a promenljiva radijus na ulazni parametar. Inicijalizacija ~lanova klase Prilikom definisanja ~lanova klase mo`e se izvr{iti i njihova inicijalizacija. Dobra programerska praksa je da se sve promenljive prilikom deklaracije inicijalizuju.
public class Sfera { //promenljive klase static final double PI=3.14; static int brojac = 0; // promenljiva klase za brojanje objekata //promenljive instance double xCentar = 10.0; double yCentar= 10.0 ; double zCentar = 10.0; double radijus = 5.0; … }

35

Ako je prilikom inicijalizacije potrebno izvr{iti odre|ena izra~unavanja mo`ete da koristite blok za incijalizaciju. Blokovi za incijalizaciju se ozna~avaju viti~astim zagradama, izme|u kojih se stavljaju iskazi koji treba da se izvr{e. Postoje stati~ki i obi~an blok za incijalizaciju. Stati~ki blok za incijalizaciju se deklari{e klju~nom re~i static ispred viti~astih zagrada. Ovakav blok se izvr{ava jednom, prilikom u~itavanja klase i u njemu se obi~no inicijalizaciju stati~ki ~lanovi klase. Nestati~ki blok za inicijalizaciju se izvr{ava jednom prilikom kreiranja svake instance klase i u njemu mogu da se inicijalizuju promenljive instance. Primer:
public class ProbaInicijalizacije{ static int[] values = new int[10]; double fl; // blok za incijalizaciju static{ for(int i = 0; i < values.length; i++) values[i] = i; } // nestaticki blok za inicijalizaciju { fl = 28.0; } }

Konstruktori U svakoj klasi postoji jedna ili vi{e specijalnih metoda, tzv. konstruktora. Ako prilikom definisanja klase ne zadate nijedan konstruktor, kompajler }e sam napraviti jedan, prazan, podrazumevani konstruktor. Osnovna namena konstruktora je da obezbedi sredstva za inicijalizaciju promenljivih instanci. Konstruktor se izvr{ava prilikom kreiranja instance klase. Ako u klasi postoje blokovi za incijalizaciju, oni se izvr{avaju pre konstruktora. Konstruktor ima dve osobine koje ga razlikuju od ostalih metoda klase: Konstruktor nikada ne vra}a vrednost, tako da se za njega ne zadaje povratni tip (pa ni void) Konstruktor uvek ima isto ime kao klasa. Primer:
public class Sfera { //promenljive klase static final double PI=3.14; static int brojac = 0; // promenljiva klase za brojanje objekata //promenljive instance double xCentar; double yCentar; double zCentar; double radijus; // konstruktor Sfera(double rad, double x, double y, double z){ radijus = rad; xCentar = x; yCentar = y; zCentar = z; brojac++; } // staticka metoda klase koja vraca broj napravljenih objekata public static int getBrojac(){ return brojac; }

36

// metoda instance koja racuna zapreminu double zapremina(){ return 4.0/3.0 * PI *radijus * radijus * radijus; } }

U gornjem primeru je konstuktor uokviren. Kao {to vidite konstruktor ima isto ime kao klasa i nema odre|en povratni tip. Konstruktor mo`e da ima vi{e agumenata, ali ne mora da ima ni jedan. U ovom slu~aju postoje ~etiri argumenta i svaki od njih se koristi za inicijalizaciju odre|ene promenljive instance. Poslednja akcija u konstruktoru je da se uve}a brojac, koji broji instance klase Sfera. Kreiranje objekata klase Kada se negde u kodu deklari{e promenljiva tipa Sfera, iskazom: Sfera lp; ne poziva se nikakav konstruktor. Ovde se ne prave nikakvi objekti. Sve {to se uradili je da ste napravili promenljivu lp, koja mo`e da sadr`i jedan objekat tipa Sfera, ako ga budemo nekada pravili. Da biste napravili instancu klase, morate da upotrebite klju~nu re~ new, iza koje sledi poziv konstruktora. Za na{u klasu Sfera to mo`e da izgleda ovako:
lp = new Sfera(10.0, 1.0, 1.0, 1.0);

Nakon izvr{enja ovog iskaza postoji objekat Sfera sa polupre~nikom 10.0, ~iji je centar ta~ka sa koordinatama 1.0. Promenljiva lp se nakon ovog iskaza pona{a kao referenca na objekat. Ako biste sada napisali
Sfera josLp = lp;

nova promenljiva josLp ukazuje na isti objekat kao i promenljiva lp. Jo{ uvek postoji samo jedan objekat (instanca), ali postoje dve promenljive koje na njega ukazuju. ^injenica da su promenljiva i objekat razdvojeni ima uticaj na na~in na koji se metodi prosle|uju objekti kao argumenti. Prosle|ivanje objekata metodi Objekti se metodama prosle|uju po referenci. To zna~i da se u metodu ne radi sa kopijom objekta, kao kada se prosle|uju promenljive osnovnih tipova, ve} se radi sa istim objektom. To dalje zna~i da }e ako u metodu do|e do neke promene objekta, ta promena imati uticaja i na osnovni objekat koji je metodu prosle|en. Primer: Datoteka SferaMain.java
public class SferaMain { public static void main(String[] args) { Sfera sf = new Sfera(10., 1.0, 1.0, 1.0); System.out.println("Radijus sfere je " + sf.getRadijus()); promenaObjekta(sf); System.out.println("Radijus sfere je " + sf.getRadijus()); } static void promenaObjekta(Sfera sf){ sf.setRadijus(12.0); } } Datoteka Sfera.java public class Sfera { //promenljive klase static final double PI=3.14;

37

static int brojac = 0; // promenljiva klase za brojanje objekata //promenljive instance double xCentar; double yCentar; double zCentar; double radijus; // konstruktor Sfera(double rad, double x, double y, double z){ radijus = rad; xCentar = x; yCentar = y; zCentar = z; brojac++; } // staticka metoda klase koja vraca broj napravljenih objekata public static int getBrojac(){ return brojac; } // metoda instance koja racuna zapreminu double zapremina(){ return 4.0/3.0 * PI *radijus * radijus * radijus; } public void setRadijus(double rad){ this.radijus = rad; } public double getRadijus(){ return this.radijus; } }

U ovom primeru smo prikazali dve klase. Jedna je klasa Sfera koju smo ve} koristili, ali sada dopunjena metodama setRadijus() i getRadijus(). Ove metode slu`e za promenu atributa radijus i za njegovo va|enje iz klase. Druga klasa je SferaMain, koja nam slu`i za izvr{enje ovog programa. Obratite pa`nju na njenu metodu promenaObjekta(). U ovoj metodi se menja radijus objekta koji se metodi prosle|uje kao argument. Po kasnijoj {tampi se vidi da promena radijusa u metodi, menja radijus i u objektu koji je metodi prosle|en. @ivotni vek objekta (instance) @ivotni vek objekta je odre|en promenljivom koja na taj objekat referencira. Ako imate deklaraciju
Sfera sf = new Sfera(10.0, 1.0, 1.0, 1.0)

onda objekat sf postoji sve dok postoji promenljiva sf. To }e biti na kraju oblasti u kojoj se ova deklaracija nalazi. Na isti objekat mo`e da referencira vi{e promenljivih. U tom slu~aju objekat postoji sve dok postoji i poslednji objekat koji na njega ukazuje. Ako se napi{e iskaz sf = null; onda promenljiva sf vi{e ne ukazuje na objekat, tako da taj objekat mo`e biti uni{ten (pod pretpostavkom da nema drugih promenljivih koje na njega ukazuju. Proces izbacivanja objekata koji se u programu vi{e ne koriste se naziva skupljanjem otpada (garbage collection). Ovo skupljanje otpada se u Javi odvija automatski. To ipak ne zna~i da objekti istog trenutka kada se vi{e ne koriste i nestaju iz memorije, pa samim tim ta memorija ne mora da bude odmah na raspolaganju. U pitanju je proces koji nije pod va{om kontrolom, tako da o njemu ne treba mnogo brinuti. 38

U primeru koji sledi smo pokazali kako se koristi klasa Sfera koju smo napravili. Primer: Datoteka SferaMain.java
public class SferaMain { public static void main(String[] args) { System.out.println("Broj objekata je " + Sfera.getBrojac()); Sfera lp = new Sfera(4.0, 0.0, 0.0, 0.0); System.out.println("Broj objekata je " + lp.getBrojac()); Sfera lp1 = new Sfera(12.0, 1.0, 1.0, 1.0); System.out.println("Broj objekata je " + Sfera.getBrojac()); System.out.println("Zapremina sfere lp je " + lp.zapremina()); System.out.println("Zapremina sfere lp1 je " + lp1.zapremina()); } }

Klasa Sfera je ista kao u prethodnom primeru, a u datoteci SferaMain.java smo dali klasu koja kreira instancu klase Sfera i poziva neke njene metode. Preklapanje metoda U klasi mo`ete da defini{ete vi{e metoda sa istim imenom, ali sa razli~itim argumentima. Takvi metodi se nazivaju preklopljenim metodima. Preklopljene metode se me|usobno moraju da razlikuju po broju ili tipu argumenata. Ne mogu se razlikovati samo po povratnom tipu. Primer za preklopljene metode mogu biti metodi append, klase StringBuffer, koje smo ve} koristili. Vi{estruki konstruktori Kao i obi~ne metode, tako se i konstruktori mogu da preklapaju. Preklopljeni konstruktori se koriste kada je potrebno da instancu klase napravite na osnovu razli~itih ulaznih parametara. Ako pogledamo klasu Sfera, u njoj mo`emo da imamo jedan podrazumevani konstruktor (bez argumenata) i konstruktor koji smo ve} napravili (sa argumentima za radijus i koordinate ta~ke). Primer: Konstruktori iz klase Sfera // podrazumevani konstruktor
Sfera(){ radijus = xCentar = yCentar = zCentar = brojac++; } 1.0; 0.0; 0.0; 0.0;

Sfera(double rad, double x, double y, double z){ radijus = rad; xCentar = x; yCentar = y; zCentar = z; brojac++; }

Prilikom kreiranja instanci klase Sfera kompajler odre|uje koji }e konstruktor pozvati na osnovu tipa argumenata koje ste zadali.
Sfera lp = new Sfera(); // podrazumevani konstruktor Sfera lp1 = new Sfera(2.0, 1.0, 1.0, 1.0);

39

Primer koji sledi se odnosi na jednostavnu geometriju u ravni. U njemu }emo koristiti dve klase. Jedna klasa defini{e objekat tacka, a druga liniju. Ove objekte }emo koristiti za pronala`enje preseka dveju linija. Klasa Tacka:
public class Tacka { // Koordinate tacke double x; double y; // Kreiranje tacke na osnovu koordinata Tacka(double xVal, double yVal) { x = xVal; y = yVal; } // Kreiranje tacke na osnovu druge tacke Tacka(final Tacka oldTacka) { x = oldTacka.x; y = oldTacka.y; } // Pomeranje tacke void move(double xDelta, double yDelta) { // parametarske vrednosti koje se dodaju trenutnim koordinatama x += xDelta; y += yDelta; } // Rastojanje do druge tacke double distance(final Tacka aTacka) { return Math.sqrt( (x - aTacka.x)*(x - aTacka.x) + (y - aTacka.y)*(y - aTacka.y) ); } // KOnvertuje tacku u string public String toString() { return Double.toString(x) + ", " + y; } }

Klasa Linija (Linija.java):
public class Linija { Tacka start; // pocetna tacka linije Tacka end; // Krajnja tacka linije // Kreiranje Linija(final { this.start this.end = } linije na osnovu dve tacke Tacka start, final Tacka end) = new Tacka(start); new Tacka(end);

// Kreiranje linije na osnovu koordinata dveju tacaka Linija(double xStart, double yStart, double xEnd, double yEnd) { start = new Tacka(xStart, yStart); end = new Tacka(xEnd, yEnd);

40

} // izracunavanje duzine linije double length() { return start.distance(end); // koristi se metod klase Tacka } // Linija se konvertuje u string public String toString() { return "(" + start + "):(" + end + ")"; } // presek dve linije Tacka intersects(final Linija Linija1) { Tacka lokalnaTacka = new Tacka(0, 0); double num = (this.end.y - this.start.y)*(this.start.x - Linija1.start.x) (this.end.x - this.start.x)*(this.start.y - Linija1.start.y); double denom = (this.end.y - this.start.y)*(Linija1.end.x - Linija1.start.x) (this.end.x - this.start.x)*(Linija1.end.y - Linija1.start.y); lokalnaTacka.x = Linija1.start.x)*num/denom; lokalnaTacka.y = Linija1.start.y)*num/denom; return lokalnaTacka; } } Linija1.start.x Linija1.start.y + + (Linija1.end.x (Linija1.end.y -

Klasa Geometrija (Geometrija.java):
public class Geometrija { public static void main(String[] args) { // Kreiraju se dve tacke i prikazuju se Tacka start = new Tacka(0.0, 1.0); Tacka end = new Tacka(5.0, 6.0); System.out.println("Napravljene su dve tacke " + start + " i " + end);

// Kreiraju se dve linije i prikazuju se Linija Linija1 = new Linija(start, end); Linija Linija2 = new Linija(0.0, 3.0, 3.0, 0.0); System.out.println("Napravljene su dve linije " Linija2);

+

Linija1

+

"

i

"

+

// Presek System.out.println("Presek je " + Linija2.intersects(Linija1)); // Pomera se krajnja tacka linije 1 i prikazuje se novi presek end.move(1.0, -5.0); System.out.println("Novi presek je " + Linija1.intersects(Linija2)); } }

41

U klasi Tacka postoje dva ~lana (x i y koordinata tacke). U ovom trenutku postoje dva konstruktora, jedan koji tacku pravi na osnovu para koordinata i drugi koji pravi novi objekat Tacka, na osnovu postoje}eg. U klasi smo definisali i metodu toString(), koja preklapa metodu toString() nasle|enu iz klase Object. Ako klasa ima ovu metodu, onda se u prilikom {tampanja pomo}u operatora + (spajanje stringova) mo`e koristiti objekat ove klase. U klasi Linija smo liniju definisali preko dva objekta klase Tacka, {to je i prirodno. U metodu za izra~unavanje preseka, smo koristili parametarske jedna~ine du`i (x=x1 + (x2-x1)t i y=y1+(y2-y1)s). Rekurzija Metode koji smo do sada koristili se pozivaju iz drugih metoda. Proces u kome metoda poziva samu sebe se naziva rekurzijom. U rekurzivnom metodu mora da postoji i neka logika koja }e prekinuti poziv metode, jer bi u suprotnom dobili beskona~ane pozive. U primeru koji sledi je data rekurzivna metoda koja ra~una stepen zadate ceoblrojne vrednosti. To zna~i da se ra~una xn.
public class Stepen { public static void main(String[] args) { double x = 5.0; System.out.println(x + " na 4 je " + power(x,4)); System.out.println("7.5 na 5 je " + power(7.5,5)); System.out.println("7.5 na 0 je " + power(7.5,0)); System.out.println("10 na -2 je " + power(10,-2)); } // Dize se x na n-ti stepen static double power(double x, int n) { if(n > 1) return x*power(x, n-1); // rekurzivni poziv else if(n < 0) return 1.0/power(x, -n); // Negative power of x else return n == 0 ? 1.0 : x; // Ako je n 0 vraca se 1, u suprotnom se vraca x } }

Ako je n pozitivan broj, ve}i od 1, metoda power poziva samu sebe, ali sa ulaznim parametrom smanjenim za 1. Ovo se ponavlja sve dok stepen ne dobije vrednost 0, u kom slu~aju se prekida rekurzija. Rekurzivni metodi su veoma zahtevni po pitanju resursa i vremena. Zbog toga treba da se pozivaju samo kada je to neophodno. Navedeni primer bi se mnogo lak{e realizovao putem petlje. Na taj na~in bi se izvr{avao mnogo efikasnije. Rekurzije najvi{e primene imaju kod struktura podataka kao {to je stablo ili liste. Paketi Sve klase u Javi su organizovane u pakete. Paketi u Javi su sli~ni direktorijumima (fasciklama) koji se koriste za organizaciju podataka na disku. I klase koje smo do sada koristili se nalaze u paketima, ali do sada na to nismo obra}ali pa`nju. Sve standardne klase koje postoje u Javi su tako|e organizovane u pakete. Klase koje smo do sada koristili (String, StringBuffer) se nalaze u paketu java.lang. Ovaj paket nije potrebno nazna~avati u 42

kodu, jer je on automatski dostupan u svim programima. Postoje i drugi standardni paketi, ali se oni uglavnom moraju eksplicitno uklju~iti u kod. Pakovanje klase se izvodi tako {to se u datoteku u kojoj se nalazi klasa na po~etku doda iskaz za pakovanje. Ovaj iskaz mora biti prvi u toj datoteci.
package Proba; public class Sfera …

Prethodni iskaz ka`e da je klasa Sfera pripadnik paketa Proba. U jednom paketu mo`e biti vi{e klasa. Klju~na re~ public u definiciji klase ukazuje na to da se klasi Sfera mo`e pristupiti i iz drugih paketa i klasa u programu. Ako se prilikom definicije klase ne navede klju~na re~ public, onda se toj klasi mo`e pristupati samo iz metoda klasa koje se nalaze u istom paketu. Paketi su povezani sa strukturom direktorijuma na kome se nalaze datoteke sa Java klasama. Ve} znamo da se definicija klase nalazi u datoteci ~ije je ime isto kao ime klase. Sve datoteke u paketu ImePaketa moraju se nalaziti u direktorijumu ImePaketa. Paketi mogu da imaju strukturu. Na primer, ako `elite da napravite jedan vrhovni paket za rad sa geomtrijom i nazovete ga Geometrija, a da u njemu razdvojite klase koje se koriste za 2D i 3D geometriju, mo`ete da napravite jo{ dva paketa po imenu 2dObilici i 3dOblici, koji se nalaze u paketu Geometrija. Ti paketi se defini{u na slede}i na~in:
package Geometrija.2dOblici; public class Linija …

Klasa Linija iz ovog primera mora da se nalazi u direktorijumu 2dOblici, koji se nalazi u direktorijumu Geometrija. Ova struktura mo`e imati dubinu koja odgovara Va{im potrebama. Prilikom kompajliranja datoteka sa izvornim kodom, nastaju datoteke sa bajt kodom, ~ija je ekstenzija .class. Struktura direktorijuma sa ovim datotekama, tako|e mora da po{tuje pakete koji se primenjuju. O ovome brine kompajler, ali i vi to morate znati, jer se prilikom preno{enja tih klasa ta struktura mora da ispo{tuje. Dodavanje klasa iz nekog drugog paketa u program Ako su klase u drugom paketu definisane sa klju~nom re~i public, onda novi program te klase mo`ete dodati preko iskaza import. Ovaj iskaz treba da se nalazi na po~etku datoteke sa definicijom klase, ali iza iskaza za definisanje paketa. Na primer, ako u datoteci u~inite dostupnim klase iz paketa Geometrija.3dOblici, mo`ete da napi{ete: import Geometrija.3dOblici.*; Zvezdica na kraju prethodno iskaza zna~e da se uklju~uju sve klase iz paketa. Ako se napi{e konkretna klasa, pripadnik tog paketa, onda se mo`e pristupati samo toj klasi. import Geometrija.3dOblici.Sfera; // uklju~uje klasu Sfera Ime klase, pored imena same klase, sadr`i i ime paketa u kome se ta klasa nalazi. To zna~i da u programu mo`ete da imate dve klase sa istim osnovnim imenom, ako se one nalaze u razli~itim paketima. Ovo je isto kao sa datotekama na disku, koje mogu da imaju isto ime, ako se nalaze u razli~itim direktorijumima. Standardne klase i paketi Sve standardne klase koje se isporu~uju sa Javom se nalaze u standardnim paketima. Lista ovih paketa stalno raste, ali evo nekih od njih: java.lang - ovaj paket ne mora da se eksplicitno ubacuje u program. Sadr`i osnovne klase kao {to su String, StringBuffer, Math i sl. java.io - sadr`i klase koje s ekoriste za ulazno izlazne operacije 43

java.awt - osnovne klase za grafi~ki korisni~ki interfejs (GUI). java.swing - grafi~ki interfejs, ali pobolj{an java.util - klase za datum i vreme, za manipulisanje kolekcijama i sl java.sql - klase za pristup bazama podataka putem jezika SQL … Standardne klase za osnovne tipove objekata Za sve osnovne tipove podataka u Javi postoje klase omota~i, koje sadr`e osnovni tip ali i dodatne metode za manipulaciju tim osnovnim tipom. To su slede}e klase: Boolean Character Byte Short Integer Long Float Double Sve ove klase se nalaze u paketu java.lang. Ove klase }ete koristiti ako `elite da od stringa napravite osnovni tip (meetode tipa parseInt, parseDouble i sl), ili kada je potrebno da na neki drugi na~in manipuli{ete osnovnim tipom. Dostupnost ~lanova klase U istom paketu, bilo koja klasa ima direktan pristup do bilo koje klase iz tog paketa. Promenljive i metodi te druge klase ne moraju obavezno da budu dostupni. Njihova dostupnost zavisi od atributa dostupnosti za svaki konkretan metod i atribut. Prilikom definisanja dostupnosti postoje ~etiri mogu}nosti. Atribut Bez atributa dostupnosti public private protected Dozvoljen pristup Iz bilo koje klase u okviru paketa Iz bilo koje klase, bilo otkuda nema pristupa izvan klase iz bilo koje klase u okviru paketa i iz bilo koje potklase, koja se nalazi u bilo kom paketu

^lanovi klase bi generalno trebalo da budu deklarisani sa atributom private. Ovo je u skladu sa jednim od principa objektno orijentisanog programiranja, koji se odnosi na u~aurenje. To zna~i da se ~lanovi klase ne mogu menjati direktno na bilo kom mestu odakle se pozivaju. Sa druge strane, metode predstavljaju interfejs klase, tako da je njih najbolje deklarisati kao public. Dobra programerska praksa je da se ~lanovi deklari{u kao privatni, a da se za one koje je potrebno menjati spolja i ~ije se vrednosti ~itaju spolja deklari{u odgovaraju}i set i get metodi. Promena ovih ~lanova i pristup do njih je tada mogu} samo preko ovih metoda.
double radijus; public double getRadijus(){ return this.radijus; }

44

public void setRadijus(double rad){ this.radijus = rad; }

Metoda finalize() U klasi mo`e da postoji i metoda finalize(). Ovo je metoda koja se automatski poziva pre nego {to se objekat uni{ti i oslobodi prostor u memoriji koji je on zauzimao. To ne mora biti istog trenutka kada se objekat prestane da koristi. Kada objekat vi{e nije u oblasti va`enja, {to se ti~e programa on ne postoji, ali Java virtuelna ma{ina mo`da ne}e odmah da ga izbaci iz memorije. Kada do|e do izbacivanja ona poziva metodu finalize(0. Evo kako izgleda ta metoda: protected void finalize(){ // kod za ~i{}enje
}

Ova metoda je korisna kada se u klasi koriste neki resursi koji zahtevaju posebnu akciju prilikom uni{tavanja objekta. Obi~no ti objekti nisu u okviru Java okru`enja i nema garancije da }e biti automatski oslobo|eni. To mogu biti grafi~ki resirsi, ili datoteke na disku i sl. Nasle|ivanje Jedna od osnovnih osobina objektno orijentisanog programiranja jeste nasle|ivanje. Nasle|ivanje omogu}ava da novu klasu izvedete iz neke postoje}e i da je kasnije pro{irite. U novoj klasi mo`ete da koristite sve mogu}nosti osnovne klase, ali i da dodate nove. Klasa iz koje se izvodi nova klasa se naziva osnovnom ili originalnom ili superklasom izvedene klase. U primeru koji sledi smo definisali osnovnu klasu Pas, iz koje smo zatim izveli potklasu Spaniel.
class Pas{ // clanovi klase Pas } class Spaniel extends Pas{ // clanovi klase Spaniel }

Prilikom definisanja izvedene klase se koristi klju~na re~ extends (pro{iruje). Ova definicija konkretno zna~i da se klasa Spaniel izvodi iz klase Pas, tako da }e objekat tipa Spaniel imati sve ~lanove koje ima klasa Pas, plus ~lanove koji su specifi~ni samo za njega. Spaniel je specijalizovani primerak psa. To odra`ava i realni svet. [panijel je vrsta psa i ima mnoge osobine koje su zajedni~ke za sve pse, ali ima i jedinstvene osobine koje ga razlikuju od ostalih vrsta pasa. Mehanizam nasle|ivanja je u ovom slu~aju dobar model za opisivanje stvarnog sveta. Prilikom nasle|ivanja se odvija aditivan proces u smislu definicije klase. Osnovnu i izvedenu klase razlikuju dodatni ~lanovi koje pravite u izvedenoj klasi. Bilo koji ~lan koji se defini{e u izvedenoj klasi je dodatak ~lanovima koji postoje u osnovnoj klasi. Objekat Spaniel }e u sebi uvek imati kompletan objekat Pas, sa svim njegovim podacima i metodama. To ipak ne zna~i da }e u klasi Spaniel biti dostupni svi ~lanovi i metodi klase Pas. Dostupni su samo oni ~lanovi koji se nasle|uju. Ako ~lan osnovne klase nije dostupan u izvedenoj klasi, onda on nije nasle|eni ~lan, ali jeste deo objekta izvedene klase. Da biste mogli da izvodite novu klasu iz neke klase, osnovna klasa ili mora biti u istom paketu, ili mora biti deklarisana kao public. Potklasa ili izvedena klasa nasle|uje sve ~lanove osnovne klase osim onih koji su deklarisani kao privatni (klju~na re~ private). Ovo va`i ako su osnovna i izvedena klasa u istom paketu. Ako

45

osnovna i izvedena klasa nisu u istom paketu, onda se nasle|uju samo oni ~lanovi osnovne klase koji su definisani kao za{ti}eni (klju~na re~ protected). Pravila nasle|ivanja se odnose i na promenljive instance i na promenljive klase.
class OsnovnaKlasa{ private static int a;// ne nasledjuje se protected static int b;// nasledjuje se }

Ako se u izvedenoj klasi defini{e ~lan sa istim imenom kao u osnovnoj klasi, onda taj iz izvedene klase sakriva onaj iz osnovne. Nasle|ivanje metoda Metode koje nisu konstruktori se nasle|uju isto kao i atributi. One metode koje su osnovnoj klasi deklarisane kao private se ne nasle|uju, a one koje su deklarisane bez atributa dostpunosti se nasle|uju samo u istom paketu. Konstruktori se nikad ne nasle|uju. Primer: Pretpostavimo da smo definisali klasu Zivotinja:
public class Zivotinja{ private String tip; public Zivotinja(String aTip){ tip = new String(aTip); } public String toString(){ return “Ovo je “ + tip; } }

U ovoj klasi postoji ~lan tip koji slu`i za to da odredi o kojoj se `ivotinji radi. Sada mo`emo definisati drugu klasu koja se zasniva na klasi Zivotinja. Ova klasa }e definisati pse.
public class Pas extends Zivotinja{ // konstrktori za objekat Pas private String ime; private String rasa; }

Klasa Pas nasle|uje samo metodu toString(), po{to se ~lanovi deklarisani kao private i kontruktori ne nasle|uju. Objekat Pas }e imati i podatak ~lan koji se odnosi na tip, ali se tom ~lanu ne mo`e pristupiti iz klase Pas. Konstruktori izvedene klase
public class Pas extends Zivotinja{ public Pas(String aIme){ super(“Pas”); ime = aIme; rasa = “Nepoznato”; } public Pas(String aIme, String aRasa){ super(“Pas”); ime = aIme; rasa = aRasa; } private String ime; private String rasa; }

Kao {to vidite u konstruktorima izvedene klase treba pozivati konstruktore osnovne klase, koji inicijalizuju podatke koji su definisani u toj klasi. To se radi iskazom: 46

super(“Pas”); Konstruktor osnovne klase se uvek poziva preko klju~ne re~i super. Ako u konstruktori izvedene klase niste u prvom redu pozvali konstuktor osnovne klase, kompajler }e to poku{ati da uradi umesto vas. U tom slu~aju }e se dodati iskaz: super(); Ovo je podrazumevani konstruktor za osnovnu klasu. Ako on ne postoji, prilikom kompajliranja }e se javiti gre{ka. Primer: U primeru koji sledi smo prikazali kako bi mogla da se upotrebi klasa Pas, koju smo pre toga napravili.
public class TestIzvodjenje { public static void main(String[] args) { Pas ps = new Pas("Fido", "Chiuahua"); Pas ps1 = new Pas("Lesi"); System.out.println(ps); System.out.println(ps1); } }

Metod toString koji se ovde poziva je metod koji dolazi iz osnovne klase. Ovaj metod nije svestan ~lanova izvedene klase. Probajte da iz konstruktora u klasi Pas izbacite poziv konstruktora osnovne klase i analizirajte rezultate. Preklapanje metoda osnovne klase U izvedenoj klasi mo`ete definisati metodu koja ima isto zaglavlje kao i metoda u osnovnoj klasi. Atribut dostupnosti mora biti isti kao u osnovnoj klasi, ili manje restriktivan. To zna~i da ako je metoda u osnovno klasi deklarisana kao public, u izvedenoj klasi mora biti tako|e deklarisana kao public. Kada se iz instance izvedene klase kasnije poziva metoda sa ovim imenom, poziva se metoda iz izvedene klase, a ne metoda iz osnovne klase. To zna~i da metoda u izvedenoj klasi ima prioritet u odnosu na metodu iz osnovne klase. Pokaza}emo ovo na primeru metode toString() koju smo definisali u klasi Zivotinja. Sada }emo je definisati i u klasi Pas.
public String toString(){ return "Ime psa je " + ime + " a rasa je " + rasa; }

Po{to u klasama Zivotinja i Pas postoje metode toString(), koje imaju isto zaglavlje (ime, povratni tip i argumente), to se prilikom poziva metode iz instance klase Pas, poziva odgovaraju}a metoda te klase. Ako bismo `eleli da prika`emo i vrstu `ivotinje, moramo prikazati atribut tip iz osnovne klase. Ovaj atribut je deklarisan kao privatan, tako da mu s ene mo`e pristupiti iz izvedene klase. Zbog toga }emo jo{ jednom promeniti metod toString() u izvedenoj klasi:
public String toString(){ return super.toString() + "\nIme psa je " + ime + " a rasa je " + rasa; }

Sada se direktno preko iskaza super.toString() poziva metod toString() osnovne klase, koji {tampa vrstu `ivotinje.

47

Polimorfizam Pomorfizam je jedna od va`nih osobina objektno orijentisanog programiranja. Ova osobina omogu}ava da se jedna ista promenljiva, zadatog tipa, koristi za referenciranje objekata razli~itih tipova, pri ~emu se automatski pozivaju metode specifi~ne za tip objekta kojem se pristupa. To omogu}ava da se jedna ista metoda pona{a na razli~ite na~ine, u zavisnosti od tipa metoda na koji se poziv odnosi. Polimorfizam radi sa izvedenim klasama. Promenljiva zadatog tipa obi~no ukazuje na objekat istog tipa. Izvedene klase uvode nove mogu}nosti, koje se odnose na ~injenicu da se objekat izvedene klase mo`e uskladi{titi u promenljivoj koja je tipa direktne ili indirektne osnovne klase. Ako se prisetimo klasa Zivotinja i Pas iz prethodnog primera, kod njih je mogu}e da se instanca klase Pas, smesti u promenljivoj tipa Zivotinja. Isto va`i i za instancu klase Spaniel, koja mo`e bti uskladi{tena u promenljivima tipa Zivotinja i Pas. Da bi se dobilo polimorfno pona{anje prilikom poziva metode, metoda mora biti ~lan i osnovne i izvedene klase. Ne mo`ete da pozovete metodu iz objekta izvedene klase, koriste}i metodu osnovne klase, ako metoda ne postoji u osnovnoj klasi. Metode u osnovnoj i izvedenim klasama moraju da imaju istu deklaraciju i isti povratni tip, a dostupnost ne sme biti vi{e restriktivna. Pretpostavimo da ste deklarisali promenljivu Zivotinja ziv; // deklaracija promenljive tipa Zivotinja Ovu promenljivu mo`ete upotrebiti za ukazivanje na objekat bilo koje klase koja je izvedena iz klase Zivotinja. Mo`ete je na primer koristiti za ukazivanje na objekat klase Pas: ziv = new Pas(“Vucjak”); Da pogledamo malo detaljnije kako ovo izgleda na primeru. Klasu Pas }emo pro{iriti novom metodom koja prikazuje zvuk koji pas proizvodi.
public class Pas extends Zivotinja{ // metoda za lavez public void zvuk(){ System.out.println("Av Av"); } //.. ostatak isti kao ranije }

Iz klase Zivotinja mo`emo da izvedemo i klasu Macka:
public class Macka extends Zivotinja { public Macka(String aIme) { super("Macka"); ime = aIme; rasa = "Nepoznato"; } public Macka(String aIme, String aRasa) { super("Macka"); ime = aIme; rasa = aRasa; } // Vra]a se string sa detaljima o toj macki public String toString() { return super.toString() + "\nIme macke je " + ime + " a rasa je " + rasa; }

48

// metod za mjaukanje public void zvuk() { System.out.println("Mijauuu"); } private String ime; private String rasa; } // ime macke // rasa

Izve{}emo i klasu za patke.
public class Patka extends Zivotinja { public Patka(String aIme) { super("Patka"); ime = aName; rasa = "Nepoznato"; } public Patka(String aIme, String aRasa) { super("Patka"); ime = aIme; rasa = aRasa; } // Detalji o patkio public String toString() { return super.toString() + "\nIme patke je " + ime + " a rasa je " + breed; } // metod za zvuk public void zvuk() { System.out.println("Kva kva"); } private String ime; private String rasa; }

Da bi mogao da se primeni polimorfizam, metoda zvuk() mora da se implementira i u osnovnoj klasi Zivotinja. U tu klasu dodajte slede}i kod:
public void zvuk(){ }

Potreban nam je i program koji }e koristiti ove klase.
import java.util.Random; public class Polimorfizam { public static void main(String[] args) { // NIz sa razlicitim zivotinjama Zivotinja[] zivotinje = { new Pas("Dzoni", "Pudlica"), new Macka("Cica", "Sijamska"), new Patka("Daca") }; Zivotinja izborZivotinje; Random select = new Random(); // Pet slucajnih izbora for(int i = 0; i < 5; i++){ // generator slucajnih brojeva

49

izborZivotinje = zivotinje[select.nextInt(zivotinje.length)]; System.out.println("\nIzabrali ste :\n" + izborZivotinje); izborZivotinje.zvuk(); // reakcija } } }

Ovde su napravljene tri instance klasa Pas, Macka i Patka. One su sme{tene u nizu ~iji je osnovni tip Zivotinja. Kasnije koristimo klasu Random i njen objekat select, preko kojih generi{emo slu~ajne brojeve koje koristimo za pristup elementima niza. Iz dobijenih rezultata (koji su svaki put kada se program izvr{i razli~Iti) se vidi da se metode toString() i zvuk() pozivaju u zavisnosti od objekta koji je uskladi{ten u promenljivoj izborZivotinje. Vi{estruki nivoi nasle|ivanja Izvedena klasa mo`e biti osnovna za neku drugu klasu. Iz klase Pas bismo mogli da bez problema izvedemo klasu Vucjak.
public class Vucjak extends Pas{ public Vucjak(String aIme){ super(aIme, “Vucjak”); } }

U prethodni primer mo`emo dodati i ovu klasu. Promenite samo slede}i kod:
Zivotinja[] zivotinje = { new Pas("Dzoni", "Pudlica"), new Macka("Cica", "Sijamska"), new Patka("Daca"), new Vucjak(“Reks”); };

Klasa Vucjak }e naslediti sve ~lanove klase Pas, uklju~uju}i i one ~lanove koji su nasle|eni iz klase Zivotinja. Klasa Pas je direktna super klasa, a klasa Zivotinja je indirektna super klasa. Jedini dodatni ~lan klase Vucjak je konstruktor u kome se poziva konstruktor klase Pas, kome se prosle|uje ime, i rasa “Vucjak”. Apstraktne klase U klasi Zivotinja smo imali metodu zvuk() koja je bila prazna i koja se tu nalazila samo da bi kasnije mogla da se koristi u izvedenim klasama. Ovaj metod u klasi Zivotinja nema nikakvo zna~enje. Ovo se mo`e re{iti i preko apstraktnih klasa. Apstraktna je ona klasa u kojoj su neke metode deklarisane, ali ne i definisane. Po{to ove metode nemaju definiciju, u pitanju su apstraktne metode. Evo kako to izgleda na primeru:
public abstract class Zivotinja{ public abstract void zvuk(); //apstraktna metoda public Zivotinja (String aTip) { tip = new String(aTip); } public String toString() { return "Ovo je " + tip; } private String tip; }

Od klase koje je deklarisana kao apstraktna se ne mogu praviti instance, ali se mo`e napraviti promenljiva tog tipa. 50

Univerzalna superklasa Sve klase koje pravite u Javi su izvedene iz jedne zajedni~ke klase, Object. Ovo se nigde eksplicitno ne zadaje. To se podrazumeva. U skladu sa ovim promenljiva tipa Object mo`e da primi instancu bilo koje druge klase. To je korisno kada treba da napi{ete metodu koja rukuje objektom nepoznatog tipa. U tom slu~aju dodajete promenljivu tipa Object, a u samoj metodi ispitujete koja je vrsta objekta u pitanju. Klasa Object ima odre|en broj metoda i atributa (~lanova), koje Va{e klase nasle|uju. Evo koje su to metode: Metoda toString() Namena Vra}a se String koji opisuje trenutni objekat. U nasle|enoj verziji metode to }e biti ime klase iza kojeg sledi @, i heksadecimalna reprezentacija objekta. Ova metoda poredi prosle|eni objekat i trenutni objekat i vra}a true ako su objekti isti (ne samo jednaki ve} to mora biti isti objekat u memoriji). Vra}a false ako su razli~iti objekti, pa ~ak i ako su vrednosti njihovih atributa identi~ne. Vra}a se objekat tipa Class koji identifikuje klasu trenutnog objekta. Vra}a hash kod objekta koji se koristi kod sme{tanja objekta u hash tabelama. Koristi se za obave{tavanje niti koja je u vezi sa trenutnim objektom. koristi se za obave{tavanje svih niti koje su u vezi sa trenutnim objektom. Dovodi do toga da nit ~eka na promenu u trenutnom objektu.

equals()

getClass() HashCode() notify(0 notifyAll() wait()

Metode getClass(), notify(), notifyAll i wait() se ne mogu preklapati u izvedenim klasama. Postoje i dve metode tipa protected. To su metode clone() koja se koristi za kopiranje objekta i metoda finalize() koja se poziva kada se objekat bri{e iz memorije. Ove metode se mogu menjati u izvedenim klasama. Metoda toString() Ovu metodu smo koristili u na{im klasama. Nju kompajler koristi kada je potrebna String prezentacija objekta. Ako se ova metoda ne preklopi, onda se koristi verzija iz klase Object. U njoj se prikazuje ime klase, znak @ i hash kod tog objekta. Pas@b75778b2 Odre|ivanje tipa objekta Metoda getClass() koju sve klase nasle|uju iz klase Object vra}a objekat tipa Class, koji identifikuje klasu objekta o kome je re~. Pretpostavimo da imate promenljivu ziv tipa Zivotinja, koja mo`e ukazivati na objekat tipa Pas, Macka, Patka ili ~ak Vucjak.
Class tipObjekta = ziv.getClass(); System.out.println(tipObjekta.getName()); // prikaz imena klase

51

Ako promenljiva ukazuje na objekat klase Patka, onda }e drugi iskaz iz prethodnog primera dati izlaz Patka Ako se klasa nalazi u nekim paketu ovde }e biti i celo ime paketa u kome se klasa nalazi. Konverzija tipa objekta Objekat izvedene klase se mo`e konvertovati u objekat neke od superklasa za tu klasu. Mo`ete na primer, konvertovati objekat tipa Vucjak u klasu Pas ili Zivotinja, ili Object.
Vucjak vuc = new Vucjak(“Reks”); Zivotinja ziv = (Zivotinja) vuc; // konvertovanje Vucjaka u Zivotinju. Ovo i ne mora da se eksplicitno navodi (kod konverzije navi{e) Zivotinja ziv = vuc;// konvertovanje Vucjaka u Zivotinju

Kada konvertujete objekat u tip natklase, Java zadr`ava informaciju o tome koja je aktuelna klasa kojoj objekat pripada. Mogu}a je i obrnuta konverzija, ali tek ako je re~ o povratku na prvobitan tip. Ako se radi o konverziji u natklasu, onda je mogu}a implicitna konverzija, a ako je re~ o konverziji u izvedenu klasu, onda konverzija mora da se eksplicitno izvr{i. Identifikacija objekata Ako ne znate o kom se objektu radi (na primer, kada je objekat izvedene klase prosle|en metodi osnovne klase, kao argument, a deklarisani tip je izvedena klasa), mo`ete da preko operatora instanceof proverite tip objekta, pre same konverzije. Primer:
Patka pat; if(ziv instanceof Patka){ pat = (Patka) ziv; … }

Ako promenljiva ziv ukazuje na promenljivu tipa Zivotinja i Vi `elite da je konvertujete u tip Patka, to se mo`e uraditi samo ako je taj objekat inicijalno ukazivao na tip Patka. Ako to nije bio slu~aj, poku{aj konverzije dovodi do izuzetka. Na ovaj na~in se pojava tog izuzetka izbegava. Operator instanceof vra}a true ako je objekat instanca te klase ili neke od njenih potklasa. Interfejsi U klasama koje smo izvodili iz klase Zivotinja imali smo metodu zvuk() koja je bila razli~ito implementirana u svakoj od potklasa. Time smo `eleli da dobijemo polimorfno pona{anje. Ako Vam je potrebno samo polimorfno pona{anje, a ne i ostalo {to se posti`e nasle|ivanjem, mo`ete upotrebiti interfejse. Interfejs predstavlja skup konstanti i apstraktnih metoda. Da bi neka klasa mogla da koristi interfejs, on mora da se u toj klasi implementira. Nakon implementacije interfejsa u svakoj klasi morate da napi{ete i kod za metode koje ste u interfejsu deklarisali. Kada klasa implementira interfejs sve konstante koje su zadate u definiciji interfejsa su direktno dostupne u klasi, isto kao da su nasle|ene iz neke osnovne klase. Interfejs mo`e da sadr`i konstante, apstraktne metode ili oboje. Metode u interfejsu su uvek public i abstract, pa se uz njih ne vezuju atributi. Konstante su uvek public, static i final, pa se ni za njih ne zadaju atributi. U primeru koji sledi dat je interfejs koji sad`i samo konstante:
public interface FaktoriKonverzije { double INCH_U_MM = 2.54;

52

double UNCA_U_GRAM = 28.34; double FUNTA_U_GRAM = 453.59; }

Ovde je zadato nekoliko konstanti koje se mogu koristiti za konverziju jedinica. Sve one su podrazumevano public, static i final. Evo interfejsa koji sadr`i metrode za konverziju:
public interface Konverzija { double inchUMM(double inchi); double uncaUGram(double unce); double funtaUGram(double funte); }

Interfejs se defini{e klju~nom re~i interface. Interfejs, kao i klasa pripada nekom paketu. Promenljive koje smo zadali u prvom interfejsu su dostupne izvan interfejsa. Po{to je interfejs deklarisan kao public, to su ove promenljive dostupne i izvan paketa u kome se interfejs nalazi. Po{to su static i final, ove promenljive se moraju inicijalizovati i kasnije se ne mogu menjati. Ako u definiciji interfejsa izostavite klju~nu re~ public, onda je interfejs dostupan samo u paketu u kome se nalazi. U interfejsu Konverzija, koji smo zadali smo dali samo deklaraciju svake metode. Kod za svaku od ovih metoda morate da obezbedite u klasi koja implementira ovaj interfejs. Interfejs mo`e da pro{iruje neki drugi interfejs, ondnosno da se izvede iz drugog interfejsa. Ako bismo `eleli da interfejs Konverzija izvedemo iz interfejsa FaktoriKonverzije, mogli bismo da napi{emo:
public interface Konverzija extends FaktoriKonverzije{ double inchUMM(double inchi); double uncaUGram(double unce); double funtaUGram(double funte); }

Interfejs mo`e da sadr`i vi{e drugih interfejsa.
public interface MojInterfejs extends Interfejs1, Interfejs2 { // kod }

Implementacija interfejsa
public class MojaKlasa implements FaktoriKonverzije{ double tezinaUFuntama; public doublegetTezinaUKg(){ return tezinaUFuntama * FUNTA_U_GRAM; } }

Sve konstante koje su definisane u interfejsu FaktoriKonverzije su dostupne u klasi MojaKlasa. Po{to su tipa public, mo`e im se pristupati i kao ~lanovima klase MojaKlasa. Ako `elite da implementirate interfejs koji sadr`i metode morate da za svaku metodu obezbedite kod, odnosno njeno telo. U primeru koji sledi smo implementirali interfejs Konverzija:
public class MojaKlasa implements Konverzija{ public double inchiUMM(double inchi){ return inchi * INCH_U_MM; } public double UncaUGram(double unce){ return unce * UNCA_U_GRAM; } public double funtaUGram(double funte){ return funte * FUNTA_U_GRAM; }

53

}

Svaka metoda iz interfejsa mora imati definiciju u klasi koja taj interfejs implementira. Po{to su metode interfejsa public, to i metode u klasi moraju biti deklarisane kao public. Po{to interfejs Konverzija pro{iruje interfejs FaktoriKonverzije, to su u ovoj klasi dostupne i sve promenljive koje su definisane u tom interfejsu. Ako u nekoj klasi ne `elite da implementirate sve metode interfejsa, onda morate da tu klasu deklari{ete kao apstraktnu. Kada se koriste interfejsi Interfejs je pogodan na~in za pakovanje konstanti. Interfejs sa konstantama mo`ete da kasnije iskoristite u razli~Itim klasama koje }e ga implementirati. Konstante su stativ i objekti klase ih me|usobno dele. Interfejs je tako|e na~in da se implementira polimorfizam. Kod polimorfizma je potrebno da se u osnovnoj i svim izvedenim klasama defini{e metoda sa istim zaglavljem. Ovoj metodi, koja je u razli~itim potklasama razli~ito implementirana se kasnije pristupa preko promenljive koja ukazuje na osnovnu klasu, a u zavisnosti od toga kojoj od potklasa pripada objekat, dolazi do poziva metoda iz potklasa. Sli~na funkcija se mo`e posti}i i interfejsom. Sve klase za koje `elite da se pona{aju polimorfno treba da implementiraju interfejs sa zajedni~kim metodima, a polimorfno pona{anje se posti`e pozivom promenljiva koja je tipa tog interfejsa. U primeru koji sledi smo pokazali kako preko interfejsa mo`e posti}i isto {to smo radili nasle|ivanjem klase Zivotinja i sl. Primer:
import java.util.Random; public class TestInterfejs { public static void main(String[] args) { ZivotinjaIzlaz[] zivotinje = { new Pas1("Dzoni", "Pudlica"), new Macka1("Cica", "Sijamska"), new Patka1("Daca") }; ZivotinjaIzlaz ziv; Random select = new Random(); // Random number generator for(int i = 0; i < 5; i++) { ziv = zivotinje[select.nextInt(zivotinje.length)]; System.out.println("\nIzarbali ste :\n" + ziv); ziv.zvuk(); } } } public class Pas1 implements ZivotinjaIzlaz{ public Pas1(String aIme){ ime = aIme; rasa = "Nepoznato"; } public Pas1(String aIme, String aRasa){ ime = aIme; rasa = aRasa; } public String toString(){ return "\nIme psa je " + ime + " a rasa je " + rasa; } private String ime; private String rasa;

54

// metoda za lavez public void zvuk(){ System.out.println("Av Av"); } } public class Macka1 implements ZivotinjaIzlaz{ public Macka1(String aIme) { ime = aIme; rasa = "Nepoznato"; } public Macka1(String aIme, String aRasa) ime = aIme; rasa = aRasa; } {

// Vra]a se string sa detaljima o toj macki public String toString() { return "\nIme macke je " + ime + " a rasa je " + rasa; } // metod za mjaukanje public void zvuk() { System.out.println("Mijauuu"); } private String ime; private String rasa; // ime macke // rasa

} public class Patka1 implements ZivotinjaIzlaz{ public Patka1(String aIme) { ime = aIme; rasa = "Nepoznato"; } public Patka1(String aIme, String aRasa) { ime = aIme; rasa = aRasa; } // Detalji o patkio public String toString() { return "\nIme patke je " + ime + " a rasa je " + rasa; } // metod za zvuk public void zvuk() { System.out.println("Kva kva"); } private String ime; private String rasa; }

Definicije klasa su sli~ne sa onima iz prethodnog primera. Razlika je u tome da se klase ne izvode iz klase Zivotinja, tako da nema ni poziva konstruktora za super klasu u njihovim konstruktorima. Promenjena je i metoda toString(), tako {to je izba~en poziv metode super.toString(), jer toga sada nema. Nema vi{e promenljive tip iz osnovne klase, koja se nasle|ivala u izvedenim klasama. U glavnoj klasi za implementaciju se pravi promenljiva tipa ZivotinjaIzlaz, koja ukazuje na interfejs. Ta promenljiva se koristi za skladi{tenje objekata klase koja implementira taj interfejs. To se odnosi i na potklase koje nasle|uju interfejs iz direktne ili indirektne klase.

55

Klasa mo`e da implementira vi{e interfejsa. Potrebno je ih samo navesti iza imena klase (u njenoj definiciji), i odvojiti ih zarezima. Izuzeci Izuzeci obi~no signaliziraju na pojavu gre{ke u programu. Izuzetak ukazuje na neuobi~ajen doga|aj u programu koji zaslu`uje pa`nju. Osnovna prednost signaliziranja gre{ke pomo}u izuzetka je u tome da se time kod koji rukuje gre{kom razdvaja od koda koji se izvr{ava kada se stvari odigravaju na uobi~ajeni na~in. Ne morate sve gre{ke u programu da obra|ujete kao izuzetke. Izuzeci treba da budu rezervisani za katastrofalne situacije, kada mo`e do}i do prekida rada programa. Izuzetak je u Javi objekat koji se pravi kada se u programu pojavi neka nenormalna situacija. Ovaj objekat ima ~lanove (atribute) koji bli`e opisuju prirodu problema. Izuzetak se pojavljuje kada se objekat koji identifikuje neobi~ne situacije prosledi delu programa koji je posebno napisan da bi upravljao takvim problemom. Za kod koji prima objekat izuzetka se ka`e da presre}e izuzetak. Izuzeci se mogu podeliti na ~etiri osnovne kategorije: Gre{ke u kodu ili podacima - Nastaju na primer, kod neispravnog konvertovanja objekta, kori{}enja indeksa niza koji je izvan granica, ili kod deljenja nulom. Izuzeci stanadardnih metoda - Na primer, metod substring(), klase String, mo`e dovesti do pojave izuzetka StringIndexOutOfBoundsException. Sopstveni izuzeci - Izuzeci koje sami pravite Gre{ke Jave - Gre{ke u Java Virtuelnoj Ma{ini koja interpretira Va{ program, ali se obi~no javlja kao gre{ka u Va{em kodu Tipovi izuzetaka Izuzetak je uvek instanca neke klase koja je potklasa standardne klase Throwable. Ovo va`i i za stadnardne i za sopstvene izuzetke. Svi standardni izuzeci su pokriveni sa dve direktne potklase klase Throwable, a to su klase Error i Exception. Izuzeci pokriveni klasom Error - Ovi izuzeci se odnose na stanja kada se ne o~ekuje da vi ne{to uradite i stoga i ne treba da ih presre}ete. Izuzeci pokriveni klasom Exception - Skoro svi izuzeci pokriveni ovom klasom treba da se presere}u. Izuzetak ~ine izuzeci pokriveni klasom RunTimeException. Rad sa izuzecima Ako kod mo`e da proizvede neki od izuzetaka koje treba hvatati (presretati) onda morate i da napi{ete takav kod. Prilikom pisanja tog koda imate mogu}nost da izaberete da li }e se izuzetak obraditi u istoj metodi, ili }e se proslediti metodi koja je pozvala metodu u kojoj je izuzetak nastao. Ako `elite da se gre{ka i objekat klase Exception ne obra|uju na licu mesta, odnosno `elite da ih prosledite metodi koja je pozvala tu metodu, iza definicije metode treba zadate klju~nu re~ throws i da navedete vrstu izuzetka.
double mojMetod() throws FileNotFoundException{ … }

Ovo zna~i da metoda koja poziva ovu metodu mora da ima kod koji obra|uje izuzetak tipa FileNotFoundException, ili ga mo`e proslediti dalje u hijerarhiji poziva.

56

Obrada izuzetka Izuzetak se obra|uje preko tri razli~ita bloka koda. To su blokovi try, catch i finally. Blok try okru`uje kod koji mo`e dovesti do pojave izuzetka. Kod za koji pretpostavljate da }e proizvesti izuzetak mora biti u ovom bloku. Blok catch se odnosi na kod koji obra|uje izuzetak odre|enog tipa. Blok finally se uvek izvr{ava pre nego {to se zavr{i metoda, bez obzira na to da li je do{lo do pojave izuzetka. Blok try Ako `elite da presretnete (uhvatite) izuzetak, kod se mora nalaziti u okviru bloka try. Blok try izgleda ovako:
try{ // kod koji moze dovesti do pojave izuzetaka }

Blok catch Kod koji obra|uje izuzetak se mora nalaziti u bloku catch. Ovaj blok mora slediti odmah iza bloka try, sa kodom koji dovodi do pojave izuzetka.
try{ // kod koji moze dovesti do pojave izuzetaka }catch(ErithmeticException e){ // kod koji obra|uje izuzetak }

Jedina vrsta izuzetka koju ovaj blok catch mo`e da uhvati je izuzetak tipa ArithmeticException. Parametar bloka catch mora biti tipa Throwable ili neke od potklasa koje su izvedene iz ove klase. Ako klasa koju nazna~ite ima potklase, onda taj catch blok mo`e da uhvati izuzetke tog tipa klase, ali i svih potklasa. To zna~i da mo`ete da kao arugment navedete i klasu Exception, u kom slu~aju }e se hvatati svi izuzeci. U primeru koji sledi smo prikazali pojavu i obradu izuzetka.
public class TryCatchProba { public static void main(String[] args) { int i = 1; int j = 0; try { System.out.println("Ulaz u blok try " + "i = "+ i + " j = "+j); System.out.println(i/j); // deljenje sa nulom, nastaje izuzetak System.out.println("Kraj bloka try"); } // Catch the exception catch(ArithmeticException e) { System.out.println("Doslo je do pojave izuzetka tipa ArithmeticException"); } System.out.println("Posle bloka try"); return; } }

Promenljiva j u primeru je inicijalizovana na 0, tako da postoji operacija deljenja nulom. Kada se pojavi izuzetak kontrola programa se odmah prebacuje na blok catch. Nakon {to se izvr{i kod u 57

bloku catch, izvr{avanje programa se nastavlja iskazom koji sledi iza njega. Iskazi u bloku try, koji slede iza mesta na kome je do{lo do izuzetka se ne izvr{avaju. Promenite vrednost za j na 1 i probajte ponovo. Sa blokom try treba pa`ljivo raditi. Promenljive koje defini{ete u ovom bloku, su kao i kod svih blokova, vidljive samo u okviru bloka. Blok catch je odvojen od bloka try. Ako `elite da u ovom bloku radite sa objektima koji su postavljeni u bloku try, onda te promenljive morate definisati ispred bloka try. Vi{estruki blokovi catch Ako blok try mo`e da proizvede vi{e razli~itih vrsta izuzetaka, mo`ete staviti vi{e blokva catch.
try{ // kod koji moze dovesti do izuzetka }catch(ArithmeticException e){ // kod za obradu ovog izuzetka }catch(IndexOutOfBoundsException e){ // kod za obradu ovog izuzetka }

Izvr{ava se prvi blok catch koji odgovara tipu nastalog izuzetka. Blokovi koji slede iza njega se ne izvr{avaju. Ako su dva tipa izuzetka tipa osnovne i potklase i ako je osnovna klasa u catch blokovima ispred potklase, onda se se izuzetak potklasa nikad ne}e izvr{iti. To zna~i da treba paziti na redosled iskaza catch. Ako ima vi{e catch blokova i ako na po~etak stavite klasu Exception, ne}e se izvr{iti nijedan blok catch iza ovog prvog bloka (to ne mo`e ni da se kompajlira). Blok finally Pojava izuzetka zna~i da se izvr{avanje bloka try prekida, bez obzira na kod koji se nalazi iza mesta nastanka izuzetka. Na taj na~in mo`e da se desi da neki poslovi ostanu nedovr{eni. Mogli ste, na primer, da otvorite datoteku, koja zatim ostaje nezatvorena. Blok finally omogu}ava da zavr{ite va`ne stvari koje su prekinute u bloku try. Ovaj blok se izvr{ava bez obzira na to da li se desio izuzetak ili ne. Ako treba da bude zatvorena datoteka, onda to zatvaranje treba da stavite u blok finally, ~ime obezbe|ujete da }e se taj posao uvek obaviti.
try{ // kod }catch(Exception e){ // obrada izuzetka }finally{ // zavrsni kod }

Blok try ne mo`e da postoji samostalno, Iza njega mora da ide najmanje jedan blok catch ili finally. U ve}ini slu~ajeva }ete u metodi napraviti jedan blok try, iza kojeg slede svi blokovi catch i na kraju mo`da blok finally. U primeru koji sledi smo pokazali redosled izvr{avanja razli~itih blokova try i catch. Primer:
import java.io.IOException; public class TryBlockTest{ public static void main(String[] args) { int[] x = {10, 5, 0}; // Niz od tri integera //Ovaj blok javlja izuzetak ako postoji u metodu podeli() try {

58

System.out.println("Poceo je prvi try blok u metodi main()"); System.out.println("rezultat = " + podeli(x,0)); //Nema gresaka x[1] = 0; // Dovodi do deljenja sa nulom System.out.println("rezultat = " + podeli(x,0)); // Aritmeticka greska x[1] = 1; // sprecava deljenje sa nulom System.out.println("rezultat = " + podeli(x,1)); // Greska u indeksu } catch(ArithmeticException e){ System.out.println("U metodi main() je uhvacen aritmeticki izuzetak"); } catch(ArrayIndexOutOfBoundsException e){ System.out.println("U metodi main je uhvacen izuzetak IndexOutOfBoundsException"); } System.out.println("Izvan prvog bloka try u metodi main()"); System.out.println("\nPritisnite enter za kraj"); // Ovaj blok sluzi samo za pauziranje programa pre kraja try{ System.out.println("Drugi blok try u metodi main()"); System.in.read(); // Ceka se na unos return; } catch(IOException e){ // Metod read() moze da dovede do izuzetka System.out.println("I/O izuzetak uhvacen u metodi main()"); } finally{ // Ovo se uvek izvrsava System.out.println("blok finallyza drugi blok try u metodi main"); } System.out.println("Kod u metodi main posle drugog bloka try"); } // metod za deljenje public static int podeli(int[] array, int index){ try{ System.out.println("\nUlaz u prvi blok try u metodi podeli()"); array[index + 2] = array[index]/array[index + 1]; System.out.println("Kod na kraju prvog bloka try u podeli()"); return array[index + 2]; } catch(ArithmeticException e) { System.out.println("Aritemticki izuzetak uhvacen u podeli()"); } catch(ArrayIndexOutOfBoundsException e){ System.out.println("Uhvacen izuzetak Index-out-of-bounds u podeli()"); } finally{ System.out.println("finally blok u podeli()"); } System.out.println("Izvrsavanje koda nakon bloka try u podeli()"); return array[index + 2]; } }

U metodi main() postoje dva bloka try. U metodi podeli() postoje dva bloka catch, koji se izvr{avaju ako do|e do deljenja sa nulom, ili ako se pristupi elementu sa nepostoje}im indeksom. U metodi podeli postoji i blok finally koji se uvek izvr{ava. U ovoj metodi postoji i kod koji se izvr{ava izvan svih ostalih blokova. Ovaj deo koda mo`e da dovede do izuzetka IndexOutOfBoundsException. Drugi blok try u metodi main() je potreban zato {to se u njemu poziva metoda read() objekata in, koji je ~lan klase System. U pitanju je standardni ulaz (in). Po{to ova metoda mo`e da dovede do izuzetka tipa IOException, to se ona ne mo`e pozvati bez blokova try i catch. Ako poku{ate da tako uradite kompajler }e javiti gre{ku. Prvi poziv metode podeli() u prvom bloku try ne dovodi do nikakve gre{ke, {to se i vidi iz {tampanja koja se prikazuju. 59

Drugi poziv metode podeli izaziva deljenje sa nulom. U tom slu~aju se javlja izuzetak ArithmeticException, koji se hvata u toj metodi. Tre}i poziv metode podeli() spre~ava deljenje sa nulom, ali dovodi do pojave izuzetka IndexOutOfBoundsException, koji nastaje usled koda na kraju metoda podeli (return array[index+2]). Po{to ovaj kod nije u bloku try to se taj izuzetak ne hvata u metodi podeli(). U tom trenutku metoda se prekida i izvr{avanje se nastavlja u metodi main(), koja hvata taj izuzetak. Prosle|ivanje izuzetaka Iako pomo}u bloka catch mo`ete da obradite izuzetak, ~esto se javlja potreba da se izuzetak prosledi dalje programu, koji na osnovu toga treba da preduzme neku akciju. Izuzetak se iz klauzule catch mo`e da prosledi preko iskaza throw.
try{ // kod koji dovodi pojave izuzetka }catch(ArithmeticException e){ // obrada izuzetka throw e; }

Objekti izuzetaka Objekat izuzetka koji se prosle|uje bloku catch mo`e da pru`i dosta informacija o prirordi problema i njegovom uzroku. Ovo je mogu}e preko metoda klase Throwable iz koje se izvode svi izuzeci. Objekat klase Throwable ima nekoliko metoda koje pru`aju informacije o izuzetku. To su metoda getMessage() i metode printStackTrace() i printStackTrace(PrintStream s). Metoda getMessage() vra}a poruku koja opisuje trenutni izuzetak. To je obi~no puno ime klase izuzetka i kratak opis izuzetka. Metoda printStackTrace() prikazuje poruku i pregled izvr{avanja metode. TO se prikazuje na standardnom izlazu. Pregled izvr{avanja metode sadr`i broj reda u izvornom kodu u kome se izuzetak pojavio, a iza toga sledi spisak metoda koji su prethodili izvr{enju tog koda. Ovo je vrlo va`na informacija, jer se na ovaj na~in mo`e da odredi lokacija gre{ke i naravno mesto gde treba ne{to ispraviti. Metoda printStackTrace() ima i oblik sa prosle|enim objektom PrintStream u kom slu~aju vi zadajete gde }e se to {tampati. Promenili smo prethodni primer, tako da se prika`u i informacije o mestu na kome je gre{ka nastala:
import java.io.IOException; public class TrTest1 { public static void main(String[] args) throws IOException { int[] x = {10, 5, 0}; // Niz od tri integera //Ovaj blok javlja izuzetak ako postoji u metodu podeli() try { System.out.println("Poceo je prvi try blok u metodi main()"); System.out.println("rezultat = " + podeli(x,0)); //Nema gresaka x[1] = 0; // Dovodi do deljenja sa nulom System.out.println("rezultat = " + podeli(x,0)); // Aritmeticka greska x[1] = 1; // sprecava deljenje sa nulom System.out.println("rezultat = " + podeli(x,1)); // Greska u indeksu } catch(ArithmeticException e){ System.out.println("U metodi main() je uhvacen aritmeticki izuzetak"); } catch(ArrayIndexOutOfBoundsException e){ System.out.println("U metodi main je uhvacen izuzetak IndexOutOfBoundsException"); } System.out.println("Izvan prvog bloka try u metodi main()"); System.out.println("\nPritisnite enter za kraj");

60

// Ovaj blok try sluzi za pauziranje programa pre izlaza try{ System.out.println("Drugi blok try u metodi main()"); System.in.read(); // Ceka se na unos return; } catch(IOException e){ // Metod read() moze da dovede do izuzetka System.out.println("I/O izuzetak uhvacen u metodi main()"); } finally{ // Ovo se uvek izvrsava System.out.println("blok finallyza drugi blok try u metodi main"); } System.out.println("Kod u metodi main posle drugog bloka try"); } // podeli method public static int podeli(int[] array, int index) { try { System.out.println("\nUlaz u prvi blok try u metodi podeli()"); array[index + 2] = array[index]/array[index + 1]; System.out.println("Kod na kraju prvog bloka try u podeli()"); return array[index + 2]; } catch(ArithmeticException e) { System.out.println("Aritemticki izuzetak uhvacen u podeli()\n" + "\nPoruka iz objekta exception:\n\t" + e.getMessage()); System.out.println("\nIzlaz iz metode StackTrace:\n"); e.printStackTrace(System.out); System.out.println("\nKraj izlaza iz StackTrace\n"); } catch(ArrayIndexOutOfBoundsException e) { System.out.println("Uhvacen izuzetak Index-out-of-bounds u podeli()\n" + "\nMessage in exception object:\n\t" + e.getMessage()); System.out.println("\nIzlaz iz metode StackTrace:\n"); e.printStackTrace(System.out); System.out.println("\nKraj izlaza iz StackTrace\n"); } finally { System.out.println("klauzula finally u podeli()"); } System.out.println("Izvrsavanje koda nakon bloka try u podeli()"); return array[index + 2]; } }

Sopstveni izuzeci Ve}ina standardnih izuzetaka u Javi ne pru`a dodatne informacije o stanju koje dovodi do pojave izuzetka. Ako vam je potrebno vi{e informacija o okolnostima pod kojim je do{lo do pojave izuzetka, onda mo`ete kreirati sopstvene izuzetke. Sopstvene izuzetke dodajete kada `elite da imate dodatne informacije kada se pojavi standardni izuzetak ili kada u kodu imate gre{ku koja opravdava posebnu klasu izuzetka. Sopstveni izuzeci nisu zamena za normalan kod za oporavak za koji o~ekujete da }e se ~esto izvr{avati. Ako imate kod koji se ~esto izvr{ava u ovakvim situacijama, onda ga treba ubaciti u petlju if-then-else, a ne u izuzetke. Va{e klase izuzetaka moraju da imaju kao superklasu, klasu Throwable. Najbolje je da svoje klase izvodite iz klase Exception. Promeni}emo primer koji smo ranije priakzali. Napravi}emo sopstvenu klasu za izuzetak deljenja sa nulom. Ta klasa }e bli`e obja{njavati izuzetak op{teg tipa ArithmeticException. Primer:
import java.io.IOException;

61

public class Izuzetak { public static void main(String[] args) { int[] x = {10, 5, 0}; // Niz od tri integera //Ovaj blok javlja izuzetak ako postoji u metodu podeli() try { System.out.println("Poceo je prvi try blok u metodi main()"); System.out.println("rezultat = " + podeli(x,0)); //Nema gresaka x[1] = 0; // Dovodi do deljenja sa nulom System.out.println("rezultat = " + podeli(x,0)); // Aritmeticka greska x[1] = 1; // sprecava deljenje sa nulom System.out.println("rezultat = " + podeli(x,1)); // Greska u indeksu }catch(DeljenjeSaNulomIzuzetak e){ int index = e.getIndex(); // indeks elementa koji je doveo do greske if(index > 0){ x[index] = 1; x[index + 1] = x[index - 1]; System.out.println("Deljenje sa nulom je ispravljeno za element " + x[index]); } }catch(ArithmeticException e){ System.out.println("U metodi main() je uhvacen aritmeticki izuzetak"); } catch(ArrayIndexOutOfBoundsException e){ System.out.println("U metodi main je uhvacen izuzetak IndexOutOfBoundsException"); } System.out.println("Izvan prvog bloka try u metodi main()"); System.out.println("\nPritisnite enter za kraj"); // Ovaj blok try sluzi za pauziranje programa pre izlaza try{ System.out.println("Drugi blok try u metodi main()"); System.in.read(); // Ceka se na unos return; } catch(IOException e){ // Metod read() moze da dovede do izuzetka System.out.println("I/O izuzetak uhvacen u metodi main()"); } finally{ // Ovo se uvek izvrsava System.out.println("blok finallyza drugi blok try u metodi main"); } System.out.println("Kod u metodi main posle drugog bloka try"); } // metod za deljenje public static int podeli(int[] array, int index) throws DeljenjeSaNulomIzuzetak{ try{ System.out.println("\nUlaz u prvi blok try u metodi podeli()"); array[index + 2] = array[index]/array[index + 1]; System.out.println("Kod na kraju prvog bloka try u podeli()"); return array[index + 2]; } catch(ArithmeticException e) { System.out.println("Aritemticki izuzetak uhvacen u podeli()"); throw new DeljenjeSaNulomIzuzetak(index + 1); } catch(ArrayIndexOutOfBoundsException e){ System.out.println("Uhvacen izuzetak Index-out-of-bounds u podeli()"); } finally{ System.out.println("finally blok u podeli()"); } System.out.println("Izvrsavanje koda nakon bloka try u podeli()"); return array[index + 2]; }

62

} public class DeljenjeSaNulomIzuzetak extends Exception{ private int index = -1; // indeks elementa niza koji dovodi do greske // podrazumevani konstrktor public DeljenjeSaNulomIzuzetak(){ } // Standardni konstruktor public DeljenjeSaNulomIzuzetak(String s) { super(s); // Poziv konstruktora osnovne klase } public DeljenjeSaNulomIzuzetak(int index){ super("/ sa nulom"); // Poziv osnovnog konstruktora this.index = index; // Podesavanje indeksa } // Uzimanje indeksa za koji se desila greska public int getIndex() { return index; // Return the index value } }

Promenili smo metod podeli() iz prethodnog primera, tako {to smo definisali da on mo`e da prosledi izuzetak tipa DeljenjeSaNulomIzuzetak (throws u zaglavlju metoda). Promenili smo i kod za hvatanje gre{ke u ovom metodu, i to tako {to smo dodali iskaz
throw new DeljenjeSaNulomIzuzetak(index+1)

Ovaj iskaz generi{e novi izuzetak sa vi{e detalja i prosle|uje ga metodi odakle je metoda podeli pozvana. U metodi main smo dodali blok catch za obradu novog tipa izuzetka (ispred ArithmeticException) i u tom kodu smo promenili element koji je doveo do problema. Ulaz i izlaz u Javi Ulazne i izlazne operacije se u Javi realizuju pomo}u tokova. Tok je apstraktna prezentacija ulaznog ili izlaznog ure|aja, koji predstavlja izvor ili odredi{te podataka. U tok mo`ete da upisujete podatke i iz njega mo`ete da podatke ~itate. Tok se mo`e shvatiti kao niz bajtova koji teku u i iz programa. Kada podatke upisujete u tok, tok se naziva izlaznim tokom. Izlazni tok mo`e biti datoteka na disku, datoteka na drugom ra~unaru, {tampa~ i sl. Izlazni tok mo`e biti i monitor. Podaci se ~itaju iz ulaznog toka. Obi~no je u pitanju datoteka na disku, ili drugom ra~unaru ili tastatura. Samo Java aplikacije mogu da koriste tokove na ma{ini na kojoj se program izvr{ava. Oni obi~no nisu dostupni apletima. Osnovni razlog za upotrebu tokova u Javi je da se obezbedi nezavisnost programskog koda u odnosu na ure|aj koji se koristi. Prednost je u tome da ne morate brinuti o detaljima svakog od ure|aja, kao i da }e program raditi sa razli~Itim ulazno/izlaznim ure|ajima bez promene koda. Vrste tokova Ve}ina klasa koje su potrebne za manipulaciju tokovima se nalaze u paketu java.io. Ovaj paket podr`ava binarne tokove, koji sadr`e binarne podatke i znakovne tokove, koji sadr`e tokove znakova. Ako u tok pi{ete podatke kao niz bajtoba, podaci se upisuju isto onako kako se nalaze i u memoriji. Nema nikakve transformacije podataka. Znakovni tokovi se koriste za skladi{tenje i ponovno dobijanje teksta. Koriste se i za ~itanje tekstualnih datoteka koje nisu nastale iz Jave. 63

Klase za ulaz i izlaz U paketu java.io se nalaze slede}e osnovne klase za podr{ku ulazno izlaznih tokova. Klasa File OutputStream InputStream Writer Reader Opis Objekat ove klase predstavlja putanju do datoteke kojoj pristupate za ulaz ili izlaz. Mo`e da se odnosi i na direktorijum Osnovna klasa za izlazne operacije toka bajtova Osnovna klasa za ulazne operacije toka bajtova Osnovna klasa za izlazne operacije toka znakova Osnovna klasa za ulazne operacije toka znakova

Klase InputStream, OutputStream, Reader i Writer su apstraktne klase. Iz apstraktnih klasa se ne mogu praviti instance klase. Ove klase se korsite samo kao osnova za izvo|enje drugih klasa sa konrkretnim mogu}nostima. U ove ~etiri klase su me|utim, definisani osnovni metodi koji se koriste za ulazno/izlazne operacije. Tokovi datoteka koji se defini{u pomo}u klasa koje se izvode iz ove ~etiri navedene klase su po svojoj prirodi sekvencijalni. Ako `elite da datoteci i zapisima u njoj pristupate po slu~ajnom principu, morate da koriste klasu RadnomAccessFile. Definisanje datoteke Objekat File predstavlja putanju do fizi~ke datoteke ili direktorijuma na disku, a ne sam tok. Pored toga {to omogu}ava da napravite objekat koji predstavlja putanju do datoteke, u ovoj klasi se nalaze i nekoliko metoda koji omogu}avaju testiranje objekata koje pravite. Najjednostavniji na~in kreiranja objekta je preko konstruktora, koji kao arugment prihvata objekat tipa String, koji odre|uje putanju do datoteke ili direktorijuma.
File mojDir = new File(“F:/jdk1.3/src/java/io”);

Kod Windows operativnih sistema, umesto znaka “/” mo`ete koristiti i ‘\\’. Ako `elite da dobijete putanju do datoteke morate da obezbedite da prosle|eni string ukazuje na datoteku.
File mojaDatoteka = new File(“F:/jdk1.3/src/java/io/File.java”);

Ovaj objekat sada ukazuje na datoteku sa izvornim kodom koja sadr`i definiciju klase File. Ako `elite putanju do datoteke mo`ete da napravite i preko druge verzije konstruktora za klasu File. U toj verziji se {alju dva argumenta. Prvi argument je drugi objekat File koji ukazuje na direktorijum, a drugi argument je ime datoteke na tom direktorijumu.
File mojDir = new File(“F:/jdk1.3/src/java/io”)’ File mojaDatoteka = new File(mojDir, “File.java”);

Ovaj pristup je zgodan kada `elite da radite sa vi{e datoteka koje se nalaze u istom direktorijumu. U primeru koji sledi smo pokazali kako se preko objekta File mogu dobiti informacije o odre|enom direktorijumu i datotekama u njemu. Primer:
import java.io.*; public class TryFile{ public static void main(String[] args){ // Kriera se direktorijum (objekat koji sadrzi ptanju do njega) File myDir = new File("d:/temp"); System.out.println(myDir + (myDir.isDirectory()?" is":" is not") + " a directory.");

64

// Kreira se datoteka (objekat koji ukazuje na nju) File myFile = new File(myDir, "prikaz.doc"); System.out.println(myFile + (myFile.exists()?" does":" does not") + " exist"); System.out.println("You can" + (myFile.canRead()?" ":"not ") + "read " + myFile); System.out.println("You can" + (myFile.canWrite()?" ":"not ") + "write " + myFile); return; } }

Izlazni tokovi Izlazni tokovi bajtova se opisuju preko klase OutputStream i onih koje se iz nje izvode. Sve klase koje se izvode iz ove klase }e naslediti metode koje postoje u ovoj klasi. Potklase ove klase su FileOutputStream, ByteArrayOutputStream, PipedOutputStream, FilterOutputStream. Klasa FileOutputStream defini{e izlazni tok kao datoteku. Klasa ByteArrayOutputStream je izlazni tok koji podatke upisuje u niz bajtova. Klasa PipedOutputStream dodaje podatke u izlazni tok koji je namenjen za kori{}enje sa objektom PipedInputStream. Klasa FilterOutputStream je osnovna klasa za izvo|enje klasa koje pro{iruju mogu}nosti ostalih klasa. Izlazni tokovi znakova omogu}avaju pisanje znakovnih podataka. Unicode znakovi se automatski prebacuju u kod koji koristi ra~unar na kome se program izvr{ava. Sve klase koje omogu}avaju rad sa znakovima se izvode iz apstraktne klase Writer. Potklase ove klase su: StringWriter - pi{e se u String CharArrayWriter - pi{e se u niz tipa char PipeWriter - pi{e se u PipeReader OutputStreamWriter - pi{e se u OutputStream FileWriter - pi{e se u File PrintWriter - pi{e se u Writer BufferedWriter - pi{e se u spremi{te FilterWriter - apstraktna osnova za Filter. Klasa Writer defini{e slede}e metode. Ovi metodi se nasle|uju u njenim potklasama. write (int c) - Pi{e znak c u izlazni tok. Povratni tip je void. write (char[] cArray) - u tok se pi{e znakovni niz write char[] cArray, int offset, int length) - u tok se iz niza cArray pi{e length znakova, po~ev od elementa sa indeksom offset. write (String str) - u tok se pi{e string write (String str, int offset, int length) - iz stringa str u tok pi{e length znakova, po~ev od pozicije offset. Ako do|e do gre{ke ove metode proizvode izuzetak tipa IOException.

65

U ovoj klasi postoje i metode flush() i close(). Metoda flush() se koristi kada `elite da zavr{ite niz izlaznih operacija nad tokom (tako {to se prebacuju podaci koji su jo{ uvek unjemu). Metodu close() pozivate kada `elite da zavr{ite sve operacije i da prekinete vezu sa tokom. Pisanje u datoteku Za zapisivanje u tekstualnu datoteku mo`ete da koristite klasu FileWriter. Ova klasa ima konstruktor koji kao argument prihvata objekat tipa File. U primeru koji sledi }emo u datoteku dodati tekst. Primer:
import java.io.*; public class WriteCharacters{ public static void main(String[] args) { try { String dirName = "d:\\kurs\\"; // Direktorijum za izlaznu datoteku String fileName = "Proba.txt"; // Ime izlazne datoteke File output = new File(dirName, fileName); output.createNewFile(); // Ako je potrebno pravi se nova datoteka if(!output.isFile()){ // PRoverava se da li postoji datoteka System.out.println("Kreiranje datoteke " + output.getPath() + " nije uspelo."); return; } BufferedWriter out = new BufferedWriter( new FileWriter(output.getPath(), true)); String[] sayings = { "Prvi red u datoteci\n", "Drugi red u datoteci.\n", "Treci red u datoteci\n", "Cetvrti red u datoteci\n"}; // Zapisuje se u datoteku. Ispred se pi[e du`ina stringa for(int i = 0; i < sayings.length; i++){ out.write(sayings[i].length() + sayings[i]); } out.close(); }catch(IOException e){ System.out.println("Greska u pisanju u datoteku " + e); } } }

Na po~etku programa se kreira objekat File koji predstavlja putanju do datoteke koju `elimo da napravimo (direktorijum d:\\kurs i datoteka Proba.txt). Nakon toga smo na osnovu objekta FileWriter napravili objekat BufferedWriter, koji }e podatke dodavati u izlaznu datoteku. Obratite pa`nju na drugi argument (true) u konstruktoru klase FileWriter, koji govori da se u tu datoteku dodaju zapisi. Ako bi vrednost ovog atributa bila false, onda se bi se datoteka uvek pravila iznova. Ulazni tokovi Sve klase izvedene iz klase InputStream nasle|uju metode: read() - slu`i za ~itanje jednog bajta podataka iz toka i da vrati tip int. read(byte[] buffer) - ~ita se dovoljno bajtova da se popuni niz buffer ili dok se ne do|e do kraja niza. skip(long n) - koristi se za preskakanje dela datoteke koji ne `elite da obradite mark(int readlimit) - obele`ava trenutnu poziciju, tako da se kasnije pomo}u metode reset() mo`ete vratiti na nju. 66

reset() - pozicionira tok na mesto definisano prethodnim pozivom metode mark(). Postoje i druge metode. Potklase klase InputStream FileInputStream - ~itanje iz datoteke SequenceInputStream - omogu}ava spajanje vi{e ulaznih tokova u jedinstveni tok PipedInputStream - ~itanje iz toka koji dolazi iz objekta PipedOutputStream ByteArrayInputStream - - ~ita podatke iz niza bajtova FilterInputStream - Osnovna klasa za filtriranje ObjectInputStream - ~itanje iz toka sa objektima Ulazni tok znakova Ulazne operacije obezbe|uju klase koje se izvode iz klase reader. Ovaj objekat se koristi za ~itanje toka napisanog preko klase Writer. U primeru koji sledi smo pro~itali datoteku koju smo napravili u prethodnom primeru. Izlaz smo od{tampali na ekranu. Primer:
import java.io.*; public class CitanjeIzDatoteke { public static void main(String[] args) try { String dirName = "d:\\kurs\\"; String fileName = "Proba.doc";

{

File input = new File(dirName, fileName); BufferedReader in = new BufferedReader(new FileReader(input)); int c; StringBuffer buf = new StringBuffer(); while((c = in.read()) != -1){ buf.append((char)c); } System.out.println(buf.toString()); } catch(FileNotFoundException e){ System.err.println(e); return; } catch(IOException e){ System.err.println("Error reading input file" + e ); return; } } }

Datoteku ~itamo jedan po jedan karakter. Metod read() objekta BufferedReader ~ita jedan po jedan karakter i vra}a njegovu int prezentaciju. Ako je dostignut kraj datoteke vra}a -1. Taj karakter koji se vra}a pretvaramo u tip char i zatim dodajemo u objekat StringBuffer. Kada se petlja zavr{i {tampa se string koji se nalazi u StringBuffer objektu. Skladi{tenje objekta u datoteku Proces sme{tanja objekta u datoteku se naziva serijalizacijom. ^itanje objekta iz datoteke se naziva deserijalizacijom. Za serijalizaciju i deserijalizaciju objekata se koriste klase ObjectOutputStream i ObjectInputStream. Ove klase su izvedene iz klasa DataOutputStream i DataInputStream, tako da ove klase poseduju sposobnost obrade osnovnih tipova, a sve to preko nasle|enih metoda. Upisivanje objekta u datoteku 67

Konstruktor klase ObjectOutputStream kao argument zahteva objekat klase FileOutputStream. Ovaj objekat defini{e tok za datoteku u koju nameravate da smestite svoj objekat.
FileOutputStream izlaz = new FileOutputStream(“Proba”); ObjectOutputStream objectOut = new ObjectOutputStream(izlaz);

Pisanje u datoteku proba mo`ete da izvr{ite preko metode writeObject(), klase ObjectOutputStream, pri ~emu se objekat o kome se radi prosle|uje kao argument. Ovoj metodi mo`ete da prosledite objekat bilo koje klase. Da bi se objekat mogao da zapisuje u tok na ovaj na~in klasa mora da zadovoljava tri osnovna uslova: Klasa mora biti deklarisana kao public Klasa mora da implementira interfejs Serializable Ako klasa ili potklasa ima direktnu ili indirektnu potklasu koja se ne mo`e serijalizovati, onda ta osnovna klasa mora imati podrazumevani kosntruktor (koji ne zahteva nijedan argument). Ako su prethodni uslovi zadovoljeni, onda se upisivanje objekta u tok koji je ranije definisan mo`e uraditi na slede}i na~in:
objectOut.writeObject(mojObjekat);

Prilikom upisivanja se vodi ra~una o tome da se upi{e sve {to je potrebno da bi se objekat, kasnije u operaciji ~itanja mogao da rekonstrui{e. Tu su i informacije o klasi i svim njenim supreklasama, kao i sadr`aj i tipovi ~lanova klase. Ovo radi ~ak i kada su ~lanovi klase drugi objekti, sve dok se ti drugi objekti mogu serijalizovati. Nezavisni objekti se u tok zapisuju posebnim pozivom metode writeObject(), ali se objekti koji su ~lanovi drugog objekta zapisuju automatski. Metod writeObject() koji smo mi pozvali }e dalje pozvati istoimene metode za sve objekte koji su ~lanovi podaci. Svaki nezavisan objekat koji zapisujete zahteva poseban poziv metode, ali se sa objektima koji su ~lanovi klase, to radi automatski. Implementacija interfejsa Serializable U klasu za koju `elite da implementira interfejs Serializable treba dodati slede}i kod:
public MojaKlasa implements Serializable{ // definicija klase }

Sva polja u klasi moraju biti takva da se mogu serijalizovati, {to zna~i da moraju biti osnovnog tipa ili tipa klase koja se mo`e serijalizovati. ^lanovi klase deklarisani kao transient Ako klasa ima ~lanove podatke koji se ne mogu serijalizovati, ili koje ne `elite da upi{ete u tok, onda treba da ih ozna~ite sa transient.
public MojaKlasa implements Serializable{ transient protected Graphics g;// tranzientan ~lan }

Ako ste neki ~lan deklarisali sa transient, onda metoda writeObject() ne}e poku{ati da taj ~lan upisuje u tok. Kada se objekat klase ponovo u~ita, on }e biti ispravno konstruisan, uklju~uju}i i ~lanove koji su deklarisani kao transient. Vrednosti tih ~lanova ne}e biti iste kao pre slanja u datoteku, po{to se u datoteku nisu ni zapisivale. Ovo se mo`e koristiti za vrednosti koje nisu bitne, kao {to je na primer trenutno vreme ili teku}i datum, koji uvek treba da budu postavljeni na trenutnu vrednost. Njih treba eksplicitno rekonstruisati kada se objekat u~itava iz toka. ^itanje objekta iz datoteke Najpre treba napraviti objekat ObjectInputStream. Nakon toga se mo`e pozvati metoda readObject() za taj objekat. Ova metoda vra}a tip Object, koji dalje treba pretvoriti u odgovaraju}i tip. 68

Primer: Objekat tipa MojaKlasa se iz datoteke mo`e u~itati na slede}i na~in:
MojaKlasa obj; // ovde se skladisti objekat try{ // konstruise se objekat ulaznog toka za datoteku po imenu MojaDatoteka FileInputStream ulaz = new FileInputStream(“MojaDatoteka”); ObjectInputStream objectIn = new ObjectInputStream(ulaz); // deserijalizacija objekta obj = (MojaKlasa) objectIn.readObject(); }catch(IOException e){ System.out.println(e); }catch(ClassNotFoundException e){ System.out.println(e); }

Po{to metoda readObject() mo`e izazvati i izuzetke koji su potklasa klase IOException i izuzetak ClassNotFoundException, to se moraju napisati najmanje ova dva catch bloka. Pomo}ne klase U paketu java.util se nalazi skup klasa op{te namene, koje se koriste za razli~ite stvari. Tu se nalaze razli~ite klase kontejneri, zatim klase za rad sa datumima, kao i neke klase za obradu stringova. Klase kolekcija Kolekcija je op{ti termin za objekat u kome se nalazi skup objekata koji su na neki na~in grupisani. Postoje tri osnovna tipa kolekcija. To su skupovi, sekvence i mape. Kada se u Javi pomene kolekcija misli se na kolekciju referenci na objekte, a ne sa kolekciju samih objekata. Objekti su u odnosu na kolekciju spolja{nji objekti. Skupovi su najjednostavnije kolekcije. Objekti u njima nisu pore|ani na odre|eni na~in i jednostavno se u sme{taju u skup bez ikakve kontrole sme{tanja. Ovo je kao kada ne{to stavljate u d`ep. Jednostavno stavite unutra i stvari se izme|aju bez ikakvog reda. Sekvence su kolekcije u koje se objekti sme{taju na linearan na~in, sa po~etkom i krajem. Obi~an niz je primer za kolekciju, ali je ograni~ene veli~ine. Va`na osobina kolekcija je da one mogu da se {ire i da prihvate onoliko elemenata koliko je potrebno. Po{to je lista (sekvenca) linearna, u nju mo`ete da objekat dodajete na po~etak, na kraj ili da ga ubacujete ispred odre|enog objekta. Objekat iz liste se mo`e izvaditi na nekoliko na~in. Mo`e se dobiti prvi, ili poslednji objekat, zatim objekat na zadatoj poziciji (preko indeksa, kao u nizu), ili se mo`e tra`iti objekat koji je identi~an zadatom objektu. U ovom poslednjem slu~aju se proveravaju svi objekti koji se nalaze u listi. Mape se razlikuju od skupova i sekvenci po tome {to sadr`e parove objekata. Mapa se ponekad naziva i re~nikom, zbog na~ina na koji radi. Svaki objekat koji se sme{ta u mapu ima pridru`en drugi objekat, klju~. Ova dva objekta se u mapu sme{taju kao par. Klju~ odre|uje gde je objekat sme{ten u mapi. Objektu u map{i pristupate preko tog klju~a. Ovo je ekvivalentno re~i koju tra`ite u obi~nom re~niku. Klju~ mo`e biti bilo koja vrsta objekta. Svi klju~evi u mapi moraju biti razli~iti. Ako na primer, pravite program za imenik i `elite da imate sve detalje o nekoj osobi (adresa, ime, broj telefona ..) u jednom objektu, kome se kasnije pristupa preko klju~a, onda taj klju~ mo`e da bude na primer, ime osobe, ili jo{ bolje mati~ni broj, za koji smo sigurni da je jedinstven. Mesto sme{tanja objekta u map{i se odre|uje procesom he{iranja. He{iranje obra|uje objekat klju~a i pravi celobrojnu vrednost koja se zove he{ kod. Idealno je kada he{iranje proizvodi vrednosti koje su uniformno raspore|ene u odre|enom opsegu. Svaki klju~ treba da proizvede razli~it he{ kod. U paketu java.util postoji devet klasa koje se mogu koristiti za rukovanje kolekcijama objekata. U pitanju su liste, skupovi i mape. Pomenu}emo samo neke od njih.

69

Klase koje se koriste za implementaciju povezanih listi i koje se najvi{e koriste su Vector, ArrayList i LinkedList. Klasa Vector implementira listu koja automatski pove}ava svoj kapacitet da bi se prihvatili novi elementi. Objekti se sme{taju i vade iz kolekcije putem indeksa, kao i u obi~nom nizu. Elementima vektora se mo`e pristupati i preko interfejsa iterator. Vector je jedina klasa koja je sinhronizovana, odnosno dobro radi kada joj se istovremeno pristupa iz vi{e niti. ArrayList implentira niz objekata kome se mo`e menjati veli~ina i kome se mo`e pristupati i kao povezanoj listi. Radi isto kao klasa Vector, ali nije sinhronizovana. LinkedList implementira povezanu, ulana~anu listu. Ovo je tip kolekcije nazvan lista ili sekvenca. Objekti se sme{taju na linearan na~in Klasa Hashtable implementira mapu u kojoj klju~evi ne smeju biti null vrednosti. Klasa HashMap implementira mapu koja dozvoljava sme{tanje null objekata i dozvoljava da klju~ bude null (samo jedan, jer klju~evi moraju biti jedinstveni). Rad sa kolekcijom Vector Klasa Vector predstavlja kolekciju elemenata tipa Object. Funkcioni{e sli~no kao niz, ali mo`e da automatski raste i time se prilago|ava potrebnom kapacitetu. Po{to sadr`i element tipa Object, u nju se mo`e sme{tati objekat bilo kojeg tipa. To je i potencijalna opasnost da se unutra na|u klase razli~Itih tipova, {to mo`e da dovede do problema prilikom rada sa takvim vektorima. Klasa Vector ima ~etiri konstruktora. Podrazumevani konstruktor pravi prazan objekat klase Vector sa kapacitetom da se primi 10 objekata. Ako je Vector pun, odnosno ako je dostignut njegov kapacitet, onda se prilikom dodavanja novog elementa pove}ava kapacitet. Podrazumevani rast objekta, ako se kapacitet {iri radi primanja novih ~lanova je 10. Vector transakcija = new Vector(); Kapacitet objekta Vector se mo`e eksplicitno da podesi prilikom kreiranja objekta. Vector transakcija = new Vector(100); Ovaj vektor inicijalno ima kapacitet da primi 100 objekata. Svaki put kada se popuni, ako se `eli dodavanje novog elementa, kapacitet se duplira. Proces dupliranja kapaciteta, mo`e biti prili~no neefikasan. Ako na primer, u Vector koji smo malopre definisali smestimo 7000 objekata, on }e realno imati prostor za 12800 objekata. Ovo zna~i da je nepotrebno zauzeto dosta memorije. Ovo se mo`e izbe}i navo|enjem iznosa za koji Vector treba da se pove}a. U pitanju je slede}i konstruktor: Vector transakcija = new Vector(100, 10); Ovaj objekat ima inicijalni kapacitet od 100, ali }e se kapacitet svaki put uve}avati za samo 10 elemenata. Ovo ne zna~i treba i}i u drugu krajnost i pove}avati kapacitet svaki put samo za 1, jer je proces pove}anja zahteva vreme, {to mo`e da uti~e na efikasnost programa. Primer: import java.util.*;
public class TryVector { public static void main(String[] args) { Vector imena = new Vector(); String[] ime = { "Dragan", "Novica", "Petar", "Lazar", "Milan", "Nikola"}; for(int i = 0 ; i<ime.length ; i++) imena.add(ime[i]); for(int i = 0 ; i<imena.size() ; i++)

70

System.out.println((String)imena.get(i)); } }

Sme{tanje objekata u vektor Objekti se u vektor sme{taju metodom add. transakcije.add(element); Ovim se u vektor transakcija dodaje referenca na objekat element. Ovo se dodaje na kraj. Veli~ina objekta klase Vector se pri tome pove}ava za jedan. Svi objekti koji su pre toga bili u vektoru ostaju na svojim mestima. Postoji i verzija metode add() koja prima dva argumenta. Prvi argument je indeks koji ozna~ava poziciju, a drugi je objekat koji treba uvrstiti. Vrednost indeksa mora biti manja ili jednaka veli~ini objekta klase Vector. Indeks se broji isto kao od niza, po~ev od 0. transakcije.add(2, elementNovi); Prethodni iskaz u vektor transakcija ubacuje element elementNovi i to na tre}u poziciju. Objekat koji je pre toga bio na tre}oj poziciji se sada pomera na ~etvrtu, ~etvrti na petu itd. Ako navedete vrednost indeksa koja je negativna ili ve}a od veli~ini, javlja se izuzetak ArrayIndexOutOfBoundsException. Promenu elementa u vektoru je mogu}e uraditi preko metoda set(). Ovaj metod prihvata dva argumenta. Prvi argument je indeks pozicije na koju se sme{ta objekat koji se zadaje kao drugi argument. Tre}i element u objektu transakcija, klase Vector }ete promeniti na slede}i na~in: transakcije.set(2, noviElement); Metod vra}a referencu na objekat koji je prethodno bio na toj poziciji. Izvla~enje objekata iz vektora Ako znate indeks elementa u vektoru, mo`ete ga izvaditi preko metode get(). Transakcija trans = (Transakcija) transakcije.get(4); Ovim se izvla~i peti element vektora. Ovde je neophodna eksplicitna konverzija. Pristupanje elementima preko iteratora Elementima vektora se mo`e pristupati preko iteratora koji se mo`e dobiti iz klase Vector. Ovaj metod obi~no ima prednost u odnosu na metodu get() klase Vector. Referenca na iterator se dobija pozivom metode iterator, klase Vector. Iterator it = imena.iterator(); Ova metoda vra}a objekat Iterator, koji se mo`e koristiti za prolaz kroz sve elemente vektora. Mo`e se koristiti i objekat ListIterator. Pomo}u ovog metoda mo`ete i}i unapred i unazad kroz vektor. ListIterator lt = imena.listIterator(); Mogu}e je dobiti i ListIterator koji obuhvata samo deo vektora. Tom prilikom se poziva druga verzija metode listIterator, koja kao argument prihvata indeks pozizcije prvog elementa vektora, koji treba da se na|e u iteratoru. ListIterator lt = imena.listIterator(2); Ovim se dobija ListIterator koji obuhvata elemente po~ev od elementa na poziciji 2. Argument ne sme biti negativan. Brisanje elemenata iz vektora 71

Referencu na element koji se nalazi na odre|enoj poziciji u vektoru mo`ete da izbacite pomo}u metode remove(). Ona kao argument prima indeks koji ozna~ava poziciju objekta. transakcije.remove(3); Uklanja se element koji se nalazi na poziciji 3. Metoda vra}a referencu na objekat koji se uklanja. Pretra`ivanje vektora Indeks pozicije objekta koji se nalazi u vektoru se mo`e dobiti pomo}u metode indexOf(). Ovom metodu se kao argument prosle|uje referenca objekta, ~iji se indeks tra`i. int pozicija = transakcije.indexOf(element); Prilikom pretra`ivanja se koristi metoda equals(), tako da Va{a klasa treba da ima odgovaraju}u implementaciju ove metode. U primeru koji sledi smo napisali program koji modelira skup ljudi u koji se mogu, sa tastature, dodavati nove osobe. Primer:
import java.util.*; public class TryVector { public static void main(String[] args) { Vector imena = new Vector(); String[] ime = { "Dragan", "Novica", "Petar", "Lazar", "Milan", "Nikola"}; for(int i = 0 ; i<ime.length ; i++) imena.add(ime[i]); ListIterator lt = imena.listIterator(); while(lt.hasNext()){ System.out.println((String)lt.next()); } int l = imena.indexOf("Nikola"); System.out.println(l); } }

Klase za datum i vreme U paketu java.util se nalaze klase koje omogu}avaju da radite sa datumom i vremenom. To su klasa Date, klasa Calendar i klasa GregorianCalendar. Objekat klase Date defini{e odre|eni vremenski trenutak, sa ta~no{}u do milisekunde, ali mereno od 1 januara 1970-e godine. Po{to se ovo meri u odnosu na odre|eni datum, to je i to {to se dobija tako|e datum. Klasa GregorianCalendat ima metode za dobijanje dana, meseca i godine iz datuma, a tu jo{ neke korisne metode. Objekat kalendara je uvek postavljen na odre|eni datum, ali ga mo`ete i promeniti. Klasa Date Ova klasa ima dva konstruktora. To su podrazumevani konstruktor, bez argumenata, i konstruktor sa jednim argumentom tipa long. Date() - ovaj konstruktor pravi objekat na osnovu teku}eg vremena sa sata Va{eg ra~unara (sa ta~no{}u do milisekunde). Date (long time) - pravi se objekat na osnovu vremena (u milisekundama) po~ev od 1 januara 1970 godine. Klasa Date ima i neke korisne metode za pore|enje datuma. To su: after (Date prethodni) - vra}a true ako je teku}i objekat datum koji je kasniji od onog koji je prosle|en argumentom prethodni), u suprotnom vra}a false. 72

before(Date kasniji) - vra}a true, ako teku}i objekat predstavlja datum koje je raniji od onog koji je prosle|en kao argument. equals(Object datum) - vra}a true ako teku}i objekat i argument predstavljaju isti datum i vreme, u suprotnom vra}a false. Ovo zna~i da }e oba objekta da vrate istu vrednost preko metoda getTime(). Formatiranje datuma Podrazumevana vrednost za ispisivanje datuma je u skladu sa vremenskom zonom koja je pode{ena na ra~unaru na kojem se radi. Ako se `eli format datuma u skladu sa odre|enom lokacijom, mo`e se koristiti klasa SimpleDateFormat koja se nalazi u paketu java.text. Jedan od konstrktora ove klase, kao argument prihvata `eljeni format datuma. Svaki datum koji se kasnije prosledi metodi format iz ove klase se formatira prema tim pravilima.
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("dd-MM-yyyy"); System.out.println(sdf.format(dt));

Ovim se datum {tampa u formatu dan-mesec-godina. Ako `elite da iz stringa dobijete datum, mo`ete da upotrebite funkciju parse, iz klase SimpleDateFormat. Za prethodno pode{en format datum, mo`emo da napi{emo:
dt2 = sdf.parse("03-05-2002");

Dobi}e se novi datum. Ovo je korisno kada se sa odnekud (na primer, sa HTML strane) dobije datum u obliku stringa, od kojeg kasnije treba napraviti datum. Kako funkcija parse mo`e da proizvede izuzetak tipa ParseException, to se ovaj izuzetak mora da uhvati, ina~e }e kompajler da prijavi gre{ku. Klase za kalendare Kalendar je klasa koja sadr`i razli~ite pomo}ne funkcije za manipulaciju datumima. Mo`e da se koristi apstraktna klasa Calendar, ali i klasa GregorianCalendar, od koje je mogu}e praviti instance. U klasi GregorianCalendar postoji vi{e konstruktora. Podrazumevani konstruktor (bez argumenata) kreira novi kalendar i njegov datum postavlja na teku}i trenutak. GregorianCalendar cal = new GregorianCalendar(); Iz ovog objekta mo`ete da dobijete teku}i datum pozivom metoda getTime(). Date sada = cal.getTime(); Ako `elite da kalendar postavite na neki odre|eni datum, postoji metoda setTime(), koja kao argument prihvata objekat klase Date.
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("dd-MM-yyyy"); GregorianCalendar cl = new GregorianCalendar(); dt2 = sdf.parse("03-05-2002"); cl.setTime(dt2);

U klasi GregorianCalendar postoje polja koja odgovaraju danima u nedelji, danima u godini, mesecima u godini, godini i sl.
System.out.println("Dan u mesecu je " + cl.get(cl.DAY_OF_MONTH));// dan u mesecu System.out.println("MEsec u godini je " + (cl.get(cl.MONTH)+1));//mesec u godini System.out.println("Godina je " + cl.get(cl.YEAR));// godina

Kalendar poseduje i korisne funkcije koje omogu}avaju sabiranje i oduzimanje datuma. Na primer, ako `elite da datumu dodate 14 godina, mo`ete da napi{ete:
cl.add(cl.YEAR, 14);

Ako `elite da se vratite u pro{lost, treba da navedete negativan argument. 73

cl.add(cl.MONTH, -5);

Ovim ste se vratili u pro{lost za pet meseci. Primer:
package proba; import java.util.*; public class Datumi { public static void main(String[] args) { long vreme = System.currentTimeMillis(); Date dt2 = null; Date dt = new Date(); Date dt1 = new Date(vreme); System.out.println(" dt = " + dt.toString()); System.out.println(" dt1 = " + dt1.toString()); java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("dd-MM-yyyy"); System.out.println(sdf.format(dt)); GregorianCalendar cl = new GregorianCalendar(); dt2 = cl.getTime(); System.out.println(" dt2 = " + dt2.toString()); try{ dt2 = sdf.parse("03-05-2002"); System.out.println(" dt2 = " + dt2.toString()); }catch(Exception e){ System.out.println(" izuzetak"); } cl.setTime(dt2); System.out.println(" novo vreme je = " + cl.getTime()); System.out.println("Dan u mesecu je " + cl.get(cl.DAY_OF_MONTH));// dan u mesecu System.out.println("MEsec u godini je " + (cl.get(cl.MONTH) + 1));// mesec u godini System.out.println("Godina je " + cl.get(cl.YEAR));// godina cl.add(cl.YEAR, 14); System.out.println(" novo vreme je = " + cl.getTime()); cl.add(cl.MONTH, -5); System.out.println(" novo vreme je = " + cl.getTime()); } }

U primeru je pokazano kako se koriste klase koje smo u prethodnom tekstu pomenuli. Za kreiranje datuma se koristi klasa Date, za formatiranje datuma klasa SimpleDateFormatter i za rad sa vi{e datuma, klasa GregorianCalendar. Klasa StringTokenizer Ova klasa omogu}ava da se zadati string podeli na tokene, na osnovu unapred zadatog delimitera. Klasa ima nekoliko konstruktora. StringTokenizer(String s) Ovaj konstruktor kreira StringTokenizer koji iz stringa s mo`e da vadi pojedine tokene. Koriste se podrazumevani delimiteri, kao {to su blanko karakter, tabulator ili novi red. Delimiteri se ne vra}aju. Drugi konstruktor tako|e kreira tokenizer koji mo`e da razla`e string, ali se posebno zadaje delimiter. StringTokenizer(String s, String delim) 74

Delimiter se ne vra}a kao deo tokena. Tre}i konstruktor kreira tokenizer koji mo`e da razla`e zadati string, zadaje se delimiter, ali se zadaje jo{ jedan argument koji ukazuje na to da li se delimiter vra}a kao deo tokena koji se dobijaju iz stringa. StringTokenizer (Strings, String delim, boolean returnDelimiter) Ako je vrednost argumenta returnDelimiter pode{ena na true, onda se i delimiter vra}a kao deo tokena.
String s = "Recenica koja se tokenizuje.|Druga recenica."; StringTokenizer stok1 = new StringTokenizer (s); StringTokenizer stok2 = new StringTokenizer (s, "|"); StringTokenizer stok3 = new StringTokenizer (s, " |", true);

Promenljiva stok1 ukazuje na StringTokenizer koji iz stringa s vadi tokene. Kao delimiteri se koriste blanko, novi red i sl. Promenljiva stok2 predstavlja StringTokenizer koji tako|e vadi tokene iz stringa s, ali se ovog puta kao delimiter koristi karakter |. Tom prilikom se ne vra}a sam karakter. Promenljiva stok3 predstavlja StringTokenizer koji vadi tokene iz stringa s, kao delimiter koristi karakter |, ali se vra}a i sam karakter koji je delimiter. Va|enje tokena Va|enje tokena iz stringa se vr{i preko metoda nextToken(). Ovaj metod ima dve verzije. Jedna verzija nema argumente. Tada se kao delimiter koristi onaj karakter koji je upotrebljen kod konstruktora. Druga varijanta prima argument tipa String i ona se koristi ako u toku rada `elite da promenite karakter koji se koristi kao delimiter. Tokom va|enja tokena se koristi i metod hasMoreTokens() koji vra}a true ako u stringu koji se ispituje postoji jo{ tokena, ili false, ako ih vi{e nema.
System.out.println ("count1 = " + stok1.countTokens ()); while (stok1.hasMoreTokens ()) System.out.println ("token = " + stok1.nextToken ()); System.out.println ("\r\ncount2 = " + stok2.countTokens ()); while (stok2.hasMoreTokens ()) System.out.println ("token = " + stok2.nextToken ()); System.out.println ("\r\ncount3 = " + stok3.countTokens ()); while (stok3.hasMoreTokens ()) System.out.println ("token = " + stok3.nextToken ());

Metoda countTokens() broji tokene u stringu. Na nju se ne treba previ{e oslanjati. Za rad je najbolje koristiti kombinaciju metoda hasMoreTokens() i nextToken(), kao u prethodnom primeru. Primer:
public class Tokenizer { public static void main(String[] args) { String s = "Ovo je recenica koja treba da se tokenizuje. | Ovo je jos jedna takva recenica. "; StringTokenizer stok1 = new StringTokenizer (s); StringTokenizer stok2 = new StringTokenizer (s, "|"); StringTokenizer stok3 = new StringTokenizer (s, " |", true); System.out.println ("count1 = " + stok1.countTokens ()); while (stok1.hasMoreTokens ()) System.out.println ("token = " + stok1.nextToken ()); System.out.println ("\r\ncount2 = " + stok2.countTokens ()); while (stok2.hasMoreTokens ())

75

System.out.println ("token = " + stok2.nextToken ()); System.out.println ("\r\ncount3 = " + stok3.countTokens ()); while (stok3.hasMoreTokens ()) System.out.println ("token = " + stok3.nextToken ()); } }

76

Sign up to vote on this title
UsefulNot useful