You are on page 1of 21

Java In-Depth: Become a Complete Java Engineer!

author: Dheeru Mundluru

udemy.com
Sadržaj
Section 2: Java – A High-level Overview .................................................................................................. 4
5. What is Java & Who Use It ? ............................................................................................................. 4
7. Compilation ........................................................................................................................................ 4
8. Platform Dependency + Demo .......................................................................................................... 6
9. Interpreter ......................................................................................................................................... 7
10. Platform Independence in Java + Demo ....................................................................................... 10
11. Java Virtual Machine ...................................................................................................................... 12
12. An Overview of Java SE ..................................................................................................................15
16. Setting Classpath Environment Variable ...................................................................................... 16
17. WritingFirst Java Program ............................................................................................................ 16
18. Conclusion ...................................................................................................................................... 19
Section 3: Classes, Objects and their Members ...................................................................................... 20
20. Chapter Introduction..................................................................................................................... 20
21. Class & Objects ............................................................................................................................... 20

2
3
Section 2: Java – A High-level Overview
5. What is Java & Who Use It ?
Programski jezik Java je:
 general-purpose – znači da nije ograničen na jedan konkretan domen i može da se koristi za
razvoj različitih tipova aplikacija
 object-oriented – omogućava da se modeluju scenarija iz realnog života na prirodniji način
 platform independent – Java-ina mantra je WORE (Write Once Run Anywhere) – jednom
kada napišete program morate biti u mogućnosti da ga pokrenete na bilo kojoj platformi bez
obzira na operativni sisitem i arhitekturu. Ovo je jedan od ključnih benefita Java-e.
 concurrent – Java podržava multi-threading, što omogućava programima da izvode više
aktivnosti u otprilike iste vreme.
 very fast – ima slične performanse kao C ili C++

Java je izgrađena na nekoliko principa:


 familiar syntax – Java je razvijena sredinom 90-ih kada su u upotrebi bili C i C++. Kreatori
Java-e su želeli da zadrže tu sintaksu i zato je ona slična.
 simple & safe – Kreatori Jave su želeli da u poređenju sa programskim jezicima C i C++ bude
jednostavnija, pa su iz tog razloga izbacili neke karakteristike (feature) koje su izgledale složene,
konfuzne ili nesigurne, a dodali neke nove. Jedan od primera je vezan za upravljanje memorijom
(memory management) na način da se u C i C++ upravlja memorijom da bi se oslobodio prostor,
i ukoliko se ovo ne uradi valjano može rezultovati da program pukne. U poređenju sa tim Java
je jednostavnija i sigurnija jer koristi automatsko upravljanje memorijom (automatic memory
management) upotrebom karakteristike (feature) Garbage Collection, što oslobađa korisnike
od direktne manipulacije memorijom i time čini programiranje jednostavnijim.
 secure – Java programi se mogu preuzeti sa Internet-a, tako da ne izazovu problema na
računaru sa kojeg se vrši preuzimanje.

Postoji još nekoliko dobrih stvari koje Java može da ponudi:


 rich library – koje sadrže gomilu predefinisanih funkcionalnosti i ova biblioteka je Java API,
gde je API – Application Programming Interface, što omogućava Java programerima da se
fokusiraju na pisanju nove logike bez potrebe da izmišljaju točak ponovo. Npr., oni mogu
jednostavno da koriste predefinisane funkcionalnosti koje su napisane od strane eksperata i koje
već koriste milion programera
 free – Java je takođe besplatna, što je pogodno za razvoj kada nije potrebno investirati novca u
softver.
 Java je vremenom evoluirala od svoje prvobitne namene i koristi se za razvoj large-scale Web
applications, standalone desktop applications and mobile applications. Java obezbeđuje
odvojene platforme namenjene isključivo za različite tipove aplikacija.

7. Compilation
 računar razume instrukcije, koje su napisane u nizovima jedinica i nula (1, 0) i to se naziva
mašinski jezik ili mašinski kod ili nativni kod (machine language, machine code, native
code)
4
 npr. jedna mašinska instrukcija bi mogla da bude:
000000 00001 00010 00110 00000 100000
 za programere bi bilo izuzetno teško da pišu svoje programe kao nizove jedinica i nula (1, 0) i da
tako prosleđuju instrukcije operativnom sisitemu
 iz tog razloga je osmišljen asemblerski jezik (assembly language) , u kojima se mnogo lakše
pišu programi, npr. :
li $t1, 5
add $t0, $t1, 6
 vidimo da je pisanje u asemblerskom jeziku, mnogo ekspresivnije nego u mašinskom kodu
 dakle, asemblerski jezik obezbeđuje instrukcije višeg nivoa za pisanje instrukcija, ali računari
razumeju samo mašinski jezik, ne razumeju asemberski jezik
 program koji se zove asembler (assembler) prevodi instrukcije sa asemblerskog jezika na
mašinski jezik, koje računar može da razume
 i mašinski jezik i asemblerski jezik se nazivaju jezici niskog nivoa (low-level languages), jer
koriste nizak nivo detalja računara, kao što je npr. lokacija memorije (memory location) gde
skladištimo podatke
 programiranje u asemblerskom jeziku je i dalje dosadno i iz tog razloga, kao i iz želje programera
da se uklone detalji niskog nivoa u samom jeziku, razvijeni su programski jezici visokog nivoa
(high-level languages)
 neki od primera jezika visokog nivoa su: FORTRAN, C, C++, Java, C# i svi oni koriste reči na
engleskom (english-like words), matematičke notacije (math notation) i znakove interpunkcije
(punctuation), što ih čini mnogo jednostavnijim za čitanje i pisanje programa i takođe oni
sakrivaju detalje niskog nivoa računara
 danas je trend da koristimo programske jezike visokog nivoa, dok se asemblerski jezik koristi
