You are on page 1of 100

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Java programski jezik


Java je programski jezik visokog nivoa ije su osnovne karakteristike: Objektna orijentisanost Nezavisnost of hardverske platforme Distribuiranost Multitreding Platformska nezavisnost je jedna od najbitnijih karakteristika Java platforme, omoguavajui istoj Java aplikaciji da se bez ikakvih modifikacija izvrava na potpuno razliitim platformama (Linux, Windows, Solaris i druge).

Slika 1 - Proces kreiranja i izvravanja platformski nezavisne Java aplikacije

Kako se postie platformska nezavisnost? Izvorni kod u Java programskom jeziku kreira se u tekstualnim datotekama sa ekstenzijom .java. Korienjem Java kompajlera, od izvornih .java datoteka nastaju .class datoteke, koje se mogu posmatrati kao ekvivalent .exe datoteka koje nastaju kao rezultat kompajliranja C programa. Me utim, za razliku od .exe datoteka, u kojima se nalazi binarni kod koji se izvrava samo na jednoj platformi, u .class datotekama se nalazi bajt-kod (eng. bytecode), koji se moe izvravati na Java Virtuelnoj Maini (eng. Java Virtual Machine ili Java VM). Poto Java VM implementacije postoje za sve znaajnije plaforme, tako se isti java bajt-kod moe izvravati na gotovo svakoj plarformi. Proces kreiranja i izvravanja platformski nezavisne Java aplikacije prikazan je na slici 1. Jasno je da Java VM ima ulogu prevo enja bajt-koda u mainski kod platforme na kojoj se aplikacija izvrava, to se najee odvija u toku samog izvrenja aplikacije. Ovakav pristup izvravanju aplikacija moe dovesti do pogoranja performansi. Me utim, novije Java VM vre razliite vrste optimizacije u toku rada aplikacije, efikasno minimizujui gubitak performansi nastao usled uvo enja jo jednog sloja izme u aplikacije i platforme na kojoj se ona izvrava.

Java platforma
Platforma se definie kao hardversko-softversko okruenje u kome se aplikacija izvrava. Prethodno su pomenute popularne platforme, kao to su Windows, Linux, Solaris, koje se mogu opisati kao kombinacija operativnog sistema i hardvera na kome se on izvrava. Za Java platformu je karakteristino da je to isto softverska platforma, koja postoji kao deo neke druge platforme bazirane na hardveru. Java platformu sainjavaju dve komponente:

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Java Virtuelna Maina Java API (eng. Application Programming Interface) Kao to je poznato, Java VM slui za izvravanje bajt-koda na raznim platformama. API je kolekcija korisnih programskih komponenti koje programerima pruaju mogunost za brz i lak razvoj aplikacija. Ove komponente su grupisane u biblioteke srodnih klasa i interfejsa, u Java terminologiji poznate kao paketi. Broj paketa koje nudi java je ogroman, i varira od najosnovnijih, pa sve do paketa koji podravaju mreno programiranje, rad sa bazama podataka ili rad sa XML-om.
Java aplikacija API Java virtuelna maina
Platforma bazirana na hardveru

Java platforma

Slika 2 Pozicija Java platforme u sistemu

Pisanje prve Java aplikacije


Neophodni alati
Paket neophodan za razvoj Java aplikacija je JDK (Java Development Kit). Iako JDK u sebi najee sadri i JRE, treba napomenuti da JRE sam po sebi ne omoguava razvoj Java aplikacija njegova uloga je njihovo izvravanje. JDK u sebi sadri niz alata koji se pozivaju iz komandne linije, od kojih je svakako najbitniji Java kompajler Javac. Internet lokacija sa koje se JDK moe preuzeti je http://java.sun.com, koja sadri mnotvo korisnih alata i informacija vezanih za razvoj razliitih vrsta aplikacija baziranih na nekoj od Java platformi. Iako za Javu postoji niz integrisanih razvojnih okruenja, poput Eclipse-a, NetBeans-a ili Borland Builder-a, za prvi primer Java aplikacije bie korien tekst editor i alati koji se pozivaju iz komandne linije.

Podeavanje sistema
Da bi alati koji se pozivaju iz komandne linije mogli da budu na eni pod Windows operativnim sistemom, potrebno je putanju do njih dodati u sistemsku promenljivu PATH. To je mogue uraditi privremeno ili trajno. Privremeno ubacivanje moe se izvriti iz komandne linije, kao to je prikazano na slici 3.

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Slika 3 Privremeno postavljanje sistemske putanje do java alata.

Nedostatak ovakvog pristupa je u tome to je ovako kreirana putanja vidljiva samo u DOS prozoru u kome je uneta i posle zatvaranja prozora prestaje da bude vidljiva. Trajno podeavanje sistemske putanje mogue je izvriti na sledei nain. Otvori se kontrolni panel i izabere stavka System. U okviru sekcije Advanced klikom na dugme Environment Variables (slika 4a) otvara se prozor za podeavanje sistemskih promenljivih. U listi sistemskih promenljivih se prona e promenljiva Path, oznai se i klikom na dugme Edit otvara se prozor prikazan na slici 4b. U tekst-polju Variable value se na kraj doda putanja do bin foldera instalacionog foldera JDK-a. U konkretnom primeru prikazanom na slici to je putanja:
c:\Program Files\Java\jdk1.6.0_04\bin\

Podrazumeva se da ova putanja zavisi od verzije JDK-a koja je instalirana u konkretnom sluaju. Da bi promene sistemske putanje postale vidljive operativnom sistemu, potrebno je da se posle objanjenog postupka izloguje i ponovo uloguje na sistem.

Slika 4a prozor System properties

Slika 4b Podeavanje promenljivih okruenja

Izvorni kod aplikacije


Korienjem raspoloivog tekst-editora uneti kod koji je dat na slici 3 i snimiti ga u datoteku pod imenom HelloWorldApp.java.

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


/** * HelloWorldApp klasa je jednostavna Java aplikacija koja * ispisuje poruku "Hello World!" na standardnom izlazu. */ class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); // Ispis poruke } } Slika 3 Izvorni kod Hello World aplikacije

Prilikom kreiranja izvornog koda aplikacije voditi rauna o sledeem: Java programski jezik pravi razliku izme u velikih i malih slova, pa stoga izvorni kod aplikacije prepisati vodei rauna o velikim i malim slovima Preporuuje se da ime .java datoteke bude isto kao i ime klase koja se u njoj nalazi.

Prevo enje izvornog koda


Da bi Java Virtuelna Maina mogla da izvri Java aplikaciju, aplikacija mora da bude prevedena u bajt-kod. Za prevo enje Java izvornog koda u bajt-kod koristi se Java kompajler javac. Za prevo enje aplikacije potrebno je u komandnoj liniji uneti:
javac HelloWorldApp.java

Ovim se poziva java kompajler javac, kome se nalae da prevede java datoteku datu kao argument u komandnoj liniji u bajt-kod. Rezultat prevo enja bie nova datoteka, HelloWorldApp.class, koja u sebi sadri bajt-kod. Navedeni primer predstavlja najjednostavniji primer poziva java kompajlera. Java kompajler se moe pozivati uz korienje dodatnih opcija, iji se spisak moe dobiti pozivanjem kompajlera bez ikakvih parametara. Jedan od najbitnijih parametara komandne linije kompajlera je classpath, i njegova funkcija je da kompajleru ukae na putanje na kojima se nalaze paketi i klase koje se koriste u aplikaciji koja se kompajlira. Pored postavljanja promenljive classpath iz komandne linije, nju je mogue postaviti i kao sistemsku promenljivu, pri emu je postupak identian onome koji je opisan u poglavlju Podeavanje sistema.

Pokretanje aplikacije
Kada je aplikacija kompajlirana i bajt-kod je na raspolaganju, mogue ju je pokrenuti korienjem aplikacije za pokretanje (eng. launcher tool) java. Za pokretanje aplikacije iz prethodno opisanog primera komandna linija data je ispod:
java HelloWorldApp

Kao i kompajler, i aplikacija za pokretanje ima vie parametara komandne linije, me u kojima je i classpath, koji ima isto znaenje kao i kod kompajlera. Stoga je radi

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave lakeg rada iz komandne linije poeljno ovaj parametar podesiti kao sistemsku promenljivu.

Analiza izvornog koda aplikacije


Komentari U Java programskom jeziku postoje dve vrste komentara. Prvi su blok-komentari, kod kojih se poetak komentara oznaava kombinacijom simbola /*, dok se kraj oznaava kombinacijom */. Sav tekst koji se nalazi izme u otvarajuih i zatvarajuih simbola komentara ignorie se od strane kompajlera. Jedan primer blok-komentara dat je ispod:
/* Ovo je primer blok komentara Blok komentar moe zauzimati vie redova */