tamo gde su performanse kritične, kao kod operativnih sisitema i elektronskih uređaja
 izvorni kod (source code) se odnosi na bilo koji kod koji je napisan u bilo kojem programskom
jeziku
 računar ne može da razume izvorni kod, pa je potrebno da prebacimo izvorni kod u mašinski
jezik, a se vrši preko programa koji se zove kompajler (compiler)
 nakon faze prevođenja, mašinski kod se u odvojenom koraku izvršava direktno na CPU-u

slika 1. prevođenje

 na slici 1. se vidi da jezik u koji je transliran kod nazivamo željeni jezik (target language), a ne
mašinski jezik, a to je zato što u određenim slučajevima može postojati nešto drugo, npr. u
slučaju C i C++ željeni jezik će biti mašinski kod, u slučaju Java-e to će biti Java bajtkod
5
(bytecode), dok ponekad željeni jezik može biti drugi programski jezik (another programming
language)

slika 2. željeni jezik


 osnovne operacije koje izvodi kompajler su (ovo važi za sve kompajlere):
o provera sintakse (syntax) i semantike (semantics) izvornog koda – na taj način se
obezbeđuje da kod bude u skladu sa pravilima programskog jezika. Npr. svaki program je
sastavljen od naredbi (statements) i u Java-i se svaka naredba mora završiti sa znakom ;
(semicolon). Ukoliko se ipak desi da je izostavljen znak tačka-zarez, tada kompajler
prijavljuje grešku u sintaksi
o optimizacija koda (code optimization) – kompajler sprovodi optimizaciju koda radi
bržeg izvršavanja
o generisanje mašinskog koda (generate machine code) – generiše se mašinski kod od
optimizovanog među-kod-a

 Java kompajler sprovodi neke dodatne operacije, tako da sam proces kompajliranja može biti
spor usled složenosti kod prevođenja. Jednom iskompilovan mašinski kod, će biti brz i može biti
izvršen bilo kada, na bilo kojoj stvari. Bilo koja promena izvornog koda zahteva ponovnu
kompilaciju, tzv. rekompilaciju (recompilation).
8. Platform Dependency + Demo
Prikaza ćemo kratak demo o platformskoj zavisnosti (platform dependency). Pretpostavimo da
imamo Windows mašinu i pretpostavimo da imamo program napisan u C-u, pod nazivom Hello.c. Da
bi smo kompajlirali ovaj program, možemo da koristimo GCC kompajler i komanda bi bila:
gcc –o Hello Hello.c
, gde je Hello.c fajl koji sadrži C program, dok je povlaka (hyphen) opcija koja govori kompajleru, da
imenuju izlazi fajl Hello, a koji će imati ekstenziju .exe na Windows OS. Dakle, kompajliranjem fajla
Hello.c, dobiće se fajl Hello.exe, koji u sebi sadrži mašinski kod. Prilikom kompajliranja radi se i
linkovanje (linking). Generalno, bilo koji softver koji se sastoji iz mnogo fajlova izvornog koda i svaki
fajl se kompajlira u odvojeni fajl koji ze zove object file, koji ima ekstenziju .o ili .obj. npr. u ovom
slučaju to može da bude Hello.o. Nakon toga ovi object file-ovi se grupišu da formiraju krajnji izvršni
(executable) fajl. Ovo linkovanje obično radi sam kompajler, ali takođe može biti urađen manuelno,
upotrebom programa koji se zove linker. Dakle, u ovom slučaju kompajliranje, Hello.c, dobija se
izvršni fajl Hello.exe, koji se jednostavno može pozvati komandom Hello.
Na sličan način možemo kompajlirati program na Linux OS, upotrebom iste komande i to će takođe
proizvesti izvršni fajl, ali u Linux-u ekstenzija će biti .out, a fajl će biti Hello.out. Kasnije program
Hello.out se može izvršiti putem komande:
./Hello
Dakle, vidimo da oba izvršna fajla se uspešno izvršavaju, na mašinama na kojima su generisani, ali ne
bi bilo moguće da se izvršni fajl generisan na Windows mašini izvrši pod Linux-om i to je primer
platformske zavisnosti (platform dependency), dakle Hello.exe može biti izvršen samo na Windows
6
operativnom sistemu. Da bi smo pokrenuli Hello.c program, potrebno je da ga rekompilujemo na
Linux-u. Na sličan način Hello izvršni fajl generisan na Linux mašini, ne može biti izvršen na Windows
mašini, već je potrebno ponovo kompajlirati pomenuti fajl na Windows-u. Dakle generisani izvršni fajl
je specifičan u odnosu na operativni sisitem.

slika 3. platformska zavisnost


Platformska zavisnost ima veze sa operativnim sistemom.
 Jedan od glavnih razloga je format generisanog izvršnog fajla. Windows korisnici koriste format
koji nazivaju PE (portable executable), dok Linux koriste format ELF (executable and linkable
format).
 Drugi razlog za zavisnost od operativnog sistema jeste kada program učini sistemski trošak.
Sistemski pozivi kao što su: otvaranje fajla, kreiranje direktorijuma ili čak štampanje na konzoli,
tj. terminalu. Sistemski pozivi se rutiraju na kernel sistema.
Platformska zavisnost može imati veze i sa hardware-om. Npr. mašinski kod koji je generisan za X86
procesore može da bude različit od mašinskog koda istog programa generisanog za ARM procesor.
Dakle mašina na kojoj se izvršava izvršni kod treba da bude slična mašini na kojoj je generisan, u
suprotnom je potrebno da bude rekompajliran upotrebom odgovarajućeg kompajlera.
Dakle i operativni sistem i hardware igraju svoju ulogu u zavisnosti platforme.
9. Interpreter
Videli smo kada software developer-i koriste jezik koji se kompajlira, kao što je C on nije platformski
nezavisan, već je platformski zavisan (platform dependent). Sada pogledajmo interpretere
(interpreters) koji se nose sa problemima platformske zavisnosti, ali imaju neka druga
ograničenja.
Za sada znamo da kod jezika koji se kompajliraju, mašinski kod se prvo generiše od strane kompajlera,
a nakon toga se taj mašinski kod odvojeno izvršava putem CPU-a. Programski jezik koji se interpretira
radi drugačije. U jezicima koji se interepretiraju, imamo interpretere, koji su programi koji direktno
izvršavaju izvorni (source) kod. Ne postoji odvojeno proces kompilacije, pa nakon toga izvršenja,
kao što je u slučaju jezika koji se kompajliraju. Dakle ulaz u interpreter je izvorni kod, a izlaz je izvršenje
tog izvornog koda. Uočite sličnosti između interpretera i CPU-a. CPU pretvara mašinski kod u rezultat,
dok interpreter pretvara izvorni kod u rezultat. Mašinski kod služi kao skup instrukcija za CPU, dok
7
izvorni kod služi kao skup instrukcija za interpreter. Pored toga, interpreter je takođe program i
potrebno je da bude pokrenut. Dakle, CPU pokreće interpreter, a interpreter izvršava izvorni kod.

slika 4. kompajliranje VS interpretiranje


Interpreter nije ništa drugo do virtuelna mašina koja simulira CPU. Način na koji CPU izvršava
instrukcije mašinskog jezika upotrebom fetch-and-execute cycle, interpreter izvršava instrukcije
izvornog koda u fetch-and-execute cycle.
Fetch-and-Execute cycle izgleda sledeće. To je osnovna operacija računara. Imamo CPU, memoriju
i hard disk sa programom koji će se izvršiti. Kada se program izvršava, on se prvo učita u memoriju, a
program je mašinski kod, u osnovi sekvenca instrukcija, gde je svaka instrukcija jedostavna sekvenca 0
(nula) i 1 (jedinica). Sledeći korak jeste da CPU dohvati (fetch) instrukciju iz memorije i nakon toga je
izvršava (execute), u tom procesu može da dohvati bilo koje podatke (data) koji su potrebni za
izvršavanje instrukcije. Bilo koji podaci koji se generišu u izvršenju instrukcije se vraćaju u memoriju.
CPU zatim dohvata sledeću instrukciju i izvršava je. Ovaj ciklus (cycle) se izvršava sve dok se sve
instrukcije u programu ne izvrše, i to je u osnovi CPU’s fetch-and-execute life cycle.

slika 5. fetch and execute cycle

8
Pogledajmo sada interpreterov fetch-and-execute life cycle. Kao CPU interpreter dohvata svoje
instrukcije iz memorije, kako god u slučaju interpretera instrukcije su u osnovi naredbe (statement) u
izvornom kodu. Nakon toga interpreter razume šta je potrebno da bi izvršio tu naredbu. I ova 2 koraka
su ista kao kod kompajlera. Sledeći korak trebalo bi da bude izvršavanje naredbe programa. Ovde je
interesantna stvar. Interpreter održava (maintainance) biblioteku mašinskog kompajliranog koda i
samo izvršava i samo izvršava odgovarajući kompajlirani mašinski kod koji odgovara naredbi u
programu. Dakle, interpreter ne generiše mašinski kod, već jednostavno koristi svoj kompajlirani
mašinski kod izvrši oni što izvorni kod nalaže.
Pogledajmo sada primer:
 imamo add naredbu u izvornom kodu
 interpreter izvršava odgovarajući kompajlirani kod iz svoje biblioteke, što je verzija mašinskog
koda ovog bloka koda sa slike 6. Kod dohvata 2 broja koja se dodaju iz memorije. Nakon toga
sprovodi sabiranje. Na kraju, skladišti rezultat u memoriju.

slika 6. koraci u izvršavanju kod interpretera


Još jednom, interpreter ne generiše mašinski kod, on samo koristi njegovu biblioteku
prekompajliranog mašinskog koda !
Jedna od prednosti interpretera je platformska nezavisnost (platform independence). Ko što
možete videti sa slike 7. isti izvorni kod može biti izvršen ma bilo kojoj platformi, gde je jedini zahtev
da se instalira interpreter specifičan za platformu.

slika 7. platform independence


9
Setite se da sa jezikom koji se kompajlira nismo mogli da ostvarimo platformsku nezavisnost, to je bilo
zato što umesto izvornog koda smo koristili mašinski kod, a on je bio platformski zavisan. To je mašinski
kod koji uključuje atribute specifične za platformu na kojoj je generisan. Dakle, odabrana platforma na
kojoj će mašinski kod biti izvršen može da ima različiti skup atributa i zato mašinski kod ne uspeva da
se izvrši, ali sa interpretiranim jezicima izvršava se izvorni kod koji je identičan bez obzira na platformu
na kojoj je napisan, tj. on je platformski nezavisan, jer interpreter željene platforme osigurava da se
platformski nezavisan izvorni kod izvršava bez bilo kojih problema.
Prednosti interpretera su:
 platformska nezavisnost
 ne postoji kompajliranje, već izvršenje programa može odmah započeti
 lako ažuriranje

Nedostaci interpretera su:


 brzina – ima 2 razloga za to:
o skup pristup memoriji – ukoliko pogledamo primer sa slike 6., vidimo da postoji nekoliko
pristupa memoriji, što je sporije u odnosu na brzinu pristupa koja se odvija u registru, kao
kod kompajliranog koda do 100 puta
o izvorni kod je potrebno da bude reinterpretiran svaki put kada je pokrenut
 interpreter se učitava u memoriju zajedno sa izvornim kodom