U izvornom kodu aplikacije koja je data kao primer moe se zapaziti neto drugaiji otvarajui komentar, /**. Od strane kompajlera, ovaj komentar se tretira kao obian otvarajui blok komentar sa simbolom * iza, koji kompajler potpuno ignorie. Ova vrsta komentara je znaajna za javadoc alat, koji na osnovu ovakvih komentara automatski generie dokumentaciju. Zato se ovakvi komentari nazivaju dokumentacioni komentari (eng. documentation comment). Druga vrsta komentara u Javi su linijski komentari, kod kojih se ignorie sadraj od znaka za komentar (//), pa do kraja linije. Primer linijskog komentara je dat ispod:
//ovo je linijski komentar

Definicija klase Aplikacija data u primeru sastoji se iz samo jedne klase, HelloWorldApp. Kao to se vidi iz primera, opti nain definisanja klase u javi je sledei:
class ImeKlase { // Telo klase }

Slubena re class oznaava poetak definisanja klase, iza nje sledi ime klase, iza koga se u vitiastim zagradama definie telo klase. Detalji vezani za klase bie objanjeni u narednim poglavljima. Main metoda U Java programskom jeziku, svaka aplikacija mora sadrati main metod koji se definie kao:
public static void main(String[] args)

Modifikatori public i static mogu biti napisani u proizvoljnom redosledu, ali je uobiajena praksa da se koriste u redosledu koji je dat u primeru. Metoda main preuzima parametre komandne linije u vidu niza stringova args, koji u optem sluaju moe biti nazvan proizvoljnim imenom. Ova metoda je ulazna taka u Java aplikaciju, i od nje uvek kree izvravanje Java aplikacije.

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Ispis na standardni izlaz Ispis na standardni izlaz se u primeru vri u liniji:


System.out.println("Hello World!");

Kao to se vidi, za ispis se koristi funkcija klase System. Ova klasa sadri niz korisnih funkcija za rad sa standardnim ulazom (System.in.*), izlazom (System.out.*), kao i funkcije za rad sa standardnim izlaznim strimom za greke (System.err.*). Pored toga, klasa System sadri i funkcije za rad sa sistemskim promenljivima, garbage collectorom, sistemskim vremenom i druge korisne funkcije. Klasa System se ne moe instancirati, pa se njenim metodama i metodama klasa lanica pristupa kao u sluaju ispisa.

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Osnovi Java programskog jezika


Promenljive
Pravila i konvencija imenovanja
Imena promenljivih se u Java programskom jeziku kreiraju kao kombinacija slova, brojeva, znakova za dolar ($) i donje crte(_). Imena promenljivih mogu biti proizvoljne duine, pri emu postoji ogranienje da ne mogu poinjati brojem. Java pravi razliku izme u malih i velikih slova u imenima promenljivih. Osim sintaksnih pravila vezanih za kreiranje imena promenljivih, postoje i neobavezujua pravila (konvencije) kod imenovanja promenljivih u Javi. Neke od osnovnih konvencija kod imenovanja promenljivih su: Imena promenljivih zapoinjati malim slovom Promenljive imenovati celim reima, ne skraenicama Ukoliko se ime promenljive sastoji od vie rei, sve rei su spojene a svaka re (osim prve) poinje velikim slovom Ako promenljiva predstavlja konstantu, ona se pie velikim slovima, a rei od kojih se sastoji se odvajaju donjom crtom.

Primitivni tipovi podataka


U javi postoji 7 primitivnih tipova podataka. Sintaksa Java programskog jezika nalae da se sve promenljive pre korienja moraju deklarisati. Primitivni tipovi podataka u Javi dati su ispod. byte Oznaeni osmobitni broj predstavljen u obliku komplementa broja 2. Opseg vrednosti je od -128 do 127, ukljuujui i navedene krajnje vrednosti. short - Oznaeni esnaestobitni broj predstavljen u obliku komplementa broja 2. Opseg vrednosti je od -32768 do 32767, ukljuujui i navedene krajnje vrednosti. int - Oznaeni tridesetdvobitni broj predstavljen u obliku komplementa broja 2. Opseg vrednosti je od - 2,147,483,648 do 2,147,483,647, ukljuujui i navedene krajnje vrednosti. long - Oznaeni ezdesetetvorobitni broj predstavljen u obliku komplementa broja 2. Opseg vrednosti je od - 9,223,372,036,854,775,808 do 9,223,372,036,854,775,807, ukljuujui i navedene krajnje vrednosti. float Broj u pokretnom zarezu jednostruke preciznosti predstavljen sa 32 bita. double - Broj u pokretnom zarezu dvostruke preciznosti predstavljen sa 64 bita. boolean Tip promenljive koji moe imati samo dve vrednosti true i false. Zauzee memorije od strane ovog tipa promenljive nije jasno definisano. char esnaestobitni unikod (eng. Unicode) karakter. Minimalna vrednost ovog tipa podataka je '\u0000' (ili 0), a maksimalna je '\uffff' (ili 65,535). Pored primitivnih tipova podataka, Java obezbe uje posebnu podrku za stringove kroz klasu java.lang.String. Zbog dobre podranosti od Java jezika, String klasa se esto pogreno smatra primitivnim tipom promenljive, to ona nije. Nain deklarisanja promenljive u optem sluaju je sledei:
tip imePromenljive = inicijalnaVrednost;

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Pri tome se tip odnosi na tip promenljive, i moe biti neki od prethodno navedenih primitivnih tipova, string ili ime klase. Deklaracija promenljive se moe zavriti i imenom promenljive, bez potrebe da se promenljiva postavlja na inicijalnu vrednost. U tom sluaju bi se odmah iza imena promenljive stavio znak ; . Sledei primer pokazuje deklarisanje nekoliko promenljivih, sa i bez inicijalizacije.
int decimalniBroj=15; int heksadecimalniInteger=0x2f; boolean brojUnet = true; byte neinicijalizovaniBajt; char slovoC= 'C'; short neinicijalizovaniShortTipPromenljive;

U sluaju da promenljive nisu eksplicitno inicijalizovane, Java kompajler ih postavlja na poznate predefinisane vrednosti, kao to je prikazano u tabeli 1.
Tip podataka short int long float double char String ili bilo koji objekt boolean Inicijalna vrednost 0 0 0L 0.0f 0.0d '\u0000' null false

Tabela 1 - Podrazumevane vrednosti neinicijalizovanih promenljivih

Nizovi
Niz predstavlja objekat koji sadri fiksan broj promenljivih istog tipa. Veliina niza se odre uje prilikom kreiranja niza. Jedan od naina kreiranja niza je pomou new operatora:
tip[] imeNiza = new tip[dimenzijaNiza];

U prethodnoj liniji, tip predstavlja tip podataka, koji moe biti bilo jedan od primitivnih tipova ili klasa. imeNiza je ime promenljive koja uva niz, a dimenzijaNiza je broj elemenata niza. Niz je mogue u istom izrazu kreirati i inicijalizovati, kao to je prikazano u sledeoj liniji:
tip[] imeNiza = {vrednost1, vrednost2, ,vrednostN};

U prethodnoj liniji se kreira niz imeNiza elemenata tipa tip, i istovremeno se postavlja N inicijalnih vrednosti elemenata. Istovemeno je brojem elemenata (N) koji se nalaze u vitiastoj zagradi odre ena i dimenzija niza. Sledi nekoliko primera kreiranja nizova, sa i bez inicijalizacije.
int[] triIntegera = new int[3]; String[] daniNedelje={pon,uto,sre,cet,pet,sub,ned};

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


Object[] petObjekata = new Object[5];

Svakom objektu koji predstavlja niz pridruena je lanica promenljiva length, koja sadri veliinu niza. Na primer, broj dana u nedelji iz prethodnog primera je daniNedelje.length. Kopiranje elemenata nizova iz jednog niza u drugi moe se vriti korienjem metode arrayCopy klase System. Ova funkcija je definisana na sledei nain:
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) // // // // // izvorni niz poetni indeks odredini niz poetni indeks u odreditu broj elemenata za kopiranje

Poto sve klase u Javi nasle uju klasu Object, tako se ova funkcija moe koristiti za kopiranje nizova proizvoljnog tipa.

Operatori
Operatori su specijalni simboli koji obavljaju odre ene operacije nad jednim, dva ili tri operanda i vraaju rezultat izvrene operacije. U Javi nemaju svi operatori jednak prioritet, i u sloenijim izrazima bitno je poznavati redosled izvravanja operacija. Java operatori pore ani po prioritetu i grupisani po tipovima su dati u tabeli 2. Operatori pore ani prema redosledu izvravanja Tip operatora postfix unary multiplicative additive shift relational equality bitwise AND
expr++ expr-++expr --expr +expr -expr ~ ! * / % + << >> >>> < > <= >= instanceof == != &

Redosled

bitwise exclusive OR ^ bitwise inclusive OR logical AND logical OR ternary


| && || ? :

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave assignment


= += -= *= /= %= &= ^= |= <<= >>= >>>= Table 2 - Operatori pore ani po redosledu izvravanja

Kratak pregled operatora


U ovom poglavlju bie dat kratak pregled svih grupa operatora, uz delove koda koji kroz primere ilustruju naine korienja operatora. Operator dodeljivanja = Operator dodeljivanja. Aritmetiki operatori + Operator sabiranja (Tako e se koristi za sabiranje stringova) Operator oduzimanja * Operator mnoenja / Operator deljenja % Operator ostatka
int result = 1 + 2; // result postaje 3 System.out.println(result); result = result - 1; // result postaje 2 System.out.println(result); result = result * 2; // result postaje 4 System.out.println(result); result = result / 2; // result postaje 2 System.out.println(result); result = result + 8; // result postaje 10 result = result % 7; // result postaje 3 System.out.println(ostatak deljenja broja 10 brojem 7 je +result);

Unarni operatori + plus operator; oznaava pozitivnu vrednost (iako se moe izostaviti) minus operator; vri negaciju izraza ++ operator inkrementiranja; poveava vrednost promenljive za 1 -- operator dekrementiranja; smanjuje vrednost promenljive za 1 ! operator logikog komplementa; vri invertovanje boolean promenljivih
int result = +1; // result postaje 1 System.out.println(result); result--; // result postaje 0 System.out.println(result); result++; // result postaje 1 System.out.println(result); result = -result; // result postaje -1

10

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


System.out.println(result); boolean success = false; System.out.println(success); // false System.out.println(!success); // true

Operatori jednakosti i relacioni operatori == je jednako != nije jednako > je vee >= je vee ili jednako < je manje <= je manje ili jednako
int value1 = 1; int value2 = 2; if(value1 == value2) System.out.println("value1 == value2"); if(value1 != value2) System.out.println("value1 != value2"); if(value1 > value2) System.out.println("value1 > value2"); if(value1 < value2) System.out.println("value1 < value2"); if(value1 <= value2) System.out.println("value1 <= value2");

Uslovni operatori && Uslovno-I || Uslovno ILI ?: Terinarni operator (skraenica za if-then-else konstrukciju)
int value1 = 1; int value2 = 2; int result; if((value1 == 1) && (value2 == 2)) System.out.println("value1 je 1 I value2 je 2"); if((value1 == 1) || (value2 == 1)) System.out.println("value1 je 1 ILI value2 je 1"); boolean someCondition = true; result = someCondition ? value1 : value2; System.out.println(result);

Operator pore enja tipova instanceof Odre ivanje da li je objekat instanca neke klase
class InstanceofDemo { public static void main(String[] args) {

11

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


Parent obj1 = new Parent(); Parent obj2 = new Child(); System.out.println("obj1 instanceof Parent: " + (obj1 instanceof Parent)); System.out.println("obj1 instanceof Child: " + (obj1 instanceof Child)); System.out.println("obj1 instanceof MyInterface: " + (obj1 instanceof MyInterface)); System.out.println("obj2 instanceof Parent: " + (obj2 instanceof Parent)); System.out.println("obj2 instanceof Child: " + (obj2 instanceof Child)); System.out.println("obj2 instanceof MyInterface: " + (obj2 instanceof MyInterface)); } } class Parent{} class Child extends Parent implements MyInterface{} interface MyInterface{}

Bitski operatori i operatori pomeranja ~ unarni bitski komplement << oznaeno pomeranje u desno >> oznaeno pomeranje u levo >>> neoznaeno pomeranje u levo & bitska I operacija ^ bitska ekskluzivno ILI operacija | bitska ILI operacija
int bitmask = 0x000F; int val = 0x2222; System.out.println(val & bitmask); // ispisuje "2"

12

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Kontrola toka programa


U ovom delu opisani su iskazi odluivanja (if-then-else, switch), iskazi ponavljanja (petlje: for, while, do-while) i iskazi grananja (break, continue,return).

Iskaz if-then-else
Opti format ovog iskaza je dat u primeru koji sledi. Tok programa objanjen je u komentarima.
if (prviUslov) { // Deo koda koji se izvrava ako je ispunjen prviUslov } else if (drugiUslov) { // Razmatra se samo ako prviUslov nije ispunjen // Izvrava se ako je drugiUslov ispunjen } else if (uslovN) { // Ako ni jedan od prethodnih uslova nije ispunjen, a ovaj jeste // onda e se ovaj deo koda izvriti } else { // Ovaj deo koda se izvrava samo u sluaju kad ni jedan prethodni // uslov nije ispunjen. // Broj else grana nije ogranien u Javi }

Treba napomenuti da je mogue da vie uslova istovremeno moe biti zadovoljeno. U tom sluaju, izvrie se deo koda koji se nalazi unutar prvog bloka koji ispunjava dati uslov, dok ostali uslovi nee ni biti razmatrani.

Iskaz switch-case
Switch-case iskaz radi sa byte,short,char i int primitivnim tipovima podataka, sa enumerisanim tipovima, kao i sa nekoliko specijalnih klasa koje su kreirane oko nekih od primitivnih klasa: Character, Byte, Short i Integer. Primer dat ispod demonstrira korienje switch-case iskaza.
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("Pogrean unos.");break;

13

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


} } }

Iskazi while i do-while


Opti oblik while iskaza je sledei:
while (uslov) { // Deo koda koji se izvrava sve dok je uslov ispunjen }

Petlja while se izvrava sve dok je uslov ispunjen. Uslov moe biti bilo kakav izraz iji je rezultat tipa boolean. Iskaz do-while je slian while iskazu:
do { // Telo iskaza koje se mora izvriti barem jednom, dok tok // izvravanja ne dostigne while po prvi put } while(uslov);

Razlika izme u while i do-while iskaza je u tome to se telo do-while iskaza mora izvriti makar jednom, to nije sluaj sa while iskazom.

Iskaz for
Iskaz for je pogodan za iteraciju kroz opsege vrednosti. Opti oblik ovog iskaza je:
for (inicijalizacija; terminacija; inkrement) { // telo petlje }

Kod korienja for iskaza, treba znati sledee: Izraz inicijalizacija se izvrava samo jednom, kada se petlja prvi put izvrava Kada izraz terminacija dobije vrednost false, prekida se izvravanje petlje Izraz inkrement se izvrava u svakoj iteraciji petlje, i moe obavljati bilo kakvu operaciju (operacija moe i izostati) Jednostavan primer korienja for iskaza:
class ForDemo { public static void main(String[] args){ for(int i=1; i<11; i++){ System.out.println("broja je: " + i); } } }

U primeru treba primetiti da se deklaracija i inicijalizacija brojake promenljive i obavlja u for iskazu, ime se obezbe uje da ona bude vaea samo u telu petlje. Sva tri izraza u definiciji for petlje su proizvoljna. Njihovim izostavljanjem dobija se beskonana petlja:
for ( ; ; ) { // beskonana petlja // telo petlje }

14

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Pored uobiajene forme for petlje, postoji i unapre ena (eng. enhanced) for petlja, koja je pogodna za iteraciju elemenata kolekcija i nizova. U sledeem primeru dat je nain korienja unapre ene for petlje:
class EnhancedForDemo { public static void main(String[] args){ int[] brojevi = {1,2,3,4,5,6,7,8,9,10}; for (int broj : brojevi) { System.out.println("Broj je: " + broj); } } }

Break iskaz
Pored korienja break iskaza u switch-case iskazu, on se moe koristiti i za prekidanje izvrenja for, while ili do-while petlje. Sledei primer demonstrira primenu break iskaza za promenu toka programa:
class BreakDemo { public static void main(String[] args) { int[] nizIntova = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 }; int trazeniBroj = 12; int i; boolean nasaoSam = false; for (i = 0; i < nizIntova.length; i++) { if (nizIntova [i] == trazeniBroj) { nasaoSam = true; break; } } if (nasaoSam) { System.out.println("Nasao sam " + trazeniBroj + " na poziciji " + i); } else { System.out.println(trazeniBroj + " nije u nizu"); } } }

Uobiajeno ponaanje break iskaza je da prekida izvravanje prve petlje u kojoj se nalazi. Korienjem labele u break iskazu, mogue je prekinuti i spoljnu petlju oznaenu labelom, kao to je prikazano u sledeem primeru.
class BreakWithLabelDemo { public static void main(String[] args) { int[][] nizIntova = { { 32, 87, 3, 589 }, { 12, 1076, 2000, 8 }, { 622, 127, 77, 955 } }; int trazeniBroj = 12; int i; int j = 0;

15

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


boolean nasaoSam = false; search: for (i = 0; i < nizIntova.length; i++) { for (j = 0; j < nizIntova[i].length; j++) { if (nizIntova[i][j] == trazeniBroj) { nasaoSam = true; break search; } } } if (nasaoSam) { System.out.println("Nasao sam " + trazeniBroj +" na poziciji " + i + ", " + j); } else { System.out.println(trazeniBroj+ " Nije u nizu"); } } }

Vano je napomenuti da ovaj tip break iskaza ne upuuje tok programa na liniju oznaenu labelom, ve prekida petlju koja je oznaena labelom.

Iskaz continue
Iskaz continue koristi se u for, while i do-while petljama. Ovaj iskaz navodi program da preskoi deo koda petlje ispod continue i da tok izvravanja programa vrati na izraunavanje logikog izraza koji kontrolie izvravanje petlje. Kao i kod break iskaza, i continue se odnosi na unutranju petlju u kojoj se nalazi.
class ContinueDemo { public static void main(String[] args) { String zaPretragu = "petar popusta pod pritiscima"; int max = zaPretragu.length(); int brojPova = 0; for (int i = 0; i < max; i++) { //interested only in p's if (zaPretragu.charAt(i) != 'p') continue; //process p's brojPova++; } System.out.println("Nasao sam " + brojPova + " slova p u stringu."); } }

Isto kao i kod break iskaza, continue iskaz moe koristiti labele za preskakanje izvrenja spoljanje petlje. I ovde vai napomena da se labela koristi za odre ivanje na koju petlju se odnosi continue iskaz, a ne za preusmeravanje toka programa.

16

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


class ContinueWithLabelDemo { public static void main(String[] args) { String zaPretragu = "Trazimo podstring u ovom stringu"; String podstring = "pod"; boolean nasaoSam = false; int max = zaPretragu.length() - podstring.length(); test: for (int i = 0; i <= max; i++) { int n = podstring.length(); int j = i; int k = 0; while (n-- != 0) { if (zaPretragu.charAt(j++) != podstring.charAt(k++)) { continue test; } } nasaoSam = true; break test; } System.out.println(nasaoSam ? "Nasao sam" : "Nisam nasao"); } }

Iskaz return
Ovaj iskaz prekida izvrenje trenutne metode i vraa se u metodu iz koje je pozvana. Iskaz return ima dve forme jednu koja vraa vrednost i drugu koja ne vraa vrednost. U sluaju kada return vraa vrednost, treba voditi rauna da se tip podatka koji se vraa poklapa sa tipom koji je naveden kod deklaracije funkcije. Opti oblik return iskaza je:
return povratnaVrednost;

Kod funkcija kojima je kao povratni tip naznaen void, povratnaVrednost se izostavlja.

Integrisano razvojno okruenje Eclipse


Eclipse je univerzalna platforma koja se moe koristiti u razne svrhe, a izme u ostalog i za razvoj Java aplikacija. U ovom poglavlju bie ukratko objanjen nain rada u Eclipse okruenju.

Kreiranje Java projekta u Eclipse okruenju


Prilikom pokretanja Eclipse-a bie prikazan prozor kao na slici 3. Iz ovog prozora mogue je otvoriti razne vrste tutorijala ili otvoriti workbench. Termin workbench se odnosi na radno okruenje Eclipse-a. Svaki workbench moe sadrati jednu ili vie perspektiva. Pod perspektivom se podrazumeva skup editora i prozora sa alatima i informacijama koji su prilago eni obavljanju jedne vrste posla. Tako se kod razvoja Java aplikacija najee koriste dve perspektive: Java i Debug. U prvoj perspektivi se programira, dok se druga koristi kada je potrebno program debagovati.

17

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Slika 3 - Prozor kod pokretanja Eclipse-a

Poto se sa pozdravnog ekrana odabere krui Workbench, prikazuje se radno okruenje kao na slici 4.

Slika 4 - Eclipse radno okruenje Java perspektiva

Izborom opcije File->New pokree se proces kreiranja novog projekta u nekoliko koraka. Odmah po izboru opcije otvara se dijalog prikazan na slici 5. Poto se funkcionalnost Eclipse platforme moe proirivati pomou plug-inova, lista ponu enih wizarda u dijalogu moe se razlikovati od sistema do sistema. Svrha svakog od wizarda je da vodi korisnika kroz proces kreiranja odre ene vrste projekta. Za Java aplikaciju potrebno je izabrati iz ponu ene liste Java Project i prei na sledei korak klikom na dugme Next.

18

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Slika 5 - Dijalog za kreiranje projekta

U prozoru na slici 5 koji se pojavljuje u sledeem koraku uneti ime projekata i izabrati opciju Create project from existing source, ime se obezbe uje da se bira lokacija na koju se projekat i datoteke vezane za njega smetaju. Korienjem dugmeta Browse izabrati lokaciju na kojoj e kreirani projekat biti smeten. Dugmetom Next moe se prei na sledei korak u kreiranju projekta, ukoliko je potrebno izvriti dodatna podeavanja radnog okruenja. Ukoliko dodatna podeavanja nisu potrebna, klikom na dugme Finish proces kreiranja projekta se zavrava.

Slika 6 - Izbor imena i lokacije Java projekta

19

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Za podeavanje parametara Java okruenja, kao to su putanje do biblioteka, nain organizacije izvornog koda i class fajlova i slino koristi se poslednji u nizu dijaloga. Poto za ovde opisane primere nisu potrebna dodatna podeavanja, klikom na Finish zavrava se proces kreiranja novog Java projekta.

Slika 7 - Podeavanja Java okruenja za projekat

Kreiranje klasa i pokretanje programa


Po kreiranju projekta se u pogledu Package Explorer koji se nalazi na levoj strani prozora aplikacije moe uoiti folder HelloWorldApp, koji u sebi sadri samo odgovarajui JRE. Desnim klikom na folder HelloWorldApp se otvara kontekst-meni iz koga treba izabrati New->Class za kreiranje nove klase. Izborom navedene opcije otvara se dijalog prikazan na slici 8.

20

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Slika 8 - Dijalog za kreiranje klase

U dijalogu sa slike 8 u polje name uneti HelloWorldApp, i selektovati opcije public static void main(String[] args) i Generate comments. Klikom na dugme Finish, bie kreiran Java fajl koji ima isto ime kao klasa, i bie dodat u projekat u default paket (to inae nije dobra praksa). U editoru koji zauzima najvei deo ekrana se moe videti automatski generisan kod, koji u sebi sadri i main metodu. Za potrebe demonstriranja pokretanja aplikacije iz Eclipse okruenja potrebno je uneti liniju za ispis teksta Hello World! kao to je to pokazano u prvoj vebi. Tokom kucanja, Eclipse nudi opcije za automatsko dopunjavanje koda, kao to je prikazano na slici 9. Tako e, u toku unosa izvornog koda Eclipse vri sintaksnu proveru izvornog koda i neispravne (ili nekompletne) linije podvlai crvenom bojom, nudei objanjenje greke u vidu hinta na ikonici greke koja se pojavljuje uz levu ivicu prozora editora.

21

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Figure 2 - Automatsko dopunjavanje koda u Eclipse-u

Pokretanje aplikacije vri se izborom opcije Run as->Java Application iz menija Run ili izborom iste opcije iz kontekst-menija projekta. Po pokretanju aplikacije, izlaz e biti ispisan u pogledu console koji e se pojaviti u donjoj polovini prozora aplikacije.

Debagovanje programa
U Java aplikacije mogu se postavljati prekidne take (eng. breakpoint) koje zaustavljaju izvrenje aplikacije na odre enoj liniji programa i omoguavaju programeru da analizira stanje promenljivih u tom trenutku izvrenja aplikacije. Prekidne take se postavljaju dvostrukim klikom na levu ivicu prozora editora, pre poetka linije na kojoj se eli zaustaviti izvrenje aplikacije, ili izborom opcije Toggle Breakpoint iz kontekst menija. Pokretanje programa u debag modu se vri opcijom Debug as->Java Application koja se nalazi u Run meniju. Po pokretanju, Eclipse pita korisnika da li eli da promeni perspektivu na Debug, na ta treba potvrdno odgovoriti. Perspektiva se potom menja i program se izvrava sve dok ne nai e na prvu prekidnu taku, gde se izvravanje prekida i kontrola preputa korisniku. Korisnik tada moe aplikaciju izvravati korak po korak komandama iz menija Run. Izgled prozora Eclipse aplikacije u Debug perspektivi vidi se na slici 10. Stanje promenljivih u trenutku prekida moe se pratiti u pogledu Variables, a na sredini prozora aplikacije nalazi se prozor editora u kome je posebno oznaena linija programa na kojoj je prekinuto izvrenje.

22

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Slika 10 - Perspektiva Debug

23

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Objektno orijentisani koncepti u Java programskom jeziku


Klase Definisanje klasa
Kao to je ve ranije naglaeno klase modeluju stanja i ponaanje objekata. Klasa Bicycle je dobar primer klase koja modeluje stanja i ponaenje jednog realnog objekta (Bicikla). Sledi primer definisanja klase Bicycle koja modeluje objekat Bicikl:
class Bicycle { //polja, konstruktor, i metode }

Prethodni kod predstavlja definiciju (deklaraciju) klase. Telo klase se nalazi u prostoru izme u zagrada i ono sadri definiciju polja klase (promenljivih), zatim konstruktora (za inicijalizaciju novih objekata klase) i na kraju metoda koje implementiraju ponaanje objekata klase. Prethodna definicija klase predstavlja osnovnu definiciju klase. U optem sluaju klase u Javi mogu nasle ivati druge klase i implementirati interfejse. Sledi primer definicije klase koja nasle uje drugu klasu i implementira interfejs:
class MountainBicycle extends Bicycle implements MountainInterface { //polja, konstruktor, i metode }

Ovaj primer opisuje klasu MountainBicycle koja nasle uje klasu Bicycle, i implementira interfejs MountainInterface (koncepti nasle ivanja i implementiranja interfejsa dati su u sledeim poglavljima). Tako e na poetku deklaracije klase mogue je naglasiti dali je ona public ili private i na taj nain odrediti dali i druge klase mogu da pristupaju datoj klasi. Uopteno deklaracija klase moe sadrati: Modifikatore public, private. Naziv klase (po konvenciji prvo slovo naziva je veliko slovo). Kljunu re extends posle koje sledi naziv klase koju elimo da nasledimo (klasa moe naslediti samo jednu klasu). Kljunu re implements iza koje sledi naziv interfejsa koji elimo da implementiramo. Klasa moe implementirati vie od jednog interfejsa, a tada se lista implementiranih interfejsa razdvaja zarezom. Telo klase, uokvireno vitiastim zagradama

Definisanje promenljvih klase


Promenljive jedne klase se tako e nazivaju i poljima te klase. U primeru klase Bicycle, polja date klase mogu biti:

24

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


public int cadence; //stepen prenosa public int gear; //stepen brzine public int speed; //brzina u km/h private float cost; //cena bicikla public static final String vehicleName = Bicycle;

Definicija promenljive klase ima tri dela: Nijedan ili vie modifikatora promenljive (public, private, protected, final, static, const) Tip promenljive (osnovni tip int, float, boolean ili tip koji se prenosi po referenci string, objekt, niz) Naziv promeljive (cadence u klasi Bicycle npr.) Modifikatori public, private i protected omoguavaju kontrolisanje pristupa promeljivama klase. Kontrola pristupa promenljivama bie opisana kasnije. Modifikator final ispred tipa promeljive oznaava promeljvu koja je konstanta. Vrednost ovakve promenljive zadaje se jednom i kasnije se ne moe menjati. Primer ovakve promeljive je broj Pi. Modifikator static oznaava promeljive koje su deljene me u svim instancama date klase u kojoj se nalazi takva promeljiva (postoji samo jedna instanca date promenljive). Na ovaj nain mogu se oznaavati globalne promeljive ili globalne konstante. Da bi se pristupalo datoj static promeljivoj nije potrebno praviti objekte klase koja sadri datu promeljivu. Dovoljno je staviti naziv klase ispred naziva date promeljive npr:
Bycicle.vehicleName = Bicycle_1;

Modifikator const oznaava konstante vidljive u okviru jednog objekta date klase. Za razliku od final promeljivih, const promeljive mogu biti zadane, ali im se vrednost ipak moe naknadno promeniti.

Deklarisanje metoda
Sledi primer uobianje deklaracije metoda klase:
public double calculateAnswer(double wingSpan, int numberOfEngines, double length, double grossTons) { //uraditi izraunavanje ovde }

Neophodni elementi deklaracije metode su: povratna vrednost metode, naziv metode, lista parametara izme u obinih zagrada () kao i telo metode izme u vitiastih zagrada {}. Uopteno deklaracija metode moe sadrati sledeih est delova: Modifikatore public, private (modifikatori pristupa e biti objanjeni kasnije). Tip povradne vrednosti funkcije npr. int, boolean... Tip void se stavlja ako metoda nema povratne vrednosti. Naziv metode.

25

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Listu parametara metode, razdvojenih zarezima. Parametri moraju imati tip ispred naziva. Listu izuzetaka (o izuzecima e biti vie rei u narednim poglavljima). Telo metode (nalazi se u okviru vitiastih zagarada). Po konvenciji naziv metoda poinje malim slovom, a ako se naziv metode sastoji iz vie rei svaka sledea re u nazivu poinje velikim slovom. Npr: getFinalData() .

Kontrolisanje pristupa promeljvima klase


Kao to je ranije spomenuto postoje tri tipa modifkatora za modifikovanje kontrole pristupa promeljivama klase. To su: public, private i protected. Postoji i etvrti implicitni tip, koji se podrazumeva kada se ne navede ni jedan od prethodna tri tipa modifikatora. Pre objanjavanja modifikatora, bitno je shvatiti pojam paketa u Java programskom jeziku. Paketi jesu skupovi klasa i interfejsa, koje su sline po nekoj osobini, ili koje zajedno obavljaju odre ene funkcije. Na primer paket Math bi predstavljao skup klasa koje obavljaju matematike funkcije u Javi. Na poetku deklaracije svake Java datoteke, a samim tim i klase navodi se kom paketu pripada data datoteka a samim tim i njene klase. Modifikator public omoguuje da datoj promeljivoj mogu da pristupaju sve klase (bilo iz svog paketa ili drugih paketa), dok modifikator private omoguuje pristup datoj promeljivoj samo iz njene klase. Modifikator protected govori da se promeljivoj moe pristupati iz bilo koje klase u okviru paketa njene klase. Tako e protected promenljivama mogu pristupati i klase naslednice, bez obzira u kom paketu se te klase naslednice nalaze. Ako nema modifikatora, promenljivoj se moe pristupiti u okviru njene klase i u okviru paketa njene klase. U principu promenljive bi trebale da se deklariu kao private kada god je to mogue, kako bi se zatitila enkapsulacija i integritet podataka. Modifikator public trebao bi da se koristi tamo gde se navode konstante. Pristup zatienim promenljivama klase moe se omoguiti preko metoda set i get koje postavljaju i vraaju vrednost zatienih promeljivih. Npr. u klasi Bicycle to bi bile metode:
public int getCadence() { return cadence; } public void setCadence(int newValue) { cadence = newValue; }

Inicijalizacija promeljivih klase


Inicijalizacija promenljivih klase mogua je u samoj deklaraciji promeljive npr:
public class BedAndBreakfast { public static int capacity = 10; //inicijalizacija na broj //10 private boolean full = false; //inicijalizacija na false }

26

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Ovakav nain inicijalizacije je dobar ako je data promenljiva prosta, tj. ako se njena inicijalizacija moe obaviti u jednoj liniji koda. U sluaju kada treba inicijalizovati kompleksne promeljive tipa niza, koje zahtevaju prolazak kroz for petlju da bi bile inicijalizovane, ovakav nain inicijalizacije je nepogodan. Kompleksne promeljive mogu biti inicijalizovane kroz konstruktor klase, pri stvaranju svakog objekta date klase. Sledi primer konstruktora klase Bicycle koji se koristi za incijalizacju promeljivih date klase (pri stvaranju objekata klase):
public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; }

Iz primera se vidi da konstruktor klase ima oblik metode klase. Razlika je u tome to konstruktor ima isti naziv kao i sama klasa, a pri tome ne poseduje povratnu vrednost. U sluaju da se eli inicijalizovati static promenljiva klase, to se moe uiniti upotrebom static blokova za inicijalizaciju promeljivih. Static blok za inicijalizaciju promeljivih poinje kljunom reju static iza koje slede zagrade {}.U njima se nalazi kod koji se koristi za inicijalizaciju static promeljivih. Primer static bloka:
static { // kod za inicijalizaciju static promenljivih }

Klasa moe da ima proizvoljan broj static blokova za inicijalizaciju, i oni se mogu nalaziti bilo gde u telu klase. Ono to je bitno jeste da se izvavanje datih blokova za inicijalizaciju odvija u redosledu u kom se pojavljuju u telu klase. Alternativno, moe se umesto static blokova za iniciajlizaciju promeljivih napraviti private static metoda:
class Whatever { public static varType myVar = initializeClassVariable(); private static varType initializeClassVariable() { // kod za inicijalizaciju static promenljive } }

Prednost pravljenja private static metoda jeste to one mogu biti iskoriene kasnije, kako bi se reinicijalizovala neka static promeljiva (npr. neki niz globalnih brojaa).

Ugnjedene klase
Java programski jezik omoguuje definisanje klase u okviru neke druge klase. Takva klasa se naziva ugnjedena klasa. Primer ugnjedene klase:
class OuterClass { ... class NestedClass { ... } }

27

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Ugnjedena klasa je lanica klase koja je obuhvata (spoljne klase), i kao takva ima pristup svim promenljivama spoljne klase. Ugnjedena klasa moe biti deklarisana kao private, public ili protected. Tako e ugnjedene klase mogu biti i static klase:
class OuterClass { ... static class StaticNestedClass { ... } class InnerClass { ... } }

Ugnjedene klase se koriste zbog: Logikog grupisanja klasa koje se koriste samo na jednom mestu (ako se jedna klasa koristi samo na zahtev neke druge klase, onda je logino da ta druga klasa obuhvati klasu koju koristi) Poveavanja enkapsulacije (nain da ugnjedena klasa pristupa svim promeljivama spoljne klase, a da pri tom ugnjedena klasa ostane skrivena) Poveavanja razumljivosti koda, kao i lakeg odravanja koda Razlikujemo dva tipa ugnjedenih klasa: statike ugnjedene klase i unutranje klase. Statike ugnjedene klase Kao i metode i promeljive klase, statike ugnjedene klase su povezane sa svojom spoljom klasom. Statika ugnedena klasa ne moe da pristupa direktno promeljivama i metodama svoje spoljne klase, ve im moe pristupati jedino preko objekta spoljne klase. Statikim ugnjedenim klasama se moe pristupiti preko imena njene spoljne klase:
OuterClass.StaticNestedClass

Da bi se kreirao objekat statike ugnjedene klase, koristi se sledea sintaksa:


OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

Unutranje klase Kao metode i promeljive instance neke klase, tako su i ugnjedene klase povezane sa instancom svoje spoljne klase. Kao takve, ugnjedene klase mogu pristupati metodama i poljima objekta svoje spoljne klase. Poto su povezane sa instancom spoljne klase, ugnjedene klase ne mogu imati statikih polja u sebi. Objekti koji su instance ugnjedene klase postoje u okviru instance spoljne klase. Za ilustraciju - u prethodnom primeru smo imali sledee klase:

class OuterClass { ...

28

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


class InnerClass { ... } }

OuterClass,

Instanca klase InnerClass moe postojati samo u okviru instance klase i data instanca ugnjedene klase ima pristup poljima i metodama spoljne instance. Sledea slika opisuje odnos spoljne i ugnjedene klase:

Slika 11 Odnos spoljne i ugnjedene klase

Da bi se instancirao objekat unutranje klase, mora se prvo instancirati objekat spoljne klase. Tada se tek moe napraviti objekat unutranje klase na sledei nain:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

29

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Nasle ivanje i interfejsi


Primer nasle ivanja
U programskom jeziku Java klase mogu biti izvedene iz drugih klasa i odatle one nasle uju polja i metode klasa iz kojih su izvedene. Svaka klasa u Java programskom jeziku jeste izvedena iz neke druge klase. Osnovna klasa od koje su izvedene sve druge klase jeste klasa Object. Klasa od koje je izvedena neka druga klasa zove se superklasa, a izvedena klasa se zove subklasa. Hijerarhija java klasa i nasle ivanja u Javi data je na sledeoj slici:

Slika 12 Hijerarhija nasle ivanja u Javi

Na vrhu hijerarhije nalazi se osnovna klasa Object. Neke druge klase su direktno izvedene iz klase Object, a neke dalje klase su izvedene iz tih izvedenih klasa itd... Nasle ivnje uvodi mogunost ponovnog korienja prethodno napisanih klasa. Ovo je veoma bitno jer se pri stvaranju nove klase moe se naslediti prethodno napisana klasa i na taj nain se mogu iskoristiti polja i metode koje ona poseduje. Subklasa nasle uje sve metode, polja i ugnjedene klase superklase. Jedino to ne nasle uje jeste konstruktor superklase. Ipak ovaj konstruktor se moe pozvati kljunom reju super. Sledi primer implementacije superklase i subklase. Superklasa e u ovom sluaju biti ranije spomenuta klasa Bicycle , a klasa izvedena iz nje e biti klasa MountainBike:
public class Bicycle { // klasa Bicycle ima tri polja public int cadence; public int gear; public int speed; // klasa Bicycle ima jedan konstruktor public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed;

30

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


} // klasa Bicycle ima cetiri metode public void setCadence(int newValue) { cadence = newValue; } public void setGear(int newValue) { gear = newValue; } public void applyBrake(int decrement) { speed -= decrement; } public void speedUp(int increment) { speed += increment; } }

Definicija izvedene klase MountainBike:


public class MountainBike extends Bicycle { // subklasa MountainBike dodaje jedno novo polje public int seatHeight; // subklasa MountainBike ima jedan konstruktor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { //subklasa MountainBike koristi konstruktor superklase pozivom //preko kljune rei super super(startCadence, startSpeed, startGear); seatHeight = startHeight; } // subklasa MountainBike dodaje jednu novu metodu public void setHeight(int newValue) { seatHeight = newValue; } }

Subklasa nasle uje sve public i protected lanove superklase. Tako e ako je u istom paketu sa superklasom, subklasa nasle uje iz superklase i polja koja nemaju modifikator pristupa (public, private, protected). Subklasa omoguuje sledee: Nasle ena polja se mogu koristiti direktno Subklasa moe deklarisati polja istog naziva kao i polja u superklasi, i na taj nain skriti polja superklase (nije preporuljivo) Subklasa moe deklarisati nova polja koja nisu u superklasi Nasle ene metode mogu biti koriene direktno Subklasa moe definisati novu metodu koja ima istu signaturu (isti naziv, tip povratne vrednosti, broj i tip parametara).kao metoda u superklasi. Na ovaj nain se vri override (prepis) metode iz superklase.

31

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Subklasa moe definisati novu static metodu koja ima istu signaturu kao metoda u superklasi. Na ovaj nain se skriva metoda iz superklase. Mogu se definisati metode koje nisu u superklasi. Moe se napisati konstruktor subklase koji poziva konstruktor superklase korienjem kljune rei super.

Override metode iz superklase vri se definisanjem metode sa istom signaturom (isti nazivom, tipom povratne vrednosti, brojem i tipom parametara) u subklasi. Overrideom metode u subklasi omoguuje se modifikovanje date metode superklase. Skrivanje metode iz superklase vri se definisanjem static metode u subklasi koja ima istu signaturu kao i metoda u superklasi. Razlika izme u skrivane metode i override ovane metode jeste to ako se poziva override ovana metoda, onda se poziva metoda subklase. Sa druge strane ako se poziva skrivena metoda, funkcionalnost zivisi od toga dali se metoda pozvala iz superklase ili subklase. Sledi primer poziva skrivenih metoda dat kroz dve klase: Animal i Cat:
public class Animal { public static void testClassMethod() { System.out.println("The class method in Animal."); } public void testInstanceMethod() { System.out.println("The instance method in Animal."); } }

Subklasa Cat:
public class Cat extends Animal { public static void testClassMethod() { System.out.println("The class method in Cat."); } public void testInstanceMethod() { System.out.println("The instance method in Cat."); } public static void main(String[] args) { Cat myCat = new Cat(); Animal myAnimal = myCat; Animal.testClassMethod(); myAnimal.testInstanceMethod(); } }

Klasa Cat vri override metode testInstanceMethod iz klase Animal, a tako e vri i skrivanje metode testClassMethod iz iste klase (Animal). Pri pozivu main metode iz klase Cat dobija se sledei ispis:
The class method in Animal. The instance method in Cat.

32

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Kao to se moe videti poziv skrivene metode jeste poziv metode superklase (jer se pozvala statika metoda superklase), a poziv override-ovane metode jeste poziv metode subklase, to je u skladu sa pravilima skrivanja odnosno override-ovanja metoda u nasle ivanju.

Primer korienja interfejsa


U Java programskom jeziku interfejsi su referentni tip, slian klasama, koji mogu sadrati jedino konstante, signature metoda i ugnjedene tipove. U interfejsima ne postoje tela metoda. Interfejsi ne mogu biti instancirani, jedino mogu biti implementirani od strane neke klase ili nasle eni od strane drugih interfejsa. Sledi primer definicije interfejsa (slina je definiciji klase):
public interface Relatable extends Interface1, Inteface2 { // this objekat (objekat koji zove metodu isLargerThan) i // drugi objekat moraju biti instance iste klase // vraa 1, 0, -1 ako je this objekat vei od, // jednak, ili manji od objekata sa kojim se poredi public int isLargerThan(Relatable other); }

Public modifikator znai da interfejs moe koristiti bilo koja klasa u bilo kom paketu. Ako se ne specificira da je interfejs public tipa , dati interfejs e biti vidljiv samo klasama u okviru istog paketa. Kljuna re extends u deklaraciji interfejsa znai da interfejs nasle uje neke druge interfejse (u ovom sluaju Interface1, Inteface2). Treba primetiti da za razliku od klasa - interfejs moe da nasledi vie od jednog interfejsa. Sve metode deklarisane u interfejsu su impicitno public tipa, tako da se ovaj modifikator ne mora stavljati ispred naziva metode. Sve konstante deklarisane u interfejsu su implicitno public static final , tako da se ovaj modifikator moe izostaviti ispred naziva konstante. Da bi se koristio interfejs, pie se klasa koja implementira dati interfejs (definie tela metoda deklarisanih u interfejsu). Npr:
public class RectanglePlus implements Relatable { public int width = 0; public int height = 0; public Point origin; // four constructors public RectanglePlus() { origin = new Point(0, 0); } public RectanglePlus(Point p) { origin = p; } public RectanglePlus(int w, int h) { origin = new Point(0, 0); width = w; height = h; }

33

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


public RectanglePlus(Point p, int w, int h) { origin = p; width = w; height = h; } // a method for moving the rectangle public void move(int x, int y) { origin.x = x; origin.y = y; } // a method for computing the area of the rectangle public int getArea() { return width * height; } // a method to implement Relatable public int isLargerThan(Relatable other) { RectanglePlus otherRect = (RectanglePlus)other; if (this.getArea() < otherRect.getArea()) return -1; else if (this.getArea() > otherRect.getArea()) return 1; else return 0; } }

Jedna klasa moe da implementira vie od jednog interfejsa. Tada je lista interfejsa koji se implementiraju odvojena zarezom. Kada se definie novi interfejs, definie se novi referentni tip podataka. Nazivi interfejsa se mogu koristiti gde god se koriste imena bilo kog drugog tipa podataka (naziv interfejsa postaje novi tip podataka). Ako se definie promeljiva iji je tip interfejs, objekat koji se dodeljuje datoj promeljivoj mora biti objekat klase koja implementira dati interfejs. Na primer:
public Object findLargest(Object object1, Object object2) { //object1 i object2 moraju biti instance klase koja implementira //interfejs Relatable Relatable obj1 = (Relatable)object1; Relatable obj2 = (Relatable)object2; if ( (obj1).isLargerThan(obj2) > 0) return object1; else return object2; }

Ako se eli promena strukture interfejsa dodavanjem neke nove metode, ta promena se moe izvriti nasle ivanjem interfejsa, i dodavanjem nove metode u nasle eni interfejs:

public interface DoIt {

34

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


void doSomething(int i, double x); int doSomethingElse(String s); } //nasledjeni interfejs public interface DoItPlus extends DoIt { boolean didItWork(int i, double x, String s); }

Dodavanje nove metode u stari interfejs koji je ve implementiran u nekim klasama dovee do kompajlerske greke (jer klase koje implementiraju dati interfejs moraju implementirati sve njegove metode pa i novo ubaenu):
public interface DoIt { void doSomething(int i, double x); int doSomethingElse(String s); boolean didItWork(int i, double x, String s); }

Poziv konstruktora super klase


Sledi primer koji pokazuje kako se koristi kljuna re super radi poziva konstruktora superklase. U prethodnom primeru, klasa Bicycle jeste superklasa klase MountainBike. Konstruktor klase MountainBike poziva prvo kostruktor klase Bicycle, a zatim dodaje i svoj kod za inicijalizaciju:
public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { super(startCadence, startSpeed, startGear); seatHeight = startHeight; }

Poziv konstruktora superklase mora biti prva linija u konstruktoru subklase. Sintaksa poziva konstruktora superklase zavisi dali konstruktor superklase nema parametara ili ima. Npr:
super(); --ili-super(parameter list);

Ako konstruktor subklase ne pozove eksplicinto konstruktor superklase, Java kompajler e pozvati implicitno konstruktor superklase koji nema argumenata. Ako takav konstruktor ne postoji, kompajler e ispisati greku. Pozivi konstruktora superklasa se nadovezuju jedan za drugim u skladu sa redosledom nasle ivanja klasa, a proteu se sve do osnovne klase Object (ova osobina je poznata kao ulanavanje konstruktora).

35

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Pisanje apstraktnih klasa i metoda


Opis apstraktnih klasa i metoda kroz primer
Apstraktna klasa je klasa koja je deklarisana kao apstraktna (kljuna re pre rei class). Apstraktna klasa moe ali ne mora imati u sebi apstraktnih metoda. Apstraktna klasa ne moe biti instancirana, ali moe biti nasle ena. Apstraktna metoda je metoda koja je deklarisana bez implementacije, kao npr. sledea metoda:
abstract abstract void moveTo(double deltaX, double deltaY);

Ako klasa sadri apstraktne metode, ona sama mora biti deklarisana apsktraktnom:
public abstract class GraphicObject { // deklaracija polja // deklaracija ne-apstraktnih metoda abstract void draw(); }

Kada se apstraktna klasa nasle uje, njena subklasa obino sadri implementaciju svih njenih apstraktnih metoda. Ukoliko subklasa apstraktne klase ne sadri implementaciju njenih apstraktnih metoda , onda se i ta subklasa mora deklarisati apstraktnom. Sve metode interfejsa su implicitno apstraktne, jer ne sadre implementaciju. Za razliku od interfejsa apstraktne klase mogu posedovati polja (promenljive), koje nisu static final promeljive, a tako e mogu posedovati i implementirane metode. Apstraktne klase lie na interfejse, a razlika je u tome to sadre deliminu implementaciju metoda, ostavljajui subklasama da kompletiraju implementaciju. Ako apstraktna klasa sadri samo definicije metoda, onda ona treba biti preimenovana u interfejs. Dobar primer korienja apstraktne klase jeste grafika aplikacija u kojoj mogu da se crtaju razliiti oblici - kvadrati, krugovi, linije itd Svi ovi objekti imaju sledee zajednike osobine: stanja (poziciju, orjentaciju, boju linije ) ponaanja ( pomeraj na poziciju, rotacija, promena veliine)

Neka od ovih stanja i ponaanja su ista za sve grafike objekte na primer: pozicija, boja linije i funkcija pomeraj na poziciju. Druga stanja i ponaanja su razliita i zahtevaju drugaije implementacije na primer: promena veliine i rotacija. Svi grafiki objekti moraju znati kako da promene veliinu ili da se rotiraju, jedino to je razliito jeste na koji nain to rade. Ovo je mesto gde se moe iskoristiti apstraktna superklasa, koja e objednjavati iste osobine svih grafikih objekata kao to je ilustrovano na slici:

36

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


Slika 13 Primer apstraktne klase

Implementacija primera sa slike prvo zahteva deklaraciju apstraktne klase GraphicObject koja e sadrati polja i metode koje su zajednike za sve njene subklase (Rectangle, Line, Bezier i Circle). Zajedniko polje je na primer pozicija, a zajednika metoda je - pomeraj na poziciju. GraphicObject tako e deklarie apstraktne metode, na primer iscrtaj i promeni veliinu. Ove metode e biti implementirane od strane subklasa na raziliite naine. Primer klase GraphicObject:
abstract class GraphicObject { int x, y; ... void moveTo(int newX, int newY) { ... } abstract void draw(); abstract void resize(); }

Svaka ne-apstraktna subklasa klase GraphicObject implementaciju apstraktnih metoda draw i resize:
class Circle extends GraphicObject { void draw() { ... } void resize() { ... } } class Rectangle extends GraphicObject { void draw() { ... } void resize() { ... } }

mora

sadrati

Apstraktna klasa moe tako e implementirati i interfejs, ali za razilku od obine klase ne mora implementirati sve metode iz interfejsa. Na primer:
abstract class X implements Y { // implementira sve, osim jedne metode iz interfejsa Y } class XX extends X { // implementira preostali metod interfejsa Y }

Apstraktna klasa moe sadriati static polja i static metode, a njima se moe pristupiti kao to im se pristupa u okviru obine klase:
AbstractClass.staticMethod()

37

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Definisanje I korienje paketa


Paketi su grupacije povezanih klasa i interfejsa. Ove klase i interfejsi imaju specijalnu dozvolu pristupa klasama i interfejsima u okviru svog paketa. Klase i interfejsi Java programskog jezika su lanovi razliitih paketa. Osnovne Java klase nalaze se u sledeim paketima: java.lang , java.io itd... Moue je formiranje i korisnikih paketa. Pretpostavimo da imamo grupu klasa koje reprezentuju grafike objekte kvadrate, krugove, linije itd... Tako e pretpostavimo da imamo i interfejs Draggable, koji prethodne klase implementiraju ako se njihovi objekti mogu prevlaiti miem.
//u fajlu Draggable.java public interface Draggable { . . . } //u fajlu Graphic.java public abstract class Graphic { . . . } //u fajlu Circle.java public class Circle extends Graphic implements Draggable { . . . } //u fajlu Rectangle.java public class Rectangle extends Graphic implements Draggable { . . . } //u fajlu Point.java public class Point extends Graphic implements Draggable { . . . } //u fajlu Line.java public class Line extends Graphic implements Draggable { . . . }

Sve ove klase i interfejs bi trebali da se stave u jedan paket zbog sledeih razloga: Lako se moe utvrditi da su date klase u relaciji Drugi korisnici mogu odrediti gde da trae funkcije koje su u relaciji sa grafikom Imena klasa u okviru jednog paketa nisu u koliziji sa imenima klasa u drugim paketima jer se date klase nalaze u razliitim paketima Klase u okviru jednog paketa mogu imati neogranien pristup drugim klasama u okviru svog paketa, a da pri tom pristup klasama iz drugih paketa bude zabranjen.

Kreiranje paketa vri se stavljanjem kljune rei package na sam poetak datoteke. Nakon kljune rei package sledi naziv paketa. Na taj nain datoteka i sve 38

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave njene klase i interfejsi postaju deo datog paketa.Kljuna re package mora biti prva re u datoteci, a jedna datoteka moe biti lan samo jednog paketa. Formiranje paketa klasa i interfejsa iz prethodnog primera izlgledalo bi ovako:
//u fajlu Draggable.java package graphics; public interface Draggable { . . . } //u fajlu Graphic.java package graphics; public abstract class Graphic { . . . } //u fajlu Circle.java package graphics; public class Circle extends Graphic implements Draggable { . . . } //u fajlu Rectangle.java package graphics; public class Rectangle extends Graphic implements Draggable { . . . } //u fajlu Point.java package graphics; public class Point extends Graphic implements Draggable { . . . } //u fajlu Line.java package graphics; public class Line extends Graphic implements Draggable { . . . }

Ako se ne naglasi kom paketu pripada datoteka, ona e se nai u neimenovanom paketu. Uopteno gledajui neimenovani paketi su prihvatljivi samo kod malih i privremenih aplikacija. U suprotnom klase i interfejse je potrebno staviti u imenovane pakete. Da bi se koristile klase ili interfejsi (lanovi paketa) iz odre enog paketa potrebno je uraditi jedno od sledeeg: Pristupiti lanu paketa preko njegovog punog imena Ukljuiti dati lan u datoteku Ukljuiti u datoteku itav paket u kome se nalazi dati lan

39

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Ako se lanu paketa eli pristupiti iz nekog drugog paketa, a da pri tom paket datog lana nije ukljuen, pristup se moe izvriti preko punog imena lana (koje ukljuuje i naziv paketa). Puno ime klase Rectangle iz paketa graphics bi bilo:
graphics.Rectangle

Ukljuivanje odre enog lana paketa vri se upotrebom kljune rei import na poetku datoteke, iza ega sledi naziv lana paketa. Ukljuivanje lanova paketa se vri neposredno iza deklaracije paketa trenutne datoteke(ako ga ima) , a u suprotnom se nalazi na prvom mestu u datoteci. Primer ukljuivanja lana paketa:
import graphics.Rectangle;

Sada se klasi Rectangle moe pristupiti direktno preko imena:


Rectangle myRectangle = new Rectangle();

Ovaj pristup je dobar ako se koristi samo par klasa iz paketa, u suprotnom, ako se koristi vei broj klasa iz paketa, potrebno je ukljuiti ceo paket. Ukljuivanje svih lanova graphics paketa vri se na sledei nain:
import graphics.*;

Posle ovog ukljuivanja mogu je direktan pristup svim lanovima datog paketa:
Circle myCircle = new Circle(); Rectangle myRectangle = new Rectangle();

40

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Izuzeci
Tokom izvravanja programa moe doi do neoekivanih situacija koje mogu izazvati prekid izvravanja. Java nudi mehanizam izuzetaka koji omoguava oporavak od greaka tokom izvravanja. Izuzetak moe biti generisan i obra en (eng. try-catch mechanism). Generisanje izuzetka signalizira pojavu neoekivane greke. Obrada izuzetka podrazumeva preduzimanje odre enih koraka koji e dovesti do nastavka rada programa. Izuzetak obra uje kd koji se naziva rukovalac izuzetkom (eng. exception handler). Obrada izuzetka se obino ne vri u okviru istog konteksta u kom je izuzetak generisan. JVM uvek izvrava nekoliko niti: sakuplja otpada, glavnu nit u kojoj se izvrava program, itd. Svaka nit ima svoj stek izvravanja (eng. runtime stack, call stack, invocation stack) koji obra uje izuzetke koji su generisani tokom izvravanja metoda. Element steka se naziva aktivacioni slog (eng. activation record, stack frame) i predstavlja poziv metoda. U sebi sadri podatke o metodi (lokalne promenljive npr.). Prilikom svakog poziva kreira se novi aktivacioni slog i smeta na vrh. Metod iji se aktivacioni slog nalazi na vrhu steka je onaj koji se trenutno izvrava. Kada metod zavri sa izvravanjem, njegov slog bie uklonjen sa steka. Izvravanje e se nastaviti u metodu iji je slog sada na vrhu steka. Metodi koji se nalaze na steku se nazivaju aktivnima, jer njihovo izvravanje nije zavreno. Svojom strukturom stek omoguava praenje toka izvravanja niti. Trag steka (eng. stack trace) predstavlja redosled izvravanja metoda.
public class Izuzetak { public static void pitajKorisnika(String[] args){ System.out.println("Korisnik je rekao " + pisi(args)); System.out.println("Kraj metoda pitajKorisnika"); } static String pisi(String[] args){ String s = args[0]; for(int i = 1; i < args.length; i++){ s = s + "" + args[i]; } return s; } public static void main(String[] args){ pitajKorisnika(args); System.out.println("Kraj main metoda"); } }

Ukoliko pri pokretanju programa Izuzetak ne navedemo ni jedan argument, JVM e prijaviti greku prilikom pokuaja da promenljivoj s u redu 9 dodeli vrednost prvog elementa nepostojeeg niza args. Ako se u tragu steka ne pojavljuju brojevi redova kao to je prikazano dole, potrebno je iskljuiti JIT (eng. Just-in-Time) opciju JVM u Java 2 SDK:
java Djava.compiler=NONE ImePrograma.

41

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 at Izuzetak.pisi(Izuzetak.java:9) at Izuzetak.pitajKorisnika(Izuzetak.java:4) at Izuzetak.main(Izuzetak.java:17)

greku tako to generie izuzetak ArrayIndexOutOfBoundsException. Izvravanje metoda pisi() prekinuto je u redu 9 generisanjem izuzetka i return naredba iz reda 13 nikad nee biti izvrena. Kako metod ne poseduje kd koji bi obradio izuzetak, izvravanje metoda je nepovratno prekinuto, a njegov aktivacioni slog uklonjen sa steka. Izuzetak e biti prosle en sledeem metodu sa steka, u ovom sluaju pitajKorisnika(). Ni ovaj metod nema naina da obradi izuzetak, pa je i on prekinut u redu 4, a njegov aktivacioni slog skinut sa steka. Izuzetak se prosle uje metodi main(). Ni on ne moe da obradi izuzetak, pa e i on biti prekinut u redu 17. Kako izuzetak nije obradio ni jedan od aktivnih metoda, obradie ga osnovni rukovalac izuzecima glavne niti. Osnovni rukovalac izuzecima obino ispie ime izuzetka i objanjenje koje sledi redosled izvravanja aktivnih metoda u trenutku generisanja izuzetka. Neobra eni izuzetak izaziva smrt niti u kojoj se izuzetak desio. Ako se izuzetak desio prilikom izraunavanja levog operatora binarne operacije, desni operand se ne izraunava. Ukoliko se izuzetak desi prilikom izraunavanja jednog od parametara u listi stvarnih parametara, do izraunavanja ostatka liste nee doi.

JVM

prijavljuje

Vrste izuzetaka
Izuzeci su Java objekti. Svi izuzeci nasle uju klasu java.lang.Throwable. Dve najvanije podklase klase Throwable su Exception i Error.

Slika XY

42

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Klasa Throwable sadri promenljivu tipa znakovni niz (String) u koju mogu da piu potklase u cilju detaljnijeg obavetavanja korisnika o prirodi greke koja je dovela do generisanje izuzetka. Sve klase koje nasle uju Throwable definiu konstruktor od kojih je jedan argument znakovni niz u kom se nalazi poruka o greki. Najee koriteni metodi klase Throwable su: String getMessage() koji vraa poruku o greki. void printStackTrace() tampa trag steka na standardni izlaz za greku. Ovaj metod overload-uju jo dva metoda koji za argumente primaju objekte tipa PrintStream ili PrintWriter u zavisnosti od toga gde treba tampati trag steka. String toString() vraa kratak opis izuzetka zajedno sa porukom o greki. Klasom Exception predstavljeni su izuzeci kojih program treba da bude svestan tokom izvravanja. Klasa RuntimeException i sve njene potklase predstavljaju izuzetke koji se generiu tokom izvravanja programa, a usled greki u programiranju. Objekte ove klase ne bi trebalo obra ivati, ve ih treba smatrati grekama u dizajnu programa koje treba otkloniti. Klasa Error signalizira greke pri uvezivanju dokumenta, smrti niti, greke virtuelne maine itd. Izuzeci ove vrste predstavljaju probleme od kojih gotovo da nije mogu oporavak, pa ih ne treba ni obra ivati. Provereni izuzeci (eng. checked exceptions) su svi izuzeci koji ne pripadaju RuntimeException, Error i njihovim potklasama. Prevodilac garantuje da metod koji direktno ili indirektno moe generisati izuzetak, mora eksplicitno ili da ga obradi, ili da ga prosledi dalje. Metodi ne moraju obraati panju na neproverene izuzetke (eng. unchecked exceptions), jer od njih ili nije mogue oporaviti se (Error) ili su u pitanju greke u dizajnu (RuntimeException). Novi izuzeci se definiu u cilju bolje kontrole greaka. Obino nasle uju neki od proverenih izuzetaka.
package JavaVezbe2008; public class JaveVezbeException extends Exception{ public JaveVezbeException (String s){ super(s); } }

Obrada izuzetaka
Izuzeci se obra uju pomou konsrukcije try-catch-finally. Izuzeci koje generie kd koji se nalazi unutar bloka try mogu biti obra eni u odgovarajuem bloku catch. Blok finally se izvrava uvek, bez obzira na to da li je do izuzetka dolo. Konstrukcija try-catch-finally zahteva upotrebu blokova, kako je pokazano u donjem primeru. Svaki blok try zahteva nula ili vie blokova tipa catch i nula ili jedan blok finally u navedenom redosledu. Blok try blok mora slediti bar jedan blok tipa catch ili finally. Blok catch u svom zaglavlju uvek sadri tano jedan argument onog tipa izuzetka (mora nasle ivati klasu Throwable ili jednu od njenih potklasa) koji blok

43

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave treba da obradi. Svaki od blokova moe sadrati bilo kakve naredbe, to znai da je mogue ugnedavanje konstrukcija try-catch-finally.
import java.io.*; public class TryCatchFinally { static int podeli(String s1, String s2){ int i1, i2; try{ i1 = Integer.parseInt(s1); i2 = Integer.parseInt(s2); return deli(i1, i2); }catch(NumberFormatException nfe){ nfe.printStackTrace(); System.out.println("Izuzetak obradjen u podeli() metodu"); return 0; } } static int deli (int a, int b){ return a / b; } public static void main(String[] args) { try{ BufferedReader ulaz = new BufferedReader (new InputStreamReader (System.in)); System.out.println("Unesite delilac"); String s = ulaz.readLine(); int i = podeli(args[0], s); System.out.println("Rezultat deljenja je " + i); }catch (IOException ioe){ ioe.printStackTrace(); System.out.println("Izuzetak obradjen u main() metodu"); }catch (ArrayIndexOutOfBoundsException ie){ ie.printStackTrace(); System.out.println("Izuzetak obradjen u main() metodu"); }finally{ System.out.println("finally izvrsen u main() metodu"); } System.out.println("kraj main() metoda"); } }

Prilikom rada sa izuzecima moe se desiti jedna od sledeih situacija: Metoda u kom se izuzetak generie nema blok try-catch-finally izuzetak e biti prosle en sledeoj metodi sa steka, izvravanje tekue metode prekinuto i njen aktivacioni slog bie uklonjen sa steka.

44

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Metoda u kom se izuzetak generie ima blok try-catch-finally i ima blok koji moe da obradi dati izuzetak izuzetak e biti obra en izvravanjem bloka catch, zatim e biti izvren blok finally (ukoliko postoji), nakon ega se izvravanje nastavlja normalno. Uvek se izvrava samo blok catch sa ijim je argumentom dati izuzetak kompatibilan. Moe se izvriti najvie jedan blok catch; svi drugi blokovi catch se preskau. Metoda u kom se izuzetak generie ima blok try-catch-finally ali nema blok catch koji moe da obradi dati izuzetak bie izvren blok finally (ukoliko postoji), metoda e biti prekinuta, a izuzetak e biti prosle en sledeoj metodi na steku.
catch

Ukoliko se program pokrene uz navo enje 56 u komandnoj liniji i ako se unese 2 kao delilac, program e se izvriti bez prekida koje izaziva generisanje izuzetaka i ispisati:
Unesite delilac 2 Rezultat deljenja je 28 finally izvrsen u main() metodu kraj main() metoda

Kako je blok try izvren bez prekida, svi blokovi catch bie preskoeni. Izvrie se blok finally i preostali kd metode. Ukoliko prilikom izvravanja do e do pojave izuzetka i ako taj izuzetak moe biti obra en, program nastavlja sa normalnim radom. Pretpostavimo da u komandnoj liniji nije uneen znakovni niz. Prilikom pristupanja elementu niza koji ne postoji u redu 28 bie generisan izuzetak:
Unesite delilac 9 java.lang.ArrayIndexOutOfBoundsException: 0 at TryCatchFinally.main(TryCatchFinally.java:28) Izuzetak obradjen u main() metodu finally izvrsen u main() metodu kraj main() metoda

Red 29 se nee izvriti. Poto blok catch sadri rukovalac za izuzetak tipa ArrayIndexOutOfBoundsException, izuzetak e biti obra en, kao to se vidi i iz rezultata izvravanja programa Izuzetak obradjen u main() metodu. Nakon izvravanja odgovarajueg bloka catch, bie izvren i blok finally. Poto je izuzetak obra en, program e nastaviti sa normalnim izvravanjem i izvrie naredbu u redu 38. Ukoliko se za delilac prosledi 0, doi e do deljenja sa 0 u metodi deli(). Metoda deli() nema blok try-catch-finally, pa e izuzetak ArithmeticException biti prosle en sledeoj metodi na steku, u ovom sluaju metodi podeli(). Metoda podeli() ima blok try-catch-finally, ali ne poseduje blok catch sa ijim argumentom je izuzetak komaptibilan. Metoda podeli() e prekinuti izvravanje, a kako nema blok finally, samo e proslediti izuzetak sledeoj metodi sa steka izvravanja. Ni metoda main() nema odgovarajui blok catch, tako da e se izvriti samo blok finally, nakon ega e izvravanje metode biti prekinuto. Ova metoda je bila poslednja na steku izvravanja, pa e obrada izuzetka biti predata osnovnom rukovaocu izuzecima glavne niti. 45

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


Unesite delilac 0 Exception in thread "main" java.lang.ArithmeticException: / by zero at TryCatchFinally.deli(TryCatchFinally.java:19) at TryCatchFinally.podeli(TryCatchFinally.java:10) at TryCatchFinally.main(TryCatchFinally.java:28) finally izvrsen u main() metodu

Oblast vanosti argumenta bloka catch je sam blok. Da bi izuzetak bio obra en, tip izuzetka mora biti kompatibilan sa tipom argumenta bloka catch. Ukoliko postoji blok catch iji je argument je tipa superklase neke od klasa argumenata u blokovima catch koji se hronoloki nalaze iza njega, prevodilac e prijaviti greku, jer se blok catch potklase nikada nee izvriti.
} catch(Exception e){ ... } catch(IOException ioe){ // Kompajler e se poaliti da je ovaj deo koda nedostupan ... }

46

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Osnovni U/I
U/I tokovi predstavljaju razliite vrste dolaznih ili odlaznih izvora podataka kao to su datoteke na disku, spoljni ure aji, drugi programi i memorijski blokovi. Tokovi podravaju razliite vrste podataka ukljiujui bajtove, osnovne tipove, lokalizovane karaktere i objekte. Bez obzira na vrstu, svi tokovi predstavljaju jednostavan model ka programu koji ih koristi. Tok je niz podataka. Program koristi ulazne tokove da bi itao podatke sa izvora:

itanje podataka sa ulaznog toka Koristei izlazne tokove program moe da pie podatke na izlaz:

Pisanje podataka na izlazni tok Java U/I paket sadri mnoge klase koje se koriste za itanje i pisanje podataka. Veina realizovanih klasa su sekvencijalni tokovi. Sekvencijalni tokovi se mogu podeliti u dve grupe: prva koja ita i pie binarne podatke i drugu koja koja ita i pie Unicode znakove. Svaka od realizovanih klasa ima svoje specijalnosti kao to su itanje iz ili pisanje u datoteku, filtriranje podataka koji se itaju ili piu ili serijalizacija objekata. Tokovi se mogu podeliti u nekoliko grupa:

47

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


Tokovi bajtova koji rukuju binarnim podacima. Tokovi karaktera rukuju karakterim, automatski vrei prilago avanje lokalnim podeavanjima. Tokovi blokova optimizuju ulaz i izlaz smanjujui broj poziva osnovnih operacija. Pretraga i formatiranje omoguuju programu da ita i pie formatizovani tekst. U/I sa komandne linije opisuje standardne tokove i konzolni objekat. Tokovi tipova podataka(eng. Data Streams) obra uju binarni U/I osnovnih tipova podataka i znakovnih nizova (eng. Strings). Tokovi objekata slue za binarni U/I objekata.

Tokovi bajtova
Programi koriste tokove bajtova za ulaz i izlaz 8-bitnih podataka (bajtova). Postoje razliite vrste tokova bajtova ije je koritenje veoma slino a najvie se razlikuju u nainu na koji se kreiraju. Svi oni nasle uju osnovne klase InputStream i OutputStream. Primer koji sledi koristi datoteke kao U/I tokove pomou klasa FileInputStream i FileOutputStream. Program CopyBytes ita bajt po bajt iz ulaznog toka i kopira ga na izlaz u okviru petlje while. Iako je u pitanju bajt, U/I funkcija read smeta rezultat u promenljivu tipa int. Ovo omoguuje vraanje vrednosti (-1) kao znaka da je ulazni tok doao do kraja datoteke. Vrednost promenljive se uva u
donjih import import import 8 bita. java.io.FileInputStream; java.io.FileOutputStream; java.io.IOException;

public class CopyBytes { public static void main(String[] args) throws IOException { FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream("xanadu.txt"); out = new FileOutputStream("outagain.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } }

48

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Veoma je vano zatvoriti tokove nakon prestanka njihovog korienja . Korienje finally bloka garantuje da e se tokovi zatvoriti ak i u sluaju greke. Jedna od moguih greaka je neuspeno otvaranje jednog od tokova pri emu bi vrednost promenljive povezane sa njime ostala null. Iz tog razloga se pre zatvaranja toka vri provera vrednosti promenjivih in i out. Tokovi bajtova se koriste samo za najosnovniji U/I i svi ostali tipovi tokova su zasnovani na njemu.

Tokovi znakova
Java platforma za zapis karaktera koristi Unicode standard. Tokovi karaktera automatski prevode unutranji format na lokalni set olakavajui programeru rukovanje. U veini aplikacija U/I sa tokovima karaktera nije mnogo komplikovaniji od rada sa tokovima bajtova. Svi tokovi karaktera nasle uju klase Reader i Writer. Kao primer korienja bie prokazani tokovi karaktera koji rade sa datotekama FileReader i FileWriter.
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopyCharacters { public static void main(String[] args) throws IOException { FileReader inputStream = null; FileWriter outputStream = null; try { inputStream = new FileReader("xanadu.txt"); outputStream = new FileWriter("characteroutput.txt"); int c; while ((c = inputStream.read()) != -1) { outputStream.write(c); } } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } } }

Najvea razlika u odnosu na prethodni primer jeste korienje FileReader i FileWriter za ulaz i izlaz umesto FileInputStream and FileOutputStream.. Kao i CopyBytes, CopyCharacters koristi promenljivu tipa int za itanje i pisanje u tokove. Za razliku od CopyBytes u ovom primeru se vrednost promenljive uva u donjih 16 bita. Tokovi karaktera uglavnom koriste tokove bajtova za osnovne U/I operacije, dok sami vre konverziju karaktera. FileReader recimo koristi FileInputStream dok FileWriter koristi FileOutputStream. 49

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Linijski orijentisan U/I


U/I znakova je obino vei od pojedinanog karaktera. Jedna od estih formi je linija koja predstavlja niz znakova zavren oznakom za novi red koje mogu biti razliite ("\r\n", "\r", "\n"). Podrka bilo kojem od ovih znakova omoguuje rad programa sa datotekama kreiranim na razliitim operativnim sistemima. U narednom primeru emo prepraviti CopyCharacters kako bi ga prilagodili radu sa linijama. To emo postii korienjem klasa BufferedReader i PrintWriter.
import import import import import java.io.FileReader; java.io.FileWriter; java.io.BufferedReader; java.io.PrintWriter; java.io.IOException;

public class CopyLines { public static void main(String[] args) throws IOException { BufferedReader inputStream = null; PrintWriter outputStream = null; try { inputStream = new BufferedReader(new FileReader("xanadu.txt")); outputStream = new PrintWriter(new FileWriter("characteroutput.txt")); String l; while ((l = inputStream.readLine()) != null) { outputStream.println(l); } } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } } }

Funkcija readLine ita liniju teksta koja se potom ispisuje na izlaz pomou metode println koja na kraj niza znakova dodaje terminator linije koji odgovara korienom operativnom sistemu i koji ne mora biti isti kao i terminator iz ulazne datoteke.

50

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Baferovani tokovi
U prethodnim primerima koriten je uglavnom nebaferovani U/I. To znai da svaka operacija itanja i pisanja se direktno obraa operativnom sistemu. Ovo dosta usporava program jer svaki takav zahtev pokree pristup disku, mrenim resursima i sline zahtevne operacije. Da bi se to izbeglo Java platforma prua podrku za baferovani U/I. Ulazni tokovi blokova itaju podatke iz memorijskih blokova (bafera), a operativni sistem se poziva samo kada je taj blok prazan. Slino tome, izlazni baferovani tokovi piu u memorijski blok, a operativni sistem se poziva samo kada je blok pun. Program moe da pretvori nebaferovani tok u baferovani tako to e proslediti nebaferovani tok kao argument konstruktoru klase baferovanog toka. Primer CopyCharacters se moe na sledei nain modifikovati da bi koristio baferovani tok:
inputStream = new BufferedReader(new FileReader("xanadu.txt"));

outputStream = new BufferedWriter(new FileWriter("characteroutput.txt"));

Klase baferovanih tokova koje se koriste za gne enje nebaferovanih tokova su BufferedInputStream i BufferedOutputStream za binarne tokove, dok se za znakovne tokove koriste BufferedReader i BufferedWriter. U odre enim situacijama ima smisla vriti ispis iz bafera u kritinim trenucima bez ekanja da bude pun. Ovaj postupak se naziva pranjenje bafera. Neke klase tokova blokova podravaju automatsko pranjenje, koje se aktivira argumentima konstruktora. U tom sluaju odgovarajui doga aji e pokrenuti pranjenje bafera. Pranjenje se tako e moe pokrenuti i pozivom metode flush. Ovu metodu imaju svi tokovi ali ona ima efekta samo kod tokova blokova.

U/I sa komandne linije


Java programi se esto pokreu iz komandne linije i komuniciraju sa korisnikom pomou iste. Java platforma prua podrku ovoj vrsti komunikacije pomou standardnih tokova i konzole. Standardni tokovi su podrani od strane mnogih operativnih sistema. Oni najee itaju ulaz sa tastature i ispisuju izlaz na ekran. Java platforma prua podrku za tri razliita standardna toka Standard Input, kojem se pristupa preko System.in, Standard Output, kojem se pristupa preko System.out i Standard Error, kojem se pristupa preko System.err. Ovi objekti su inicijalno deklarisani i nema potrebe za njihovim otvaranjem. Iako je za oekivati da su u pitanju tokovi karaktera, iz istorijskih razloga oni su definisani kao tokovi bajtova.System.out i System.err su definisani kao PrintStream objekti, pri emu imaju dosta mogunosti koje pruaju tokovi karaktera. System.in je tok bajtova bez podrke za znakovne tokove. Da bi se dobila ova podrka potrebno je ugnezditi(umotati) System.in u InputStreamReader.

Tokovi tipova podataka (Data Streams)


out = new DataOutputStream(new BufferedOutputStream(new

51

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


FileOutputStream(dataFile))); for (int i = 0; i < prices.length; i ++) { out.writeDouble(prices[i]); out.writeInt(units[i]); out.writeUTF(descs[i]); }

Tokovi tipova podataka podravaju binarni U/I osnovnih tipova podataka (boolean, char, byte, short, int, long, float, i double) kao i promenljivih tipa znakovni niz. Sve klase tokova tipova podataka realizuju ili DataInput ili DataOutput ablone. U primeru koji sledi(DataStreams) bie prikazane najee koritene implementacije, DataInputStream i DataOutputStream. Potrebno je znati da tokovi tipova podataka umesto negativne povratne vrednosti kao signal za zavretak datoteke generie izuzetak EOFException. Tako e i sve realizacije DataInput metoda koriste umesto EOFException povratnih vrednosti.

Tokovi objekata
Tokovi objekata pruaju podrku za U/I objekata. Veina standardnih klasa podrava serijalizaciju svojih objekata implementirajui ablon Serializable. Klase tokova objekata su ObjectInputStream i ObjectOutputStream koje realizuju ObjectInput i ObjectOutput, naslednike DataInput and DataOutput.To znai da su sve osnovne metode iz tokova podataka raspoloive i za tokove objekata, stoga tok objekata moe biti meavina osnovnih tipova i objekata. Ovo je prikazano u primeru ObjectStreams. Ukoliko readObject() ne vrati objekat oekivanog tipa, pokuaj njegovog pretvaranja moe dovesti do generisanja ClassNotFoundException izuzetka. U ovom primeru to se ne moe dogoditi, tako da se ne pokuava njegovo hvatanje i obrada. Umesto toga, dodajui ClassNotFoundException u list throws metode main, dajemo do znanja prevodiocu da smo svesni te mogunosti. Metode writeObject i readObject su jednostavne za koritenje, ali one sadre sofisticirane mogunosti koritenja objekata. U klasi Calendar koja sadri samo osnovne tipove, ovo nema naroitog znaaja, ali ima kod sloenijih objekata koji mogu sadrati reference na druge objekte u sebi. Ukoliko sa readObject itamo objekat iz toka moramo biti u mogunosti da proitamo ispravno i sve objekte koje je originalni objekat referencirao. Referenciran objekti tako e mogu sadrati reference na druge objekte. U ovakvoj situaciji writeObject zapisuje itavu mreu objekata u tok. To je prikazano na sledeoj slici, gde je writeObject pozvana za upisivanje objekta a. Ovaj objekat sadri reference na objekte b i c, pri emu b sadri reference na objekte d i e. writeObject ne zapisuje samo a ve i sve ostale objekte neophodne za njegovu potpunu rekonstrukciju. Kada se a proita pomou readObject i ostala etiri objekta se tako e itaju iz toka.

52

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

itanje i pisanje objekata u i iz toka

53

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Rad sa procesima i nitima


Svaki proces ima svoj memorijski prostor. Niti postoje u okviru procesa - svaki proces ima barem jednu nit. Niti dele resurse od procesa, ukljuujui tu memoriju i otvorene datoteke. Java aplikacija moe da kreira dodatne procese koristei klasu ProcessBuilder. Odnos jednog programa (procesa) sa dve niti je prikazan na sledeoj slici:

Definisanje niti Prilikom definisanja niti, neophodno je odrediti koji kod e se izvravati u datoj niti. Dva naina za to su: 1. Obezbedite objekat koji realizuje suelje Runnable. public class HelloRunnable implements Runnable {
public void run() { System.out.println("Zdravo! Javljam se iz niti!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } }

2. Nasledite klasu Thread. Ova klasa ve realizuje suelje Runnable, ali njena metoda run ne radi nita.
public class HelloThread extends Thread { public void run() { System.out.println("Zdravo! Javljam se iz niti!"); } public static void main(String args[]) { (new HelloThread()).start(); } }

54

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Prekidi Prekid je indikacija kojom se odre enoj niti kae da bi trebala da prekine sa izvravanjem trenutnog toka programa, te da pone da radi neto drugo. Da bi ovaj mehanizam radio pravilno, nit kojoj se upuuju prekidi mora da podrava ove prekide.
for (int i = 0; i < importantInfo.length; i++) { //Pause for 4 seconds try { Thread.sleep(4000); } catch (InterruptedException e) { //We've been interrupted: no more messages. return; } //Print a message System.out.println(importantInfo[i]); }

ta treba raditi ukoliko nit troi puno vremena na pozive koji ne generiu izuzetke tipa InterruptedException? U tom sluaju, neophodno je periodino pozivati funkciju Thread.interrupted, koja moe da kae da li je u me uvremenu neko poslao prekid datoj niti.
for (int i = 0; i < inputs.length; i++) { heavyCrunch(inputs[i]); if (Thread.interrupted()) { //We've been interrupted: no more crunching. return; } }

U ovom primeru mogue je dodati i kreiranje novog izuzetka. Npr:


if (Thread.interrupted()) { throw new InterruptedException(); }

Kako proveriti da li je dolo do prekida? Za ovu svrhu, postoji statusna zastavica(eng. flag) koja nosi ovu informaciju. Funkcije koje je koriste su: - Thread.interrupt (postavlja zastavicu) - Thread.interrupted (statika funkcija koja vraa informaciju i brie vrednost) - Thread.isInterrupted (nestatika funkcija koja vraa informaciju ali ne brie vrednost) - Sve funkcije koja bacaju izuzetak tipa InterruptedException (one istovremeno i briu datu vrednost) Spojevi Spojevi su naini kojima se izvavanje jedne niti odlae do zavretka druge niti. Ukoliko jedna nit eli da odloi nastavak svog rada dok se druga nit t ne zavri, treba koristiti sledei poziv:
t.join();

55

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Imajte na umu da i ova funkcija generie izuzetke tipa InterruptedException. Primer: SimpleThreads Glavna nit kreira novu nit MessageLoop, i eka da se ova zavri. Ako je vreme potrebno da se nova nit zavri suvie dugo, glavna nit je prekida. to se tie niti MessageLoop, ona ispisuje niz poruka. Ako je neko prekine pre nego to je ispisala sve poruke, ona ispisuje poruku kojom to obelodanjuje i gasi se.
//SimpleThreads.java public class SimpleThreads { //Display a message, preceded by the name of the current thread static void threadMessage(String message) { String threadName = Thread.currentThread().getName(); System.out.format("%s: %s%n", threadName, message); } private static class MessageLoop implements Runnable { public void run() { String importantInfo[] = { "Anders Niklas Andersson - Lead vocals & guitars", "Jens Robert Dahlqvist - Guitars", "Kenny Hakansson - Bass", "Matz Robert Eriksson - Drums & vocals", "Anders Lindstrom - Piano" }; try { for (int i = 0; i < importantInfo.length; i++) { //Pause for 4 seconds Thread.sleep(4000); //Print a message threadMessage(importantInfo[i]); } } catch (InterruptedException e) { threadMessage("I wasn't done!"); } } } public static void main(String args[]) throws InterruptedException { //Delay, in milliseconds before we interrupt MessageLoop //thread (default one hour). long patience = 1000 * 60 * 60; //If command line argument present, gives patience in seconds. if (args.length > 0) { try { patience = Long.parseLong(args[0]) * 1000; } catch (NumberFormatException e) { System.err.println("Argument must be an integer."); System.exit(1); } } threadMessage("Starting MessageLoop thread"); long startTime = System.currentTimeMillis(); Thread t = new Thread(new MessageLoop()); t.start(); threadMessage("Waiting for MessageLoop thread to finish"); //loop until MessageLoop thread exits while (t.isAlive()) { threadMessage("Still waiting..."); //Wait maximum of 1 second for MessageLoop thread to //finish. t.join(1000); if (((System.currentTimeMillis() - startTime) > patience) &&

56

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


t.isAlive()) { threadMessage("Tired of waiting!"); t.interrupt(); //Shouldn't be long now -- wait indefinitely t.join(); } } threadMessage("Finally!"); } }

Sinhronizacija Kompleksnije aplikacije najee imaju vie niti, od kojih svaka ima svoj zadatak (npr. rad sa datotekama, prihvatanje unosa, ispisivanje rezultata, itd).

Komunikacija me u ovim blokovima se najee vri preko deljenih resursa, i neophodno je da se usaglasi pristup nad tim deljenim resursima. Klasian primer kod kojeg nam treba sinhronizacija je broja.
class Counter { private int c = 0; public void increment() { c++; } public void decrement() { c--; } public int value() { return c; } }

Jedno mogue reenje je pravljenje sinhronizovanih metoda. To se radi dodavanjem kljune rei synchronized.
public class SynchronizedCounter { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--;

57

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


} public synchronized int value() { return c; } }

Konstruktori ne mogu da imaju atribut synchronized. Ugra eni mehanizam za blokiranje Svaki objekat ima ugra en mehanizam za blokiranje. Celokupan sistem sinhronizacije je naslonjen na ovaj mehanizam. Pored sinhronizovanih metoda, imamo i sinhronizovane naredbe. Kod njih je neophodno odrediti nad kojim objektom e se vriti blokada, odnosno iji mehanizam za blokiranje e biti korien.
public void addName(String name) { synchronized(this) { lastName = name; nameCount++; } nameList.add(name); }

Mogue je u okviru jedne klase koristiti vie objekata za sinhronizaciju. Npr.


public class MsLunch { private long c1 = 0; private long c2 = 0; private Object lock1 = new Object(); private Object lock2 = new Object(); public void inc1() { synchronized(lock1) { c1++; } } public void inc2() { synchronized(lock2) { c2++; } } }

Atomski pristup i atomske promenjive Atomske akcije su one akcije kod kojih se promena deava odjednom. Sledee akcije se nazivaju atomskim: - akcije itanja i pisanja promenjivih koje sadre referencu, kao i akcije itanja i pisanja nad primitivnim promenjivama (svi tipovi izuzev long i double) - akcije itanja i pisanja za sve promenjive koje su deklarisane sa volatile.

58

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave to se tie atomskih promenjivih, njih koristimo kad hoemo da imamo sinhronizovan pristup promenjivim, bez potrebe da metodi u kojoj se pristupa toj promenjivoj dodelimo atribut synchronized. Kako se to realizuje na primeru ve pomenutog brojaa? Jednostavnom zamenom tipa promenjive c: iz int u AtomicInteger.
import java.util.concurrent.atomic.AtomicInteger; class AtomicCounter { private AtomicInteger c = new AtomicInteger(0); public void increment() { c.incrementAndGet(); } public void decrement() { c.decrementAndGet(); } public int value() { return c.get(); } }

Problemi koji se javljaju kod sinhronizacije: Mrtva petlja (sluaj kad su dve niti zablokirane zauvek) Izgladnjivanje (sluaj kada jedna nit dui period nije u mogunosti da pristupi deljenim resursima zbog pohlepe druge niti koja pristupa istim resursima) iva petlja (sluaj kada dve niti blokiraju jedna drugu jer akcija jedne niti prouzrokuje akciju druge niti, i obrnuto)

uvane oblasti Upotreba while petlje u jednoj niti u cilju da registrujemo da je dolo do promene neke vrednosti od strane druge niti ili procesa, krajnje je nepoeljna. Takav primer je:
public void guardedJoy() { //Simple loop guard. Wastes processor time. Don't do this! while(!joy) {} System.out.println("Joy has been achieved!"); }

Mnogo efikasniji nain je da se kae niti da se zaustavi dok ne do e do odre ene promene, odnosno do trenutka kad je neka druga nit obavesti da je dolo do promene. Ovo se postie primenom funkcije wait.
public synchronized guardedJoy() { //This guard only loops once for each special event, which may not //be the event we're waiting for. while(!joy) { try {

59

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


wait(); } catch (InterruptedException e) {} } System.out.println("Joy and efficiency have been achieved!"); }

Neka druga nit je u ovom sluaju zaduena da obavesti o promeni nakon to promeni vrednost joy. To se ini funkcijom notifyAll().
public synchronized notifyJoy() { joy = true; notifyAll(); }

Postoji mogunosti i korienja funkcije notify, ali se ona primenjuje kada je potrebno obavestiti samo jednu nit o promeni, i kad nije bitno koja je to nit me u onima koje ekaju. ivotni ciklus jedne niti

60

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Primer: Producer-Consumer U ovom primeru, podaci se dele izme u dve niti: jedna je proizvo aka (Producer) koja generie podatke, dok je druga potroaka (Consumer), koja ih upotrebljava. Ove dve niti komuniciraju jedna sa drugom preko deljenog objekta (Drop). Koordinacija je kljuna: potroa ne sme da pokua da preuzme podatke pre nego to ih proizvo a isporui, dok proizvo a ne sme da pokua da isporui nove podake dok potroa nije preuzeo prethodne.
//Drop.java public class Drop { //Message sent from producer to consumer. private String message; //True if consumer should wait for producer to send message, false //if producer should wait for consumer to retrieve message. private boolean empty = true; public synchronized String take() { //Wait until message is available. while (empty) { try { wait(); } catch (InterruptedException e) {} } //Toggle status. empty = true; //Notify producer that status has changed. notifyAll(); return message; } public synchronized void put(String message) { //Wait until message has been retrieved. while (!empty) { try { wait(); } catch (InterruptedException e) {} } //Toggle status. empty = false; //Store message. this.message = message; //Notify consumer that status has changed. notifyAll(); } }

//Producer.java import java.util.Random; public class Producer implements Runnable { private Drop drop; public Producer(Drop drop) { this.drop = drop; } public void run() { String importantInfo[] = { "Anders Niklas Andersson - Lead vocals & guitars", "Jens Robert Dahlqvist - Guitars", "Kenny Hakansson - Bass",

61

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


"Matz Robert Eriksson - Drums & vocals", "Anders Lindstrom - Piano" }; Random random = new Random(); for (int i = 0; i < importantInfo.length; i++) { drop.put(importantInfo[i]); try { Thread.sleep(random.nextInt(5000)); } catch (InterruptedException e) {} } drop.put("Done"); } }

//Consumer.java import java.util.Random; public class Consumer implements Runnable { private Drop drop; public Consumer(Drop drop) { this.drop = drop; } public void run() { Random random = new Random(); for (String message = drop.take(); ! message.equals("DONE"); message = drop.take()) { System.out.format("MESSAGE RECEIVED: %s%n", message); try { Thread.sleep(random.nextInt(5000)); } catch (InterruptedException e) {} } } }

//ProducerConsumerExample.java public class ProducerConsumerExample { public static void main(String[] args) { Drop drop = new Drop(); (new Thread(new Producer(drop))).start(); (new Thread(new Consumer(drop))).start(); } }

Vremenske kontrole Da biste uspeno koristili vremensku kontrolu, potrebno je da sledite sledee korake: 1. Realizujte potklasu od klase TimerTask. Njena metoda run e sadrati kod koji e se izvriti nakon isteka definisanog vremena. 2. Napravite jednu vremensku kontrolu, odn. klasu Timer. 3. Napravite jedan objekat tipa TimerTask. 4. Podesite kontrolu na vreme koje je potrebno da istekne pre nego to se izvri zadati kod.

62

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


//Reminder.java import java.util.Timer; import java.util.TimerTask; /** * Simple demo that uses java.util.Timer to schedule a task to execute * once 5 seconds have passed. */ public class Reminder { Timer timer; public Reminder(int seconds) { timer = new Timer(); timer.schedule(new RemindTask(), seconds*1000); } class RemindTask extends TimerTask { public void run() { System.out.format("Time's up!%n"); timer.cancel(); //Terminate the timer thread } } public static void main(String args[]) { System.out.format("About to schedule task.%n"); new Reminder(5); System.out.format("Task scheduled.%n"); } }

Vremensku kontrolu prekidamo putem funkcije cancel. U ovom primeru se prilikom podeavanja vremena isteka kontrole, koristi broj milisekundi koje treba da isteknu pre nego to se aktivira zadati kod. Mogue je tako e koristiti i tano vreme kada neto treba da se dogodi.
//Get the Date corresponding to 11:01:00 pm today. Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 1); calendar.set(Calendar.SECOND, 0); Date time = calendar.getTime(); timer = new Timer(); timer.schedule(new RemindTask(), time);

Ukoliko je potrebno da se data vremenska kontrola periodino poziva, na raspolaganju stoje razliite realizacije funkcije schedule.
schedule(TimerTask task, long schedule(TimerTask task, Date scheduleAtFixedRate(TimerTask scheduleAtFixedRate(TimerTask delay, long period) time, long period) task, long delay, long period) task, Date firstTime, long period)

// AnnoyingBeep.java import java.util.Timer; import java.util.TimerTask; import java.awt.Toolkit; /** * Schedule a task that executes once every second. */

63

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


public class AnnoyingBeep { Toolkit toolkit; Timer timer; public AnnoyingBeep() { toolkit = Toolkit.getDefaultToolkit(); timer = new Timer(); timer.schedule(new RemindTask(), 0, //initial delay 1*1000); //subsequent rate } class RemindTask extends TimerTask { int numWarningBeeps = 3; public void run() { if (numWarningBeeps > 0) { toolkit.beep(); System.out.format("Beep!%n"); numWarningBeeps--; } else { toolkit.beep(); System.out.format("Time's up!%n"); //timer.cancel(); //Not necessary because //we call System.exit System.exit(0); //Stops the AWT thread //(and everything else) } } } public static void main(String args[]) { System.out.format("About to schedule task.%n"); new AnnoyingBeep(); System.out.format("Task scheduled.%n"); } }

Java Native
Ukoliko postoji potreba da vaa aplikacija koristi funkcionalnost u nekoj biblioteci na samom OS, to je mogue uraditi sledeim postupkom. Postoji est koraka u tom postupku, i prikazaemo ih na primeru gde se trai od sistemske biblioteke trai da ispie "Hello world!". Korak 1: Napiite kod za Javu.
//HelloWorld.java class HelloWorld { public native void displayHelloWorld(); static { System.loadLibrary("hello"); } public static void main(String[] args) { new HelloWorld().displayHelloWorld(); } }

Korak 2: Prevedite napisani kod.


javac HelloWorld.java

64

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Korak 3: Kreirajte zaglavlje (.h).
javah -jni HelloWorld

Rezultat ovog koraka je zaglavlje HelloWorld.h


/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: HelloWorld * Method: displayHelloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif

Ime funkcije koju treba realizovati u izvornom okruenju se automatski kreira po sledeem ablonu:

Korak 4: Napiite metodu u izvornom okruenju


#include <jni.h> #include "HelloWorld.h" #include <stdio.h> JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj) { printf("Hello world!\n"); return; }

Korak 5: Kreirajte deljenu biblioteku. U terminologiji Windows operativnih sistema, pod deljenim bibliotekama se smatraju dinamike (DLL) biblioteke. Korak 6: Pokrenite program
java HelloWorld

65

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Grafiki prikaz ovih koraka je:

66

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Java GUI
JFC (Java Foundation Classes)
Za izradu Java aplikacija sa grafikim korisnikom spregom koriste se JFC klase. U ovu grupu spadaju klase iz sledeih biblioteka: AWT (Abstract Window Toolkit), Swing i Java2D. Klase iz ovih paketa se koriste za razvoj grafikih aplikacija u Javi bez obzira na operativni sistem na kojem se izvrava JVM (Java Virtual Machine), Windows, Linux ili Mac OS X.

AWT
Klase iz ove biblioteke su prve koriene za izradu korisnikih sprega od nastanka Java programskog jezika. Programeru daju na raspolaganje standardne grafike kontrole poput dugmeta (Button), klizaa (Slider), itd. AWT obezbe uje reakciju na poruke i doga aje od strane korisnika (GUI Event Subsystem). AWT biblioteka za izradu korisnike sprege koristi resurse operativnog sistema ispod JVM. Tako, na primer, za iscrtavanje dugmeta i implementaciju reakcije na doga aje, koriste se rutine operativnog sistema. To je jedna od veih mana ovih klasa, jer jedna aplikacija ne izgleda potpuno isto na svim platformama, tj. operativnim sistemima. Osnova svake GUI aplikacije je okvir (Frame), koji ima svoj naslov i podrava osnovne operacije za uveavanje, smanjivanje i zatvaranje prozora. U okvir se dodaje panel (Panel) u koji e dalje da se dodaju sve ostale komponente, kao to su dugme, labela, Potrebno je, tako e, registrovati svaku AWT aplikaciju za doga aje koji stiu sa tastature, to je objanjeno u sledeem primeru. Sledi jednostavan primer kreiranja prozora pomou klasa iz AWT biblioteke, sa komentarima. Datoteka: AWTExample.java
import java.awt.*; import java.awt.event.*; /** * Ova klasa predstavlja jednostavan primer kreiranja AWT okvira koji * dugme i labelu koja ispisuje koliko puta je pritisnuto dugme. */ public class AWTExample{ private Button button private Frame frame = private Label label = private static String private int numClicks = new Button("Dugme"); new Frame("Jednostavan AWT primer"); new Label(labelPrefix + "0 "); labelPrefix = "Broj pritisaka na dugme: "; = 0;

sadrzi jedno

/** * Javni konstruktor bez argumenata */ public AWTExample() { // podesavanje velicine prozora

67

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


frame.setSize(400, 200); // dodavanje osluskivaca na spoljne dogadjaje prozora frame.addWindowListener( // implementacija apstraktne klase WindowAdapter i njenih metoda // koje su nam od interesa new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); // implementacija interfejs klase koja prima spoljne dogadjaje dugmeta ActionListener buttonListener = new ActionListener() { // metoda koja se mora implementirati za obradu dogadjaja public void actionPerformed(ActionEvent ae) { // string koji sadrzi natpis na dugmetu String action = ae.getActionCommand(); if (action.equals("Dugme")) { numClicks++; label.setText(labelPrefix + numClicks); } } }; // kreiranje panela koji sadrzi ostale komponente Panel panel = new Panel(); panel.add(button); panel.add(label); button.addActionListener(buttonListener); // dodavanje panela u prozor frame.add(panel, BorderLayout.NORTH); frame.setVisible(true); } public static void main(String[] args) { AWTExample mainFrame = new AWTExample(); } }

Zadatak 1: a) Prouiti izvorni kod i pokrenuti aplikaciju. b) Dodati jo jedno dugme sa nazivom Odustani, na iji klik e da se zatvori prozor.
Napomena: metoda koja zatvara okvir (Frame) je dispose(). Vreme za izradu zadatka je 15 min.

SWING
Swing biblioteka klasa, tako e, daje na raspolaganje veliki broj klasa za rad sa GUI aplikacijama u Javi. Koristi komponente, kao i AWT, dugme, klizae itd. Razlika u odnosu na AWT biblioteku, je u tome to Swing aplikacija izgleda isto na svim platformama, za razliku od AWT-a, jer ne mapira direktno funkcije operativnog sistema za rad sa grafikom (Rutine u Swing klasama same rade obradu slike, ne oslanjaju se u velikoj meri na rutine operativnog sistema). Glavni nedostatak Swing biblioteke je manja brzina izvravanja programa u odnosu na programe pisane pomou AWT biblioteke. Swing klase su proirenje AWT klasa, tj. njihove funkcionalnosti, i sve to pruaju AWT klase, imaju i Swing klase. Komponente Swing klasa se mogu prepoznati po slovu J ispred definicije komponente. Na primer, klasi Button iz AWT biblioteke odgovara klasa JButton u Swing biblioteci. Jedna od dobrih mogunosti prilikom kreiranja GUI aplikacija je postojanje predefinisanih izgleda, odnosno, rasporeda komponenti u prozoru, Layout. Za korienje 68

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave layout-a zaduene su LayoutManager klase, i one sve implementiraju interfejs LayoutManager. Mogu se nai u java.awt paketu klasa (GridLayout, FlowLayout, ). U narednom primeru se koristi FlowLayout, koji sve komponente koje se dodaju na panel postavlja sekvencijalno. Sledi primer jednostavne Swing aplikacije sa korisnim komentarima: Datoteka: SwingExample.java
import javax.swing.*; import java.awt.*; import java.awt.event.*; /** * * Ova klasa predstavlja jednostavan primer kreiranja Swing okvira koji sadrzi jedno * dugme i labelu koja ispisuje koliko puta je pritisnuto dugme. */ public class SwingExample implements ActionListener{ private private private private private String labelPrefix = "Broj pritisaka na dugme: "; int numClicks = 0; JLabel label = new JLabel(labelPrefix + "0 "); JButton button = new JButton("Ja sam Swing dugme"); JFrame frame = new JFrame("Swing primer");

/** * Javni konstruktor bez argumenata */ public SwingExample(){ /** * definise sta da radi prozor kada se inicira * komanda za zatvaranje prozora. */ frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE); /** * dugmetu dodeljuje odgovarajuci taster, koji u kombinaciji * sa "Alt" tasterom obavlja istu funkciju kao i pritisak misa * na dugme. U ovom slucaju je to taster "i". */ button.setMnemonic(KeyEvent.VK_I); /** * posto ova klasa implementira interfejs ActionListener * dugmetu se moze dodeliti "this" objekat koji osluskuje * spoljne dogadjaje */ button.addActionListener(this); /** * kreira panel na koji se dodaju komponente * koristi se FlowLayout */ JPanel pane = new JPanel(new FlowLayout()); pane.add(button); pane.add(label); //dodaje panel na frame frame.getContentPane().add(pane); //Prikazuje prozor frame.pack(); frame.setVisible(true); } //implementacija metode za obradu dogadjaja public void actionPerformed(ActionEvent e) { numClicks++; label.setText(labelPrefix + numClicks);

69

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


} public static void main(String[] args) { /** * Pozivanje konstruktora se vrsi u posebnoj niti, tako * da aplikacija moze da se izvrsava nezavisno od niti koja * pokrece aplikaciju. Takodje, ovde se registrujemo za tzv. * Event-Dispatching nit (EDT), tj. nit koja sluzi za primanje * dogadjaja sa tastature. EDT je jedina validna nit koja sluzi * za primanje dogadjaja od svih pokrenutih Swing i AWT aplikacija. */ javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run(){ SwingExample mainFrame = new SwingExample(); } }); } }

Zadatak 2: a) Prouiti izvorni kod i pokrenuti aplikaciju. b) Dodati proizvoljan broj komponenata na panel i promeniti layout.
Napomena: Vreme za izradu zadatka je 15 min.

2D grafika
Klasa Graphics se koristi za iscrtavanje najjednostavnijih grafikih elemenata, poput linije, etvorougla, kruga, ispisivanje karaktera itd. Svi ti elementi se crtaju na praznoj povrini koju definie klasa Canvas. Aplikacija mora da nasledi klasu Canvas kako bi imala osnovne funkcionalnosti i bila u stanju da dodaje razne grafike elemente na povrinu. Metoda paint iz klase Canvas se mora redefinisati, i u njoj se vre sva crtanja. Objekat klase Graphics se prosle uje metodi paint koja je tada u stanju da postavlja grafike elemente na povrinu za crtanje. Sledi jednostavan primer. Datoteka: GraphicsExample.java
import java.awt.*; import java.awt.event.*; /** * Jednostavan program koji demonstrira osnovne mehanizme * za koriscenje 2D grafike u Javi pomocu AWT biblioteke klasa. */ public class GraphicsExample { public static void main(String[] args) { Frame f = new Frame("2D Grafika"); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.add(new SmileyCanvas(Color.red, Color.orange), BorderLayout.CENTER); f.pack(); f.setVisible(true); } } /** * Canvas je klasa koja se koristi za iscrtavanja jednostavnih * grafickih elemenata. U ovom primeru, nasa klasa SmileyCanvas * nasledjuje klasu Canvas. Metoda "paint" se redefinise i poziva * se kada se vrsi iscrtavanje komponenata na ekran. */ class SmileyCanvas extends Canvas {

70

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


public SmileyCanvas(Color faceColor, Color backColor) { setForeground(faceColor); setBackground(backColor); } /** * Ova metoda se mora implementirati jer se poziva od strane window * managera prilikom kreiranja prozora, kako bi se znala velicina * prozora koji se crta. */ public Dimension getPreferredSize() { return new Dimension(500,300); } /** * metoda paint se poziva svaki put kada se vrsi iscratavnje * grafickih komponenata */ public void paint(Graphics g) { //definisemo niz karaktera koji ce biti ispisani na ekranu char array[] = {'S','m','i','l','e','y'}; //definisemo velicinu i oblik fonta koji ce se koristiti Font font = new Font("Tahoma",Font.BOLD,25); //uzimamo velicinu prozora Dimension size = getSize(); //izracunavanje potrebnih velicina za kasnije iscrtavanje int d = (Math.min(size.width, size.height))/2; // precnik glave int ed = d/10; // precnik oka int x = (size.width - d)/2; int y = (size.height - d)/3; //crtaj glavu (boja je vec bila podesena u konstruktoru) g.fillOval(x, y, d, d); g.drawOval(x, y, d, d); //podesi boju za oci i iscrtaj ih g.setColor(Color.black); g.fillOval(x+d/3-(ed/2), y+d/3-(ed/2), ed, ed); g.fillOval(x+(2*(d/3))-(ed/2), y+d/3-(ed/2), ed, ed); //nacrtaj usta g.drawArc(x+d/4, y+3*(d/6), d/2, d/3, 0, -180); //nacrtaj kosu (izlomljena linija) //definisemo dva niza koji ce sluziti za iscrtavanje izlomljene linije x=size.width/2; y=size.height/5; int xpoints[] = {x-50, x-20, x, x+30, x+50}; int ypoints[] = {y, y+20, y-10, y+30, y}; g.drawPolyline(xpoints, ypoints, 5); //podesavanje fonta koji ce se koristiti g.setFont(font); //iscrtavanje niza karaktera g.drawChars(array, 0, 6, size.width/2, size.height/4+d); //iscrtavanje stringa g.drawString("Name: ", size.width/2 - 100, size.height/4+d); } }

Zadatak 3: a) Prouiti izvorni kod i pokrenuti aplikaciju. b) Staviti smiley-a u pravougaoni okvir plave boje.
Napomena: Vreme za izradu zadatka je 15 min.

71

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Java Media Framework


JMF arhitektura
Java Media Framework (JMF) omuguava akvziciju, procesiranje, prenos i prezentovanje vremenski baziranih podataka kao to su audio i video podaci. JMF podrava veinu standardnih audio video formata, kao to su AIFF, AU, AVI, GSM, MIDI, MPEG, Quick Time, RMF i WAV. JMF aplikativna sprega (JMF API) omoguava razvoj aplikacija koje su nezavisne od samog operativnog sistema, to je velika prednost Java aplikacija. JMF koristi model slian modelu prikayanom na slici (Slika 1).

Slika 1 Akvizicija, procesiranje i prezentovanje vremesnki baziranih podatka

Izvor podataka (DataSource) predstavlja apstrakciju audio video podataka slino video kaseti, dok aparat za reprodukciju (Player) omoguava njihovo procesiranje i kontrolu. Za akviziciju i prezentovanje audio i video podataka potrebni su odre eni ure aji, kao to su mikorfoni, kamere ili zvunici. Izvor podataka (DataSource) i reprodukcija (Player) su integralni delovi JMF aplikativne sprege i oni predstavlaju vei nivo apstrakcije. Pored ovog nivoa, JMF prua aplikativnu spregu nie apstrakcije, tako da korisnik ima mogunost da implementira razna procesiranja nad ulaznim podacima. Slika 2 daje globalni prikaz JMF aplikativne sprege.

72

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Slika 2 Arhitektura JMF aplikativne sprege

Vremenski Model
JMF meri vreme u nano sekundama. Odre eni momenat u vremenu se prestavlja preko Time objekta. Klase koje podravaju JMF vremeski model implementiraju Clock interfejs. Ovaj interfejs definie sve operacije vezane za vreme i sinhronizaciju koje su potrebne za kontrolu audio i video podataka.

Slika 3 JMF vremenski model

Clock koristi TimeBase kako bi imao uvid i kontrolisao vreme reprodukcije audio i video podataka. TimeBase predstavlja sistemsko vreme. Kako bi kontrolisao vreme, Clock korisiti: TimeBaseStartTime - sistemsko vreme (dobijeno od TimeBase) u trenutku kada prezentacija poinje, MediaStartTime - pozicija u samom toku podataka odakle poinje prezentacija Rate odnos Clock vremena i sistemskog vremena.

Formula koja se koristi je : MediaTime = MediaStartTime + Rate(TimeBaseTime - TimeBaseStartTime)

73

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

JMF Menaderi
Kako bi se uinilo lakim implementiranje aplikacija, JMF koristi vei nivo apstrakcije uvo enjem pojma menadera. JMF koristi etiri vrste menadera: Manager koristi se za stvaranje osnovnih JMF objekata Players, Processors, DataSources, and DataSinks. Stvaranje ovih objekata se radi uvek na isti nain, bez obzira da li se stvaraju JMF predefinisani objekti ili objekti implemenirani od strane korisnika. PackageManager sadri infomacije o raznim JMF paketima. CaptureDeviceManager prua informacije o dostupnim ure ajima za akviziciju (CaptureDevices) PlugInManager zaduen i prua infomacije o raznim dodatnim (plug-in) komponentama za procesiranje kao to su Multiplexers, Demultiplexers, Codecs, Effects, and Renderers.

Svaki JMF program koristi metodu create(), objekta Menager, da formira Player, Processor, DataSources i DataSinks. Ukoliko se podaci dobijaju akvizicijom sa nekog od spoljnih ure aja (kamera, mikrofon) koristi se objekat CaptureDeviceManager, kako bi se saznalo koji su sve ure aji na raspolaganju. Ukoliko se eli kontrola nad samom obradom ulaznih podataka koristi se objekat PlugInManager, kako bi se dobila informacija koje su sve komponente za procesiranje (plugins) registrovane. Ukoliko korisnik eli da registruje svoje komponente koristi se PackageManager.

Model doga aja


JMF koristi model doga aja Event Model, kako bi informisao JMF aplikaciju o tekuem stanju sistema. JMF objekti koji generiu doga aje generiu MediaEvent objekte. Za svaki tip objekta koji generie doga aj, JMF definie i odgovarajui oslukiva tog doga aja (Listener). Ukoliko neka klasa klasa eli da bude obavetena o nekom doga aju ona mora da implementira interfejs oslukivaa i da se registruje objektu koji generie doga aj pozivanjem metode addListener. Kada se generie neki dogo aj, objekat koji ga je generisao prolazi listu registrovanih oslukivaa i obavetava ih o tom doga aju. Controller objekti, kao to su Player i Processor, kao i neki kontrolni objekti kao to je GainControl generiu MediaEvent objekte.

74

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Slika 4 JMF model doga aja

Model podataka
DataSource objekat enkapsulira lokaciju podataka kao i programsku podrku (protokol) koja se koristi za dobijanje podataka. DataSource objekat se formira ili na osnovu JMF MediaLocator ili na osnovu URL (universal resource locator). DataSource kontrolie skup SourceStream objekata. Standardni DataSource koristi niz bajtova kao jedinicu transfera. Sa druge strane postoje i Buffer Data Source koji koriste klasu Buffer kao jedinicu transfera.

Slika 5 - JMF model podataka

75

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave DataSource objekati mogu biti podeljeni na dva tipa, prema tome ko inicira transfer podatka: Pull Data-Source Push Data-Source U JMF-u postoji mogunost kloniranja izvora podatka pozivom metode createCloneableDataSource() objekta Manager. Kao parametar ove metode se prosle uje izyor podataka koji se eli kolnirati. Klonovi se mogu kontrolisati pozivom metoda connect, disconnect, start, i stop kloniranog objekta.

Format podataka
Format podatka u JMF je predstavljen preko Format objekta. Ovaj objekat nosi informaciju o nainu zapisa podataka kao i o samom tipu podataka.

Slika 6 - JMF media formati

AudioFormat nosi infomacije specifine za audio podatke kao to su brzina odabiranja (sample rate), veliina odbirka (bits per sample), broj audio kanala itd. VideoFormat nosi infomacije relevantne za video podatke. Neki od standardnih video fomata su:

IndexedColorFormat RGBFormat YUVFormat JPEGFormat H261Format H263Format

Ukoliko elimo da pratimo promene formata u okviru Controller objekta, implmentira se ControllerListener interfejs i oslukuje se FormatChangeEvents doga aj.

76

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Kontrole
JMF Control objekti pruaju mehanizam kontrolisanja (postavljana kao i dobijanje infomacija) nad atributima nekog objekta. Mnogi JMF objekti kao to su Controller, DataSource, DataSink objekti omoguavaju kontrolu nad njima. Ukoliko neki JMF objekat eli da omogui kontrolu nad njim, potrebno je da taj objekat implementira Controls interfejs. Controls interfejs definie metode, pomou kojih se dobijaju Control objekti, objekta koji eli da se kontrolie. Mnoge kontrole omoguavaju kontrolu preko vizuelnih komponenti (AWT komponente).

Standardne kontrole
JMF definie standardne kontrole Control prikazane na Slika 7

Slika 7 - Standardne JMF kontrole

77

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


Prezentacija

U JMF je proces prezentacije modelovan preko Controller interfejsa. Controller interfejs definie stanja i mehanizam tranzicije izme u njih, za svaki objekat koji kontrolie, prezentuje i vri akviziciju audio/video podataka. Controller generie razliite MediaEvents objekte kako bi notifikovao promene stanja svojim oslukivaima. Oslukivai doga aja moraju da implemetiraju ControllerInterface. JMF API definie dve vrste Controller objekata: Players i Processors.

Players
Player procesira ulazni tok podataka i reprodukuje ih na odre eni ure aj u zavisnosti od tipa podataka.

Slika 8 - JMF player model

Player ne omoguava nikakvu kontrolu nad obradom podataka, niti kontrolu za njiuhov prikaz reprodukcijom.

Slika 9- JMF Player

78

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Player moe biti u jednom od est stanja:

Slika 10- Player stanja

Player u Unrealized stanju je instanciran ali nema nikakvu informaciju o audio/video podacima koje treba da reprodukuje. Kada se prvi put instancira Player preko objekta Manager, one se nalazi u Unrealized stanju. Kada se pozove realize() metoda, Player iz Unrealized stanja prelazi u Realizing stanje. U ovom stanju Player vri alokaciju potrebnih resursa ali nema jo uvek eksluzovno pravo na njih. Nakon alociranja potrebnih resursa, Player prelazi u Realized stanje. U ovom stanju Player zna koji sve reursi su mu potrebni, kao i tip samih podataka koje treba da reprodukuje. Poto u ovom stanju zna kako da reprodukuje podatke, Player u ovom stanju nudi razne kontrole kao i vizuelne komponente. Pozivom prefetch metode, Player prelazi u Prefetching stanje u kome se priprema za prezentaciju podataka. Nakon pripreme, Player prelazi u Prefetched stanje u kom moe biti startovan. Pozivom metode start, Player prelazi u Started stanje.

79

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Processors
Processor objekti se mogu isto koristiti za prezentovanje audio video podataka. Propcessor objekti su specijalizovani Player objekti koji pored standardnih kontrola omoguavaju i kontrolu procesiranja ulaznih podataka.

Slika 11 - JMF Processor model

Kao dodatak, Processor objekti izlazne podatke mogu preko DataSource da proslede sledeem Processor, Player objektu ili da zapiu u podatke datoteku korienjem DataSink objekta.

Slika 12 - JMF Processor

Kao to je reeno Processor za razliku od Player omoguava korisniku da definie implmentira obradu samih podataka. Obrada samih podataka se deli u nekoliko faza:

Slika 13 - Processor faze

80

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave Demultiplexing je proces parsiranja ulaznog toka podatka. Ukoliko se ulazni tok sastoji iz vie razliitih tokova podataka oni se razdvajaju u posebne tokove podataka (Track). Na primer QuickTime datotoeka nakon demultipleksiranja se razdvaja na audio i video tok podataka. Demulktipleksiranje se obavlja automatski ukoliko. Pre-Processing je proces primenjivanja razliitih efekata nad pojedinanim tokom podataka. Coding je proces konverotvanja ulaznih podataka u kompresovani tok podataka. Decoding je proces dekompresije ulaznih podataka. Post-Processing je proces primene efekata nad kompresovanim podacima Multiplexing je proces spajanja kodovanih tokaova odataka u jedan Rendering je proces prezentacije podataka korisniku.

Procesiranje u svakoj fazi je odre eno preko procesnih komponeneta (plug-ins). Ukoliko Processor podrava TrackControls, korisnik selektovanjem odre enog plug-in moe da izabere odre eno procecisranje nad pojedinanim tokom. Postoje pet tipova JMF procesnih komponenti. Demultiplexer parsira ulazni tok podataka kao to su (WAV, MPEG ili QuickTime) Effect primenjuje razliite efekte nad na svakom izdvojenom toku podataka Codec komresija i dekompresija Multiplexer kombinuje vie ulaznih tokova u jedan Renderer procesira tok podataka i prezenuje ga korisniku

Processing kontrole
Da bi dobili kontrolu nad procesiranjem, poziva se Processor metoda getTrackControl koja vraa niz TrackControl objekata za svaki od tokova podataka unutar Processor-a. Pomou TrackControl objekta se mogu definisati efekti, kodeci koji ele da se primene nad tim tokom podataka. Pozivom TrackControl metode getControls dobija se niz kontrola za taj odre eni tok podataka ( kao to su BitRateControl, QualityControl itd).

81

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Primer 1: Jedostavan JMF Player


package example_1; import import import import import import import import import import import import import import import import import import import import java.awt.BorderLayout; java.awt.Component; java.awt.Frame; java.awt.event.WindowEvent; java.awt.event.WindowListener; java.util.Vector; javax.media.CaptureDeviceInfo; javax.media.CaptureDeviceManager; javax.media.ConfigureCompleteEvent; javax.media.ControllerEvent; javax.media.ControllerListener; javax.media.EndOfMediaEvent; javax.media.Manager; javax.media.MediaLocator; javax.media.Player; javax.media.PrefetchCompleteEvent; javax.media.RealizeCompleteEvent; javax.media.ResourceUnavailableEvent; javax.media.SizeChangeEvent; javax.media.format.VideoFormat;

public class TrivialPlayer extends Frame implements ControllerListener,WindowListener{ Player p = null; boolean stateTransitionOK = true; Object waitSync = new Object(); // sync object public TrivialPlayer() throws Exception{ // Get list of available video devices (any video format) Vector devicesList = CaptureDeviceManager.getDeviceList(new VideoFormat(null)); CaptureDeviceInfo info = null; // Display all video capture devices for(int i=0; i<devicesList.size();i++){ info = (CaptureDeviceInfo)devicesList.get(i); System.out.println(info.getName()); } // Get first video device if(devicesList.size() > 0){ info = (CaptureDeviceInfo)devicesList.firstElement(); }else{ throw new Exception(); } // Get media locator and create data source MediaLocator ml = info.getLocator(); p = Manager.createPlayer(Manager.createDataSource(ml)); // listen for transition events p.addControllerListener(this); // realize p.realize(); waitForState(p.Realized); // prefetch p.prefetch(); waitForState(p.Prefetched); Component vc = null; Component cc = null; // Layout the components setLayout(new BorderLayout()); // Get visual AWT component of player

82

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


if ((vc = p.getVisualComponent()) != null) { add("Center", vc); } // Get control AWT component of player if ((cc = p.getControlPanelComponent()) != null) { add("South", cc); } // Add window listener to close player properly addWindowListener(this); // Start player p.start(); } /** * Block until the processor has transitioned to the given state. * Return false if the transition failed. */ boolean waitForState(int state) { synchronized (waitSync) { try { while (p.getState() < state && stateTransitionOK) waitSync.wait(); } catch (Exception e) {} } return stateTransitionOK; }

/** * Controller Listener. */ public void controllerUpdate(ControllerEvent evt) { if (evt instanceof ConfigureCompleteEvent || evt instanceof RealizeCompleteEvent || evt instanceof PrefetchCompleteEvent) { synchronized (waitSync) { stateTransitionOK = true; waitSync.notifyAll(); } } else if (evt instanceof ResourceUnavailableEvent) { synchronized (waitSync) { stateTransitionOK = false; waitSync.notifyAll(); } } else if (evt instanceof EndOfMediaEvent) { p.close(); } else if (evt instanceof SizeChangeEvent) { } } public void windowClosing(WindowEvent arg0) { p.close(); System.exit(0); } public RuntimeException windowClosingDelivered(WindowEvent arg0) { // TODO Auto-generated method stub return null; }

public RuntimeException windowClosingNotify(WindowEvent arg0) { // TODO Auto-generated method stub return null; }

83

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


public void windowActivated(WindowEvent arg0) { // TODO Auto-generated method stub } public void windowClosed(WindowEvent arg0) { // TODO Auto-generated method stub } public void windowDeactivated(WindowEvent arg0) { // TODO Auto-generated method stub } public void windowDeiconified(WindowEvent arg0) { // TODO Auto-generated method stub } public void windowIconified(WindowEvent arg0) { // TODO Auto-generated method stub } public void windowOpened(WindowEvent arg0) { // TODO Auto-generated method stub } public static void main (String[] args) { try { Frame f = new TrivialPlayer(); f.pack(); f.setVisible (true); } catch (Exception e) { e.printStackTrace(); } } }

84

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Primer 2: Primer zapisa video podatka u datoteku


DataStorage.java
package example_2; import java.awt.Dimension; import java.util.Vector; import import import import import import import import import import import javax.media.CaptureDeviceInfo; javax.media.CaptureDeviceManager; javax.media.DataSink; javax.media.Format; javax.media.Manager; javax.media.MediaLocator; javax.media.Processor; javax.media.format.RGBFormat; javax.media.format.VideoFormat; javax.media.protocol.DataSource; javax.media.protocol.FileTypeDescriptor;

import jmapps.util.StateHelper; public class DataStorage { Processor p = null; DataSink datasink = null; StateHelper sh = null; Dimension videoDimension = new Dimension(320, 240); VideoFormat videoFormat = new RGBFormat(videoDimension, Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED, 24, 3, 2, 1, 3, Format.NOT_SPECIFIED, Format.TRUE, Format.NOT_SPECIFIED); public DataStorage() throws Exception{ // Get list of available video devices (any video format) Vector devicesList = CaptureDeviceManager.getDeviceList(videoFormat); CaptureDeviceInfo info = null; // Display all video capture devices for(int i=0; i<devicesList.size();i++){ info = (CaptureDeviceInfo)devicesList.get(i); System.out.println(info.getName()); } // Get first video device if(devicesList.size() > 0){ info = (CaptureDeviceInfo)devicesList.firstElement(); }else{ throw new Exception(); } DataSource ds = Manager.createDataSource(info.getLocator());

p = Manager.createProcessor(ds); sh = new StateHelper(p); // Configure the processor if (!sh.configure(10000)) System.exit(-1); // Set the output content type and realize the processor p.setContentDescriptor(new

85

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


FileTypeDescriptor(FileTypeDescriptor.MSVIDEO));

// Set the output content type and realize the processor if (!sh.realize(10000)) System.exit(-1); // Get the processor's output, create a DataSink. DataSource outputDS = p.getDataOutput(); MediaLocator dest = new MediaLocator("file://c://foo.avi"); datasink = Manager.createDataSink(outputDS, dest); datasink.open(); // now start data sink and processor datasink.start(); System.out.println("Started saving..."); // Capture for 20 seconds sh.playToEndOfMedia(20000); sh.close(); datasink.close(); } public static void main(String[] args) { try { DataStorage dataStorage = new DataStorage(); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } }

86

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Primer 3: Primer itanja video podatka iz datoteke


DataReader.java
package example_3; import import import import import import import import import import import import import import import import import import java.awt.BorderLayout; java.awt.Component; java.awt.FileDialog; java.awt.Frame; java.awt.event.WindowAdapter; java.awt.event.WindowEvent; java.io.File; javax.media.ConfigureCompleteEvent; javax.media.ControllerEvent; javax.media.ControllerListener; javax.media.EndOfMediaEvent; javax.media.Manager; javax.media.PrefetchCompleteEvent; javax.media.Processor; javax.media.RealizeCompleteEvent; javax.media.ResourceUnavailableEvent; javax.media.SizeChangeEvent; javax.media.protocol.DataSource;

public class DataReader extends Frame implements ControllerListener{ Processor p = null; boolean stateTransitionOK = true; Object waitSync = new Object(); // sync object public DataReader() throws Exception{ FileDialog fd = new FileDialog(this, "DataReader", FileDialog.LOAD); fd.setVisible(true); File f = new File (fd.getDirectory(), fd.getFile()); System.out.println(fd.getDirectory() + fd.getFile()); //create data source of input file DataSource ds = Manager.createDataSource(f.toURL()); // Create processor p = Manager.createProcessor(ds); // Listen for transition events p.addControllerListener(this); // Configure p.configure(); waitForState(p.Configured); // Use as player p.setContentDescriptor(null); //Realize p.realize(); waitForState(p.Realized);

// Prefetch p.prefetch(); waitForState(p.Prefetched);

// Layout the components setLayout(new BorderLayout()); Component vc = null;

87

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


if ((vc = p.getVisualComponent()) != null) { add("Center", vc); } p.start(); //Action on window close addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { p.close(); System.exit(0); } }); } /** * Block until the processor has transitioned to the given state. * Return false if the transition failed. */ boolean waitForState(int state) { synchronized (waitSync) { try { while (p.getState() < state && stateTransitionOK) waitSync.wait(); } catch (Exception e) {} } return stateTransitionOK; }

/** * Controller Listener. */ public void controllerUpdate(ControllerEvent evt) { if (evt instanceof ConfigureCompleteEvent || evt instanceof RealizeCompleteEvent || evt instanceof PrefetchCompleteEvent) { synchronized (waitSync) { stateTransitionOK = true; waitSync.notifyAll(); } } else if (evt instanceof ResourceUnavailableEvent) { synchronized (waitSync) { stateTransitionOK = false; waitSync.notifyAll(); } } else if (evt instanceof EndOfMediaEvent) { p.close(); } else if (evt instanceof SizeChangeEvent) { } } public static void main(String[] args) { // try { Frame f = new DataReader(); f.setTitle("DataReader"); f.pack(); f.setVisible (true); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } }

88

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Primer 4: Primer implmentiranja video efekta kao i njegove kontrole


MyEffect.java
package example_4; import import import import import import import import import import java.awt.Dimension; java.awt.image.BufferedImage; java.io.FileOutputStream; java.io.IOException; javax.media.Buffer; javax.media.Control; javax.media.Effect; javax.media.Format; javax.media.ResourceUnavailableException; javax.media.format.RGBFormat;

import com.sun.image.codec.jpeg.ImageFormatException; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; public class MyEffect implements Effect { boolean takeSnapshot = true; protected protected protected protected Format inputFormat; Format outputFormat; Format[] inputFormats; Format[] outputFormats;

private Control[] controls; public MyEffect() { super(); // Array of input formats which this effect supports inputFormats = new Format[] { new RGBFormat(null, Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED, 24, 3, 2, 1, 3, Format.NOT_SPECIFIED, Format.TRUE, Format.NOT_SPECIFIED) }; // Array of output formats which this effect supports outputFormats = new Format[] { new RGBFormat(null, Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED, 24, 3, 2, 1, 3, Format.NOT_SPECIFIED, Format.TRUE, Format.NOT_SPECIFIED) }; } public Format[] getSupportedInputFormats() { return inputFormats; }

89

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


public Format[] getSupportedOutputFormats(Format input) { if (input == null) return outputFormats; if (matches(input, inputFormats) != null) { return new Format[] { outputFormats[0].intersects(input) }; } else { return new Format[0]; } } private void writeImage(String fileName, byte[] data, int width, int height) throws ImageFormatException, IOException { // Output file FileOutputStream outputFile = new FileOutputStream(fileName); // Create a JPG encoder for the file JPEGImageEncoder jpeg_encode = JPEGCodec.createJPEGEncoder(outputFile); // Reformat the data to an array on int int ints[] = new int[data.length/3]; int k = 0; for (int i = height-1; i > 0;i--) { for (int j=0;j<width;j++) { ints[k++] = 255 << 24 | (int) (data[i*width*3 + j*3 + 2] & 0xff) << 16 | (int) (data[i*width*3 + j*3 + 1] & 0xff) << 8 | (int) (data[i*width*3 + j*3] & 0xff); } } // Create a buffered image BufferedImage image = new BufferedImage (width, height,BufferedImage.TYPE_INT_RGB); image.setRGB(0,0,width,height,ints,0,width); // Encode the image and close the output file jpeg_encode.encode(image); outputFile.close(); } public int process(Buffer inputBuffer, Buffer outputBuffer) { RGBFormat vfIn = (RGBFormat) inputBuffer.getFormat(); Dimension sizeIn = vfIn.getSize(); if(takeSnapshot){ // Save frame as JPEG image // Get the data portion of the buffers byte[] inData = (byte[]) inputBuffer.getData(); try { // file name contains time in ms writeImage("snap_" + System.currentTimeMillis()+ ".jpg", inData, sizeIn.width, sizeIn.height); } catch (ImageFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } takeSnapshot = false; } // Do some processing // Swap the data between the input & output. Object data = inputBuffer.getData(); outputBuffer.setData(data);

90

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


// Copy the input attributes to the output outputBuffer.setFormat(inputBuffer.getFormat()); outputBuffer.setLength(inputBuffer.getLength()); outputBuffer.setOffset(inputBuffer.getOffset()); return BUFFER_PROCESSED_OK; } public Format setInputFormat(Format input) { inputFormat = input; return input; } public Format setOutputFormat(Format output) { if (output == null || matches(output, outputFormats) == null) return null; outputFormat = output; return outputFormat; } public void close() { } public String getName() { return "MyEffect"; } public void open() throws ResourceUnavailableException { } public void reset() { } public Object getControl(String controlType) { try { Class cls = Class.forName(controlType); Object cs[] = getControls(); for (int i = 0; i < cs.length; i++) { if (cls.isInstance(cs[i])) return cs[i]; } return null; } catch (Exception e) { // no such controlType or such control return null; } } public Object[] getControls() { if (controls == null) { controls = new Control[1]; controls[0] = new MyEffectControl(this); } return (Object[])controls; } // Utility methods. /** * Select the first output format that matches the input format. * @return first matching output format ot null if none match */ protected Format matches(Format in, Format outs[]) { for (int i = 0; i < outs.length; i++) { if (in.matches(outs[i])) return outs[i]; } return null; } }

91

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave MyEffectControl.java


package example_4; import import import import import java.awt.BorderLayout; java.awt.Component; java.awt.Panel; java.awt.event.ActionEvent; java.awt.event.ActionListener;

import javax.media.Control; import javax.swing.JButton; public class MyEffectControl implements Control, ActionListener { MyEffect effect = null; private Component component; private JButton button; public MyEffectControl(MyEffect effect) { super(); this.effect = effect; } public Component getControlComponent() { if (component == null) { button = new JButton("Take snapshot"); button.addActionListener(this); button.setToolTipText("Click to to take current snapshot"); Panel componentPanel = new Panel(); componentPanel.setLayout(new BorderLayout()); componentPanel.add("Center", button); componentPanel.invalidate(); component = componentPanel; } return component; } public void actionPerformed(ActionEvent e) { Object o = e.getSource(); if (o == button) { effect.takeSnapshot = true; } } }

92

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave TestEffect.java


package example_4; import import import import import import import import import import import import import import import import import import import import import import java.awt.BorderLayout; java.awt.Component; java.awt.FileDialog; java.awt.Frame; java.awt.event.WindowAdapter; java.awt.event.WindowEvent; java.io.File; javax.media.Codec; javax.media.ConfigureCompleteEvent; javax.media.Control; javax.media.ControllerEvent; javax.media.ControllerListener; javax.media.EndOfMediaEvent; javax.media.Manager; javax.media.PrefetchCompleteEvent; javax.media.Processor; javax.media.RealizeCompleteEvent; javax.media.ResourceUnavailableEvent; javax.media.SizeChangeEvent; javax.media.control.TrackControl; javax.media.format.VideoFormat; javax.media.protocol.DataSource;

import cbsjmf.MyVideoEffect; import example_3.DataReader; public class TestEffect extends Frame implements ControllerListener{ Processor p = null; boolean stateTransitionOK = true; Object waitSync = new Object(); // sync object

public TestEffect() throws Exception{ // Layout the components setLayout(new BorderLayout()); FileDialog fd = new FileDialog(this, "DataReader", FileDialog.LOAD); fd.setVisible(true); File f = new File (fd.getDirectory(), fd.getFile()); System.out.println(fd.getDirectory() + fd.getFile()); //create data source of input file DataSource ds = Manager.createDataSource(f.toURL()); // Create processor p = Manager.createProcessor(ds); // Listen for transition events p.addControllerListener(this); // Configure p.configure(); waitForState(p.Configured); // Use as player p.setContentDescriptor(null); // Get processor track controls TrackControl tc[] = p.getTrackControls(); if (tc == null) {

93

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


System.err.println("Failed to obtain track controls from the processor."); throw new Exception(); } // Search for the track control for the video track. TrackControl videoTrack = null; for (int i = 0; i < tc.length; i++) { if (tc[i].getFormat() instanceof VideoFormat) { videoTrack = tc[i]; break; } } if (videoTrack == null) { System.err.println("The input media does not contain a video track."); throw new Exception(); } Codec[] codec = new Codec[1]; codec[0] = new MyEffect(); videoTrack.setCodecChain(codec); // Realize p.realize(); waitForState(p.Realized); Control[] controls = p.getControls(); for (int i = 0; i < controls.length; i++) { if (controls[i] instanceof MyEffectControl) { Component ec = ((MyEffectControl)controls[i]).getControlComponent(); if(ec != null){ add("North", ec); } } } // Prefetch p.prefetch(); waitForState(p.Prefetched); Component vc = null; if ((vc = p.getVisualComponent()) != null) { add("Center", vc); } // Take MyEffect control component and make it visible p.start(); //Action on window close addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { p.close(); System.exit(0); } }); } boolean waitForState(int state) { synchronized (waitSync) { try { while (p.getState() < state && stateTransitionOK) waitSync.wait(); } catch (Exception e) {} } return stateTransitionOK; }

94

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


/** * Controller Listener. */ public void controllerUpdate(ControllerEvent evt) { if (evt instanceof ConfigureCompleteEvent || evt instanceof RealizeCompleteEvent || evt instanceof PrefetchCompleteEvent) { synchronized (waitSync) { stateTransitionOK = true; waitSync.notifyAll(); } } else if (evt instanceof ResourceUnavailableEvent) { synchronized (waitSync) { stateTransitionOK = false; waitSync.notifyAll(); } } else if (evt instanceof EndOfMediaEvent) { p.close(); } else if (evt instanceof SizeChangeEvent) { } } public static void main(String[] args) { try { Frame f = new TestEffect(); f.setTitle("TestEffect"); f.pack(); f.setVisible (true); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } }

95

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave

Primer 5: Primer implementiranja proizvoljnog DataSource-a


ImageDataSource.java
package example_5; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import import import import javax.media.Time; javax.media.protocol.ContentDescriptor; javax.media.protocol.PullBufferDataSource; javax.media.protocol.PullBufferStream;

/* * Image data source has only one RGB format stream */ class ImageDataSource extends PullBufferDataSource{ ImageSourceStream streams[]; public ImageDataSource(int width, int height, File file) throws FileNotFoundException { streams = new ImageSourceStream[1]; streams[0] = new ImageSourceStream(width, height, file); } public PullBufferStream[] getStreams() { return streams; } public void connect() throws IOException { } public void disconnect() { } public String getContentType() { return ContentDescriptor.RAW; } public Object getControl(String arg0) { return null; } public Object[] getControls() { return new Object[0]; } public Time getDuration() { return DURATION_UNKNOWN; } public void start() throws IOException { } public void stop() throws IOException { } }

96

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave ImageSourceStream.java


package example_5; import import import import import import import import import import import import java.awt.Dimension; java.io.BufferedInputStream; java.io.DataInputStream; java.io.File; java.io.FileInputStream; java.io.FileNotFoundException; java.io.IOException; javax.media.Buffer; javax.media.Format; javax.media.format.RGBFormat; javax.media.protocol.ContentDescriptor; javax.media.protocol.PullBufferStream;

class ImageSourceStream implements PullBufferStream { int width, height; String fileName; long fileSize; Format format; public ImageSourceStream(int width, int height, File file) throws FileNotFoundException { super(); // Get image width and height this.width = width; this.height = height; // Get file name and its size in byte this.fileName = file.getPath(); this.fileSize = file.length(); // Format of data stream is RGB Dimension videoDimension = new Dimension(width, height); format = new RGBFormat(videoDimension, Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED, 24, 1, 2, 3, 3, width*3, Format.FALSE, RGBFormat.NOT_SPECIFIED);

} public Format getFormat() { return format; } /** * This is called from the Processor to read a frame worth * of video data. */ public void read(Buffer buf) throws IOException { // Open input data FileInputStream inputFile= new FileInputStream(fileName); DataInputStream in = new DataInputStream(new BufferedInputStream(inputFile)); // Check size of buffer byte data[] = null;

97

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


if (buf.getData() instanceof byte[]){ data = (byte[])buf.getData(); } if (data == null || data.length < fileSize) { data = new byte[(int)fileSize]; buf.setData(data); } // Read the entire image from the file. in.readFully(data, 0, (int)fileSize); //System.err.println(" read " + data.length + " bytes.");

buf.setOffset(0); buf.setLength((int)fileSize); buf.setFormat(format); buf.setFlags(buf.getFlags()); // Close the random access file. in.close(); } public boolean willReadBlock() { return false; } public boolean endOfStream() { return false; } public ContentDescriptor getContentDescriptor() { return new ContentDescriptor(ContentDescriptor.RAW); } public long getContentLength() { return 0; } public Object getControl(String arg0) { return null; } public Object[] getControls() { return new Object[0]; } }

98

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave TestImageSource.java


package example_5; import import import import import import import import import import import import import import import import import import import java.awt.BorderLayout; java.awt.Component; java.awt.FileDialog; java.awt.Frame; java.awt.TextArea; java.awt.event.WindowAdapter; java.awt.event.WindowEvent; java.io.File; javax.media.ConfigureCompleteEvent; javax.media.ControllerEvent; javax.media.ControllerListener; javax.media.EndOfMediaEvent; javax.media.Manager; javax.media.PrefetchCompleteEvent; javax.media.Processor; javax.media.RealizeCompleteEvent; javax.media.ResourceUnavailableEvent; javax.media.SizeChangeEvent; javax.media.StartEvent;

public class TestImageSource extends Frame implements ControllerListener{ Processor p = null; boolean stateTransitionOK = true; Object waitSync = new Object(); // sync object public TestImageSource() throws Exception{ // Choose file FileDialog fd = new FileDialog(this, "TestImageSource", FileDialog.LOAD); fd.setVisible(true); File f = new File (fd.getDirectory(), fd.getFile()); System.out.println(fd.getDirectory() + fd.getFile()); //create data source of input file ImageDataSource ids = new ImageDataSource(512, 512, f); // Create processor p = Manager.createProcessor(ids); // Listen for transition events p.addControllerListener(this); // Configure p.configure(); waitForState(p.Configured); // Use as player p.setContentDescriptor(null); //Realize p.realize(); waitForState(p.Realized); // Prefetch p.prefetch(); waitForState(p.Prefetched); // Layout the components setLayout(new BorderLayout()); Component vc = null; if ((vc = p.getVisualComponent()) != null) { add("Center", vc); } p.start();

99

Projektovanje sistema zasnovanih na raunarima Priprema za laboratorijske vebe iz Jave


waitForState(p.Started); //Action on window close addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { p.close(); System.exit(0); } }); } /** * Block until the processor has transitioned to the given state. * Return false if the transition failed. */ boolean waitForState(int state) { synchronized (waitSync) { try { while (p.getState() < state && stateTransitionOK) waitSync.wait(); } catch (Exception e) {} } return stateTransitionOK; } /** * Controller Listener. */ public void controllerUpdate(ControllerEvent evt) { if (evt instanceof ConfigureCompleteEvent || evt instanceof RealizeCompleteEvent || evt instanceof PrefetchCompleteEvent || evt instanceof StartEvent ) { synchronized (waitSync) { stateTransitionOK = true; waitSync.notifyAll(); } } else if (evt instanceof ResourceUnavailableEvent) { synchronized (waitSync) { stateTransitionOK = false; waitSync.notifyAll(); } } else if (evt instanceof EndOfMediaEvent) { p.close(); } else if (evt instanceof SizeChangeEvent) { } } public static void main(String[] args) { // try { Frame f = new TestImageSource(); f.setTitle("TestImageSource"); f.pack(); f.setVisible (true); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } }

100

You might also like