10. Platform Independence in Java + Demo
Pogledaćemo kako Java koristi nezavisnost platforme, bez uticaja na brzinu izvršavanja. Govorili smo
o kompilaciji i interpretaciji i poredili smo njihove prednosti i nedostatke. Sa kompilacijom imamo brzo
izvršenje, ali bez benefita platformske nazavisnosti, sa druge strane sa interpretacijom imamo benefit
platformske nezavisnosti, ali sa mnogo manjom brzinom izvršenja. Java koristi najbolje od oba.

slika 8. Java kombinovanje najboljeg od interpretacije i kompilacije


Način na koji Java postiže platformsku nezavisnost i brzinu je sledeći:
 Java izvorni kod se prvo kompajlira u među-formu koda koja se naziva Java bajt kod (byte code)
 Java bajt kod tada može biti interpretirana na bilo kojoj platformi sa Java virtuelnom
mašinom (Java Virtual Machine), skraćeno JVM
10
slika 9. Java interpretacija bajt koda
Kao u slučaju interpretera na svaku platformu se instalira JVM, specifična za tu platformu.
Pretpostavimo da imamo Java program Hello.java, koji uključuje izvorni kod. Hello.java se
kompajlira i generiše se Hello.class, koji sadrži Java bajtkod. Za kompajliranje koristimo komandu:
javac Hello.java
javac je Java kompajler. Hello.class, tada može biti izvršena na bilo kojoj platformi koja ima
instaliranu JVM-u. Kao što vidimo JVM, je specifična u odnosu na platformu. Za Windows platformu
instaliramo JVM specifičnu za Windows. Da bi smo izvršili fajl sa ekstenzijom .class, koristimo
komandu:
java Hello
Ova komanda kreira instancu JVM-e. CPU učitava JVM-u u memoriju i zatim JVM-a izvršava
Hello.class. Ko što vidite JVM-a je platformski zavisna, ali Java bajt kod je platformski
nezavisan. Ovaj ceo proces je sličan interpretiranju.

slika 10. platformska nezavisnost Java bajt koda i platformska zavisnost JVM-a
11
U slučaju Java-e mi koristimo JVM da bi smo interpretirali bajt kod, umesto izvornog koda, kao kod
ranije pomenutih interpretera. Dakle JVM je interpreter. Zapravo proces interpretacije je urađen
preko Java interpretera, koji je pod komponenta JVM-e. Obzirom da JVM intrpretira Java bajt kod,
o Java-i možemo misliti kao o interpretiranom jeziku. Znamo da je interpretiranje sporo, pa kako se
Java to sprovodi brzo ?
Ključ je da je mnogo lakše interpretirati Java bajt kod, nego izvorni kod, to je iz razloga što je bajt kod
kompaktan, štaviše on je već kompajliran, što znači da je prošla provera sintakse i semantike,
takođe bajt kod je optimizovan.
Takođe, da bi se ubrzalo izvršavanje JVM izvodi dodatnu optimizaciju kroz proces koji se zove Just-
in-time (JIT) compilation. (- o kome diskutujemo kasnije)
Takođe potrebno je reći da je kompaktnost Java bajt koda, smišljena da se brzo prenese preko mreže,
jer je Java osmišljena kao jezik koji radi u mrežnom okruženju i prenosi se do različitih uređaja na
mreži.
11. Java Virtual Machine
Do sada smo naučili da interpretacija Java bajt koda od strane JVM-e omogućava platformsku
nezavisnost, bez kompromisa sa brzinom. JVM omogućava i drugim programskim jezicima kao što su
Scala i Ruby da se kompajliraju u Java bajt kod i pokrenu na JVM-i. Na taj način i oni dobijaju na
platformskoj nezavisnosti, pored brzine i sigurnosti koje JVM nudi. JVM je kamen temeljac Java
platforme, i pomaže da Java ostvari neke od svojih ciljeva kao što su: platformska nezavisnost, sigurnost
i brzo izvršavanje. JVM – Java Virtual Machine se naziva virtuelnom, jer je apstraktna računarska
mašina (abstract computing machine), a to znači da je kao prava računarska mašina jer ima skup
instrukcija koji se izvršava. Skup instrukcija je Java bajt kod, dok je skup instrukcija kod CPU-a
mašinski kod. Kao prava računarska mašina JVM vrši manipulaciju memorijom prilikom izvršenja
(runtime). Vreme izvršenja (runtime) se odnosi na vreme kada je program zapravo izvršen.
JVM ima nekoliko glavnih odgovornosti:
 učitavanje i interpretacija Java bajt koda
 sigurnost
 automatsko upravljanje memorijom
Još jednom, interpretiranje Java bajt koda omogućava platformsku nezavisnost. Sigurnost je kritična
jer je Java razvijena za mrežno okruženje, gde se programi preuzimaju preko mreže i ne želi se da se
izvršavanjem programa proizvede bilo kakva štetna aktivnost na računaru korisnika. Za razliku od C-a
i C++ -a Java oslobađa programera od direktnog upravljanja memorijom i to rešava automatskim
upravljanjem memorijom. Na taj način programiranje u Java-i je lakše i bezbednije i eleminišu se
problemi neadekvatnog upravljanja memorijom. JVM ima nekoliko komponenti preko kojih sprovodi
pomenute odgovornosti.
Postoji nekoliko stvari koje je potrebno pomenuti u vezi JVM-e:
 JVM specifikacija – to je dokument koji opisuje JVM karakteristike (features) i kako je
potrebno da one rade, takođe data je specifikacija skupa instrukcija bajt koda. Svako može da
iskoristi specifikaciju da bi implementirao svoju JVM-u. Postoji i specifikacija Java jezika
(Java Language Specification, skraćeno JLS), što je još jedan dokument koji daje opis sintakse i
semantike Java jezika, i jedan je od najobuhvatnijih resursa (materijala) za Java programski
jezik.
 konekretna implementacija JVM specifikacije. Popularne implementacije su: Oracle
HotSpot JVM, IBM JVM. Potrebno je reći da sve JVM implementacije ne slede JVM specifikaciju
 runtime instanca – instanca konkretne JVM implementacije
12
Pogledajmo primer:
Pretpostavimo da imamo Java program, sa nazivom Hello. Ovaj program izvršavamo putem komande:
java Hello
, instanca JVM je kreirana i učitana u memoriju, dakle to je runtime instanca, nakon toga JVM učitava
program Hello.class u memoriju i nakon toga ga izvršava. Kao što vidite na slici 11. oba su u memoriji
i JVM i program Hello.

slika 11. runtime instanca, učitavanje i JVM i programa u memoriju


Svaka Java aplikacija se pokreće u okviru runtime instance neke konkretne JVM implementacije.
Primetite takođe da runtime instanca, pokreće samo 1 Java aplikaciju.
U odnosi na performanse JVM ima kritičnu ulogu u obezbeđivanju da se Java izvršava brzo. Već smo o
tome govorili da je interpretiranje Java koda mnogo brže nego interpretiranje izvornog koda, zato što
bajt kod ima kompaktan format, već je kompajliran i takođe je optimizovan. Da bi smo dodatno
ubrzali izvršavanje, sprovodi se just-in-time (JIT) kompilacija i radi na sledeći način: kako se bajt
kod interpretira JVM nadgleda (monitor) frekvencu svakog dela izvršenog koda i neki deo koda se
možda više izvršava od drugog i kod koji se frekventno izvršava naziva se hot spots, „hot spot“-ovi se
zatim predaju JVM komponenti JIT kompajleru, JIT kompajler zatim konvertuje „hot spot“-ove u
mašinski kod i nakon toga ovaj mašinski kod se kešira, tj. čuva se u memoriji. U budućnosti ovaj keširan
mašinski kod omogućava brže performanse, dok se ostali deo koda i dalje interpretira preko Java
interpretera. Dakle, kod koji se frekventno izvršava ne interpretira se svaki put, već se kešira, a nakon
toga izvršava. JIT kompilacija se naziva dinamička kompilacija (dynamic compilation), jer je
kompajliranje mašinskog koda urađeno dinamički u runtime-u. Primetićete da dinamička kompilacija
ne postoji u JVM specifikaciji, jer to je implementacioni detalj. Neke od JVM implementacija možda ne
biraju da implementiraju dinamičku kompilaciju, ali većina JVM implementacija kao što su Oracle Hot
Spot i IBM JVM implementiraju dinamičku kompilaciju.
Pogledajmo sada primer da bi smo lakše osetili JVM kompilaciju. Pretpostavimo da imamo 2 metode
foo() i bar(). Za sada ćemo metode objasniti kao blokove koda koji mogu da budu pokrenuti mnogo puta
i one tipično predstavljaju poslovnu logiku softvera. Racimo da metoda bar() ima 50 linija koda. U
runtime-u bajt kod koji odgovara ovim 50 linijama koda je interpretiran od stane Java interpretera i
mašinski kod koji mu odgovara je izvršen. Recimo da se to dešava 1. put, 2. put, i sve do 1000-og puta.
Svaki put bajt kod koji odgovara ovom kodu je interpretiran i njegov mašinski kod koji mu odgovara je
izvršen, i to se izvršava 1000 puta. Zbog toga se metoda bar() smatra da je kod koji se frekventno, tj.
učestalo izvršava i samim tim on se opredeljuje za „hot spot“. Nakon toga se pokreće JIT kompajler i on
generiše svoju verziju mašinskog koda pomenute bar() metode. Ova verzija će biti optimizovana verzija
mašinskog koda koji je pokretan do sada. JIT sada kao regularan kompajler može da sprovede
optimizaciju i ovaj JIT generisan mašinski kod se kešira. Kada se metoda bar() pokrene 1001 put,
13
keširani mašinski kod će biti izvršen direktno. Dakle, neće biti više interpretiranja bajt koda u 50 linija
koda koji odgovaraju u ovoj metodi bar(). Obzirom da se mašinski kod izvršava direktno, biće brz kao
kod napisan u C-u ili C++ -u.

slika 12. optimizacija kompajliranja preko JIT – dinamičko kompajliranje


Nakon toga, recimo da je metoda bar() pokrenuta još 2000 puta, to može da pokrene novu rundu
optimizacije, od strane JIT kompajlera, za dalje ubrzavanje izvršavanja. Primetite da metoda foo() nije
izvršavana učestalo i zbog toga može biti interpretirana svaki put. Konceptualno gledano, ovako JIT
kompajler radi, sa nekim varijacijama u odnosu na implementaciju JVM-e.
Evo je tipična arhitektura JVM-e koja ima nekoliko komponenti.

slika 13. arhitektura JVM-e


Dakle, imamo program Hello.java, koji se kompajlira u program Hello.class. Kada izvršavamo
Hello.class upotrebom ranije opisane komande java Hello, tada će instanca JVM-e biti pokrenuta prvi
put. JVM tada poziva pod komponentu Class Loader, koja locira Hello.class i učitava odgovarajući
bajt kod u memoriju. Bajt kod se zatim verifikuje putem komponente Bytecode Verifier. Da bi se to
osiguralo, učitani .class fajl ima odgovarajuću internu strukturu i koji je u skladu sa pravilima Java
14
jezika. Ovo je kritično jer da bi se osigurao integritet JVM, obzirom da se .class fajlovi mogu preuzeti sa
mreže u slučaju apleta i generisani od strane loših ili zlonamernih kompajlera. Kada se bajt kod
verifikuje, tada se izvršava od strane Execution Engine, koja u uvom slučaju uključuje JIT
Compiler sa Interpreter-om. Garbage Collector je komponenta odgovorna za automatsko
upravljanje memorijom, što je jedna od glavnih odgovornosti JVM-e. Security Manager može da
dozvoli korisnicima da pokrenu nepouzdan bajt kod, dokle god bajt kod ne sprovodi neke opasne
operacije, npr. želite da sprečite bilo koji preuzeti bajt kod pristupa vašem fajl sistemu. Security
Manager se može osigurati da pokrene bajt kod u mnogo restriktivnijem okruženju koje se zove
sandbox okruženje. Na vrhu slike 13. imamo različite runtime data areas, koje formiraju deo
memorije koju JVM-a alocira. Kada se JVM-a pokrene, dobija od OS deo memorije da bi pokrenula
programe i različiti delovi Java programa će biti skladišteni u različitim delovima ove memorije.
U daljim poglavljima ćemo objasniti detaljno razne komponente i tipove memorije na primerima.
12. An Overview of Java SE
Kao što smo rekli na početku kursa upotrebom Java programskog jezika možemo kreirati aplikacije za
različite tipove uređaja: desktop aplikacije, Web serverske aplikacije, mobilne aplikacije i td.
Postoje odvojene platforme namenjene razvoju ovih različitih tipova aplikacija. Ovaj kurs je o jednoj
takvoj platformi koja se zove Java SE.
Java Software Family uključuje veći broj platformi koje koriste različite tipove uređaja. Postoje 3
platforme koje se najčešće koriste:
 Java Standard Edition (Java SE) – Samostalne aplikacije za desktop i servere, npr. sisitem
za upravljanje inventarom u prodavnici za kućnu opremu
 Java Enterprise Edition (Java EE) – Koristi se za razvoj poslovnih (enterprise) aplikacija,
za Web servere, npr. sajt za e-trgovinu kao što je Amazon. Koriste se tehnologije kao što su
Servlets i Java Server Pages (JSP). Java EE, uključuje Java SE, kao i neke dodatne biblioteke
specifično namenjene za razvoj poslovne aplikacije.
 Java Micro Edition (Java ME) – koristi se za razvoj aplikacija za uređaje sa ograničenim
resursima, kao što su mobilni telefoni.
Ukoliko želite da koristite i Java EE i Java ME, one su izgrađena na osnovama Java programskog jezika,
koji je Java SE. Takođe aplikacije za Android OS pametnih telefona, koriste Java-u.
Java SE, dolazi u 2 verzije:
 Java Runtime Environment (JRE) – to je runtime okruženje koje se koristi za pokretanje
Java aplikacija. Dakle, ako želite samo da pokrećete Java aplikacije dovoljno je da instalirate
JRE. JRE uključuje JVM i Java API. API – Application Programming Interface, je zapravo
Java biblioteka, koja uključuje predefinisane funkcionalnosti.
 Java Development Kit (JDK) – takođe se navodi kao JSDK – Java Software Development
Kit, služi za razvoj i pokretanje Java programa.
Dakle, JRE se koristi za pokretanje Java programa, dok JDK se koristi i za razvoj i za pokretanje Java
programa. Obzirom da JDK se koristi i za razvoj i za pokretanje Java programa, potrebno je reći da JDK
dolazi sa nekoliko alata, od kojih je glavni Java kompajler. Obzirom da JDK koristi i JVM i Java API,
samim tim uključuje JRE.
Java programi su napisani u formi klasa, dakle sve počinje sa klasom, čak i objekti koji se kreiraju iz
klasa. Java API dolazi sa JDK i on sadrži gomilu predefinisanih funkcionalnosti, što nije ništa drugo do
Java klase.
U ovom kursu koristimo Oracle JDK, umesto Open JDK.

15
16. Setting Classpath Environment Variable
Pre nego što krenemo na pisanje programa, a nakon instalacije JDK i podešavanje Environment
Variable-a, pogledaćemo Classpath promenljivu, čija vrednost je vidljiva na celom okruženju, što je kao
globalna promenljiva. Classpath je promenljiva, kao što joj ime kaže je putanja na fajl sisitemu za
lociranje Java klasa i može da uključi više od jedne putanje. Koristi se tokom kompilacije i izvršenja
Java programa. Classpath Environment Variable je specifična u odnosu na Java-u. Npr. ako
specificirate ranije pominjanu komandu java Hello, kompajler je potrebno da zna gde može da locira
pomenuti program, što je ništa do Hello.class. Da bi se pogledao program može da se koristi
Classpath. Na primer, recimo da je classpath uključuje 2 putanje: prvog gleda putanju .class fajla u
direktorijumu foo na c drajvu, to je prva putanja i ako nije nađena tu, pretražiće u drugoj putanji koja
uključuje bar direktorijum, u ovom slučaju pronalazi nešto u bar direktorijumu i zatim izvršava
Hello.class, slika 14.

slika 14. Java classpath


Primetite da je ovaj classpath, potreban samo kada kompajlirano i pokrećemo naše programe sa
komandne linije, a nije potrebno kada koristimo IDE, kao što je Eclipse. IDE je skraćenica od
Integrated Development Envirenment, integrisano razvojno okruženje.
17. WritingFirst Java Program
Pogledajmo strukturu Java programa. Java programi se sastoje od klasa (classes). Dakle, kada pišete
Java program pišete najmanje 1 klasu. Od klase možemo kreirati jedan ili više objekata (objects).
Objekat je centralni koncept objektno-orjentisanog programiranja. Elementi koji čine jednu klasu su:
 deklaracije promenljivih (variable declarations)
 konstruktori (constructors)
 metode (methods)
 ugnježdene klase (nested classes)
Program HelloWorld je tradicionalno prvi program koji se piše prilikom učenja novog programskog
jezika. Napisaćemo klasu HelloWorld i ta klasa će imati jedinu metodu koja će odštampati tekst Hello
World. Pogledajmo sada korake koje ćemo preduzeti:
 kreiraćemo strukturu direktorijuma, gde je javaindepth glavi direktorijum, a zatim imamo
nekoliko poddirektorijuma, gde je poslednji basics i Hello World program će biti u ovom
direktorijumu basics
javaindepth\src\com\semanticsquare\basics
 napisaćemo Hello.java u nekon tekst editoru, kao što je Notepad++ (Windows)
o korisitćemo tekst editor oko prvih 20% kursa, a zatim ćemo se prebaciti na Eclipse
 nakon toga ćemo kompajlirati program i pokrenuti ga
16
Prvo ćemo kreirati strukturu direktorijuma, upotrebom Command Prompt alata (CMD), tako što ćemo
otkucati komadu:
mkdir C:\javaindepth\src\com\sematicsquare\basics
Sada da bi smo se pomerili u pomenuti direktorijum, koristimo komandu:
cd C:\javaindepth\src\com\sematicsquare\basics

slika 15. kreiranje radnog direktorijuma pod Windows OS


Sledeće što ćemo uraditi jeste da ćemo napisati Java program i snimiti ga u basics direktorijum, a zatim
ćemo da ga kompajliramo i izvršimo iz ovog istog direktorijuma. Sada pređimo na pisanje koda.
Svaka klasa u Java-i, počinje sa rezervisanom rečju class, a rezervisanu reč prati ime klase i svaka
klasa ima otvorenu vitičastu zagradu i zatvorenu vitičastu zagradu. Unutar klase imaćemo samo jednu
metodu, koja se zove main metoda, koja isto kao i klasa ima vitičastu zagradu na početku i na kraju.
Naziv metode je main. Parametri metode su String[] args, što je niz (array) String-ova. void je
povratna vrednost metode (method output). public i static su modifikatori (modifiers). O svim ovim
elementima metode main, ćemo kasnije tokom kursa diskutovati. Ova metoda main, ima jednu naredbu
(statement), koja ima za cilj da odštampa tekst.
class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld!");
}
}
Snimo sada ovaj tekstualni fajl u Notepad++ - u, u Hello.java u direktoriju koji smo kreirali. Sada
ćemo iskompajlirati pomenuti program, putem komande, kao na slici 16. :
javac Helloworld.java

slika 16. kompajliranje HelloWorld.java programa


Ukoliko pogledamo sada direktorijum basics, videćemo da pored .java fajla imamo i fajl koji ima
ekstenziju .class i u njemu se nalazi Java bajtkod, kao na slici 17.

slika 17. izgled foldera nakon kompajliranja


17
Nalazimo se na Windows OS, i znamo da .class fajl može biti izvršen na bilo kojoj platformi. Sada
izvršimo program upotrebom Java interpretera kucanjem komande:
java HelloWorld

slika 18. izvršavanje Java programa

Vratimo se sada u Notepad++ program i primetimo da se i klasa zove HelloWorld i fajl se zove
Helloworld.java. Ok, ne moraju da budu istog naziva. Promenimo ime klase iz HelloWorld u
HelloWorld1. Kompajliramo isto kao na pređašnji način, upotrebom komande:
javac Helloworld.java
Ukoliko sada pogledamo direktorijum na disku vidimo da imamo HelloWorld.java, kao i
HelloWorld.class, kao i HelloWorld1.class. Obrisaćemo ranije kreirani HelloWorld.class.

slika 19. izgled foldera


Ovo je samo bio primer da se pokaže da ime klase ne mora da odgovara imenu fajla, ali u praksi to ne
bi trebalo da radi. U slučaju da postoji public modifikator na klasi, kao u kodu ispod, tada ime klase
i ime fajla moraju da budu isti:
public class HelloWorld1 {
public static void main(String[] args) {
System.out.println("HelloWorld!");
}
}
Ukoliko sada pokušamo kompilaciju, prikazaće se poruka:

slika 20. greška kad se ime fajla i ime klase razlikuju, a klasa imam public modifikator
Za slučaj da imamo 2 klase u fajlu, što ponovo ne bi trebalo da se radi, kao u kodu ispod, gde imamo 2
klase jedna je HelloWorld, a druga GoodBye, pri čemu obe od njih imaju main metode u kojima ispisuju
tekst na ekran, dok samo klasa HelloWorld je klasa sa public modifikatorom (samo 1 klasa u fajlu može
imati public modifikator).
Ukoliko sada kompajliramo pomenuti kod, videćemo da smo kreirali 2 .class fajla, jedan
HelloWorld.class, a drugi GoodBye.class, kao na slici 21.

slika 21. kompajliranje 2 fajla


18
public class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld!");
}
}

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

main metoda je metoda gde se vaš program počinje da se pokreće. Kada se izvrši komanda:
java HelloWorld
, JVM-a učitava Java bajtkod HelloWorld.class u memoriju i zatim poziva njegovu main() metodu.
main metoda mora biti deklarisana kao static, public i void. Iz main metode tipično pozivamo druge
klase, koje ne moraju da imaju main metodu. Samo klasa koja je izvršena sa komandne linije mora da
ima main metodu. Program se završava kada se završi main metoda.
18. Conclusion
Pokrili smo nekoliko važnih koncepata visokog nivoa Java-e:
 Java je dizajnirana da radi u mrežnom okruženju, koje se sastoji iz heterogenih korisničkih
uređaja. Rad u takvom okruženju nameće nekoliko jedinstvenih izazova:
o platformska nezavisnost – ovo je važno zbog toga što će softverske komponente biti
prosleđene između korisničkih uređaja i ove softverske komponente bi trebalo da budu
pokrenute na ovim uređajima bez ikakvih problema, bez obzira na operativni sisitem i
hardversku arhitekturu ovih uređaja. Da bi se postigla nezavisnost platforme, izvorni kod
se prvo kompajlira u među platformski nezavisana Java bajtkod, koji je zatim
interpretiran od platformski zavisne JVM-e. Imajte na umu da je JVM apstraktna mašina,
a Java bajtkod služi kao njen skup instrukcija.
o robusnost (robustness) – Java bajtkod može da se preuzme sa Internet-a, i može da
bude generisan od strane zlonamernih korisnika. Da bi se obezbedila robusnost
bajtkodovi se verifikuju pre samog izvršenja bajtkod verifikatorom (bytecode verifier)
o visoke performanse – Java je potrebno da bude brza, iz tog razloga bajtkod je
dizajniran da bude interpretiran brzo. Tehnike kao što su JIT kompilacija, omogućavaju
da Java bude jedva različita od C – a i C++ - a.
o familijarna i jednostavna – većina programera tokom 90-ih koristi C i C++. Java
dizajneri su želeli da sintaksa bude familijarna i zato je ona familijarna sintaksi C – a i
C++ - a. Jednostavnost je bila jedan od osnovnih zadataka Java-inih kreatora, pa je bilo
cilj ukoniti greše u vezi sa upravljanjem memorijom, koje su se javile kod C – a i C++ -a.
To se obezbeđuje automatskim upravljanjem memorijom upotrebom tehnike garbage
collection-a. Takođe ovo Java programe čini robusnijim.
o objektna-orjentisanost i višenitnost – Java je čist objektno-orjentisan jezik i
podržava višenitnost (multi-threading)

19
Section 3: Classes, Objects and their Members
20. Chapter Introduction
Pogledaćemo klase, objekte, kao neke osnovne jedinice koje čine klase i objekte. Java je objektno-
orjentisani jezik, tako da ćemo govoriti o objektno-orjentisanom okruženju i njegovoj upotrebi u
modelovanju scenarija iz realnog sveta. I zbog ovog ćemo predstaviti 2 osnovna koncepta kao što su
klase i objekti. Ove koncepte ćemo razumeti konceptualno i videćemo kako se kreiraju u Java-i.
Pokrićemo promenljive u potpunosti, gde je promenljiva (variable) osnovna jedinica klase i njena uloga
je da sadrži podatke. Sa jedne strane imamo promenljivu koja može da sadrži vrednost, potrebne su
nam i promenljive koje mogu da sadrže grupu vrednosti. Za to ćemo korisiti niz (array), koji je
najjednostavnija struktura podataka u svim programskim jezicima. Sa jedne strane promenljive
koristimo da čuvamo određene podatke, potreban nam je neki koncept koji će sadržati i enkapsulirati
poslovnu logiku (business logic) i to su metode (methods). Metode su takođe osnovne jedinice klase,
kao i promenljive. Poslovna logika softvera ili njegova poslovna logika će biti deo metoda. Na kraju
ćemo proći nešto što se zovu konstruktori (constructors), i kao što im ime kaže oni konstruišu nešto, a
šta je to nešto – to su objekti (objects).
21. Class & Objects
Java je objektno-orjentisani jezik, a spomenuli smo da objektno-orjentisani jezici pomažu da se
aplikacije modeluju na realniji način, tj. da modeluje scenarija iz realnog sveta na realniji način.
Objektno-orjentisano programiranje, kako mu samo ime kaže, je kompletno u vezi objekata, dok je sam
objekat kreiran iz klase.
Objektno-orjentisano programiranje, skraćeno OOP, ima svoje korene još 1960-ih. Dakle stara
je paradigma sa idejom da omogući implementaciju velikih i složenih projekata na jednostavan način.
To znači da OOP modeluje scenarija iz realnog sveta, na prirodniji način. To je osnovna
prednost objektno-orjentisanog programiranja.
Jedan od primera je sledeći - jedan student (student) je registrovan na neki konkretan kurs (course),
koji je ponuđen od strane konkretnog smera (department). Drugi primer bi bio kupac (customer) koji
kupuje određeni proizvod (product). Slično imamo kada doktor (doctor) leči pacijenta (patient). Svi ovi
primeri mogu prirodno biti modelovani u objektno-orjentisanom okruženju.
Pogledajmo kako je to moguće. Uzmimo 1. primer sa studentom koji je registrovan na neki konkretan
kurs koji je ponuđen od nekog smera.

slika 22. student – course – department


Ovde će student imati neke podatke (data) u vezi sebe, a takođe može da ima i neko ponašanje
(behaviour) u vezi sebe. Podaci će biti: ime studenta, godište studenta, pol, adresa i td. Ponašanja mogu
da budu: registrovanje na kurs ili ažuriranje informacija na profilu. Takođe i kursevi i smerovi će biti
povezani sa nekim podacima i nekim ponašanjima. Na slici 23. vidimo instancu, gde imamo studenta
sa imenom John, i imamo 4 kursa i 2 smera: računarska nauka (computer science, cs) i građevinski
(civil). Ovde imamo neke instance, gde su podaci (data) samo imena, kao što je John ili Java ili
računarska nauka (cs). Možemo da imamo 4 kursa sa slike 23. koja su ponuđena od strane smera za
računarske nauke (cs), a John može da se registruje na ova 3 kursa. Dakle, to su neka ponašanja ili
akcije koja se dešavaju između ove 2 instance. Ovo je realan scenario, gde se student John, registrovao
na 3 kursa, koja su ponuđena od strane smera za računarske nauke.

20
slika 23.

21

You might also like