Java interfejsi
Download
1 / 69

Objektno orijentisano programiranje - PowerPoint PPT Presentation


  • 148 Views
  • Uploaded on

Java, interfejsi. Objektno orijentisano programiranje. Određivanje klase objekta - nastavak. Iako se može koristiti metod forName() da bi se dobio Class objekat koji odgovara određenoj klasi ili interfejsu, postoji direktniji način

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Objektno orijentisano programiranje' - axl


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Java interfejsi

Java, interfejsi

Objektno orijentisano programiranje


Odre ivanje klase objekta nastavak
Određivanje klase objekta - nastavak

  • Iako se može koristiti metod forName() da bi se dobio Class objekat koji odgovara određenoj klasi ili interfejsu, postoji direktniji način

  • Ako nadovežemo .class na ime proizvoljne klase, interfejsa ili primitivnog tipa, imamo referencu na Class objekat te klase

  • npr. java.lang.String.class referiše Class objekat za klasu String, dok Pas.class referiše Class objekat za klasu Pas

  • int.class je Class objekat za primitivni tip int

  • Ovo možda u ovom trenutku ne izgleda posebno značajno, ali treba ga imati na umu


Odre ivanje klase objekta nastavak1
Određivanje klase objekta - nastavak

  • Pošto postoji samo po 1 Class objekat za svaku klasu ili interfejs, klasa objekta se može testirati programski

  • Zivotinja ljubimac;

    može se proveriti da li referiše na objekat klase Pas na sledeći način:

    if(ljubimac.getClass()==Pas.class)

    System.out.println(”To je pas!”);

  • Ako ljubimac sadrži referencu na objekat potklase klase Pas, rezultat poređenja u if-u je false

  • U Javi postoji operatorinstanceofkoji radi skoro istu stvar, ali ne i potpuno istu


Klasa class
Klasa Class

  • Klasa Class nije obična klasa

  • To je primer generičkog tipa ( zapravo definiše skup klasa)

  • Svaka klasa, interfejs, niz i primitivni tip koji koristimo u programu biće predstavljen objektom jedinstvene klase iz skupa definisanog Class generičkim tipom


Kopiranje objekata
Kopiranje objekata

  • protected metod clone() koji je nasleđen od klase Object kreiraće novi objekat koji je kopija tekućeg objekta

  • On će to uraditi jedino ako klasa objekta koji treba klonirati ukazuje da je kloniranje dopušteno, a to je slučaj kada klasa implementira interfejs Cloneable

  • Metod clone() nasleđen od Object klonira objekat kreiranjem novog objekta istog tipa kao što je tekući objekat i postavljajući svako od polja novog objekta na istu vrednost koju ima odgovarajuće polje tekućeg objekta


Kopiranje objekata1
Kopiranje objekata

  • Kada atributi tekućeg objekta referišu na objekte klasa, objekti na koje oni referišu se NE DUPLIRAJU prilikom kreiranja klona – samo se reference iskopiraju iz polja starog objekta u polja kloniranog objekta

  • To tipično nije ono što želimo da se desi – i novi i stari objekat onda mogu menjati taj deljeni objekat na koji se referiše preko njihovih odgovarajućih atributa, bez registrovanja da se to dešava


Kopiranje objekata2
Kopiranje objekata

  • Ako objekte klase treba klonirati, klasa mora implementirati Cloneable interfejs (implementiranje interfejsa obično uključuje implementiranje specifičnog skupa metoda )

  • Sve što je potrebno da bi klasa implementirala ovaj interfejs jeste da se to deklariše u prvoj liniji definicije klase pomoću ključne reči implements:

  • class Pas implements Cloneable{

    // Detalji definicije klase ...

    }

    onda se objekti klase Pas mogu klonirati

  • primer: kloniranje


Komentarisanje primera
Komentarisanje primera

  • PasLjubimac objekat može se kreirati sa:

    PasLjubimac mojLjubimac = new PasLjubimac(”Maza”,”Mesanac”);

  • Ako želite istog takvog, možemo ga klonirati:

    PasLjubimac vasLjubimac = (PasLjubimac)mojLjubimac.clone();

  • Sada imamo 2 PasLjubimac objekta koji sadrže referencu na isti objekat Buva

  • Metod clone() će kreirati novi PasLjubimac objekat vasLjubimac i kopirati referencu na objekat Buva iz atributa buva objekta mojLjubimac u istoimeni atribut objekta vasLjubimac


Komentarisanje primera1
Komentarisanje primera

  • ime ljubimca može se promeniti naredbom:

    vasLjubimac.setIme(”Lunja”);

  • Vaš pas će verovatno želeti sopstvenu buvu :) , pa možemo promeniti ime njegove buve naredbom:

    vasLjubimac.getBuva().setIme(”Buvica”);

  • Nažalost :) , Mazina buva će se takođe preimenovati u Buvica, pošto Maza i Lunja dele zajedničku buvu


Clone kopi konstruktor
clone() , kopi-konstruktor

  • Osim ako stvarno želimo da atributi dva različita objekta dele objekte na koje referišu, trebalo bi da metod clone() u našoj klasi implementiramo tako da radi kloniranje na odgovarajući način

  • Kao alternativa kloniranju ( ili zajedno sa njim ) možemo našoj klasi da dodamo konstruktor koji kreira novi objekat od postojećeg

  • Ako implementiramo našu sopstvenu public verziju clone() metoda da predefinišemo nasleđenu verziju, tipično ćemo kodirati ovaj metod na isti način kao što bismo i kopi-konstruktor


Primer clone metoda
Primer clone() metoda

  • clone() metod klase PasLjubimac mogao bi biti:

    public Object clone() throws CloneNotSupportedException{

    PasLjubimac ljubimac = new PasLjubimac(ime, rasa);

    ljubimac.setIme(”Lunja”);

    ljubimac.getBuva().setIme(”Buvica”);

    return ljubimac;

    }

  • Ovde metod kreira novi PasLjubimac objekat koristeći ime i rasu tekućeg objekta


Primer clone metoda1
Primer clone() metoda

  • Mogli smo koristiti i nasleđeni clone() metod da dupliramo tekući objekat i onda da eksplicitno kloniramo član buva da bi referisao na nezavisan objekat

  • public Object clone() throws CloneNotSupportedException{

    PasLjubimac ljubimac = (PasLjubimac)super.clone();

    ljubimac.buva = (Buva)buva.clone();

    return ljubimac;

    }

  • Novi objekat kreiran nasleđenim clone() metodom je objekat klase PasLjubimac, ali se vraća kao referenca klase Object

  • Za pristup članu buva neophodna je referenca na PasLjubimac pa je ovde kastovanje od ključnog značaja

  • Efekat ove verzije clone() metoda je isti kao i prethodne verzije


Metodi sa promenljivim brojem argumenata
Metodi sa promenljivim brojem argumenata

  • Moguće je pisati metod koji prima proizvoljan broj argumenata pri pozivu i argumenti koji se prosleđuju ne moraju biti istog tipa

  • Da bi se razumelo kako to funkcioniše, neophodno je razumeti ulogu klase Object.

  • Da metod očekuje proizvoljan broj argumenata ukazuje se navođenjem poslednjeg parametra u obliku

    Object ... args

  • Metod može imati 0 ili više parametara pre ovoga, a ovaj mora biti poslednji


Metodi sa promenljivim brojem argumenata1
Metodi sa promenljivim brojem argumenata

  • Ime parametra args predstavlja niz tipa Object[] i vrednosti argumenata sudostupne u elementima niza kao tip Object.

  • Unutar tela metoda, dužina niza args nam kaže koliko argumenata je prosleđeno.

  • Jednostavan primer:

    želimo da implementiramo statički metod koji će prihvatati proizvoljan broj

    argumenata i ispisivati argumente u komandnu liniju – šta god da su

    public static void printAll(Object ... args){

    for(Object arg : args)

    System.out.print(” ” + arg);

    System.out.println();

    }

  • argumenti mogu biti sasvim proizvoljnih tipova

  • na vrednosti primitivnih tipova biće primenjen autoboxing, jer metod očekuje reference kao argumente


Metodi sa promenljivim brojem argumenata2
Metodi sa promenljivim brojem argumenata

  • Jedna od upotreba mogućnosti promenljive liste argumenata u bibliotekama klasa jeste za definisanje printf() metoda u PrintStream klasi. Ovaj metod proizvodi formatirani izlaz za proizvoljnu sekvencu vrednosti proizvoljnih tipova, pri čemu je formatiranje određeno prvim argumentom metoda

  • System.out je tipa PrintStream, pa se printf() može koristiti da proizvede formatirani izlaz u komandnoj liniji


Ograni avanje tipova u promenljivoj listi argumenata
Ograničavanje tipova u promenljivoj listi argumenata

  • Tip promenljive liste argumenata ne mora biti Object, možemo staviti proizvoljnu klasu ili interfejs.

  • Argumenti onda moraju biti tog zadatog tipa ili njegovog proizvoljnog podtipa.

  • Ako se stavi da je tip Object, maksimizuje se fleksibilnost jer se mogu prosleđivati argumenti proizvoljnog tipa, ali u mnogim situacijama želimo da ograničimo koji tipovi argumenata mogu da se proslede

  • Primer: ako hoćemo da definišemo metod koji računa prosečnu vrednost proizvoljnog broja vrednosti koje se zadaju kao posebni argumenti, onda želimo da budemo sigurni da su argumenti isključivo numeričke vrednosti


Primer
Primer

  • public static double average(Double ... args){

    if(args.length = = 0)

    return 0;

    double avg = 0.0;

    for(double value : args)

    ave += value;

    return ave/args.length;

    }

  • U ovom slučaju, argumenti moraju biti tipa Double ili tipa izvedenog iz Double ili – zbog autoboxing konverzije obezbeđene kompajlerom – tipa double

  • Ako bismo pokušali da prosledimo vrednosti tipa int kao argumente metoda, kompajler bi to označio kao grešku, jer ne postoji automatska konverzija tipa int u tip Double


Kastovanje objekata
Kastovanje objekata

  • Moguće je kastovati objekat u tip neke druge klase, ali jedino ako su klasa tekućeg objekta i nova klasa u istoj hijerarhiji izvedenih klasa i jedna je superklasa druge

  • Object

    Zivotinja

    Macka Pas Patka

    Sarplaninac


Kastovanje objekata1
Kastovanje objekata

  • Moguće je kastovati referencu na objekat klase naviše u tip njene direktne ili indirektne superklase.

  • Npr. moguće je kastovati referencu na objekat tipa Sarplaninac direktno u tip Pas, Zivotinja ili Object.

  • Sarplaninac ljubimac = new Sarplaninac(”Sarko”);

    Zivotinja zivotinja = (Zivotinja) ljubimac;

    // kastovanje Sarplaninac Zivotinja

  • Kada izvršimo dodelu reference na objekat promenljivoj tipa superklase, nije neophodno eksplicitno pisati kastovanje, može se pisati i samo:

  • Zivotinja zivotinja = ljubimac;

  • Kompajler će uvek po potrebi sam ubaciti kastovanje u tip superklase


Kastovanje objekata2
Kastovanje objekata

  • Kada kastujemo referencu na objekat u tip superklase, Java pamti stvarnu klasu kojoj taj objekat pripada.

  • Da to nije slučaj, polimorfizam ne bi bio moguć.

  • Pošto se pamti informacija o originalnom tipu objekta, moguće je i kastovanje naniže kroz hijerarhiju klasa

  • Ipak, kastovanje naniže se uvek mora izvršiti eksplicitno pošto ga kompajler ne umeće sam.

  • Da bi kastovanje radilo, objekat mora biti legitimna instanca klase u koju kastujemo, tj. klasa u koju kastujemo mora biti stvarna klasa objekta, ili superklasa objekta


Kastovanje objekata3
Kastovanje objekata

  • Npr. moguće je kastovanje reference iz promenljive zivotinja u tip Pas ili Sarplaninac, pošto je početno objekat bio Sarplaninac, ali nije moguće kastovanje u Mačka ili Patka pošto objekat klase Sarplaninac nema klase Mačka ili Patka za superklase

  • Za kastovanje zivotinja u tip Pas možemo pisati:

  • Pas pas = (Pas) zivotinja; // kastovanje Zivotinja Pas

  • Upamtiti da se promenljiva pas može koristiti samo za poziv polimorfnih metoda klase Sarplaninac koji predefinišu metode koji postoje u Pas. Ne mogu se pozivati metodi koji nisu definisani u klasi Pas. Ako želimo da zovemo metod koji postoji u klasi Sarplaninac, a ne i u klasi Pas, moramo prvo kastovati pas u tip Sarplaninac


Kastovanje objekata4
Kastovanje objekata

  • Iako nije moguće kastovanje objekata koji nisu u vezi, npr. Sarplaninac Patka, moguće je postići konverziju pisanjem odgovarajućeg konstruktora, ali samo gde ima smisla raditi tako nešto

  • Napiše se konstruktor u klasi u koju hoćemo da konvertujemo i on treba da prihvata objekat klase iz koje konvertujemo kao argument

  • Ono što u tom slučaju radi konstruktor je prilično različito u odnosu na kastovanje. Ovde se kreira potpuno nov objekat koji je odvojen od originala, dok kastovanje predstavlja isti objekat kao različit tip


Kada kastovati objekte
Kada kastovati objekte?

  • Postojaće razlozi za kastovanje objekata u oba pravca kroz hijerarhiju klasa

  • npr. kadgod polimorfno izvršavamo metode, smeštamo objekte u promenljivu bazne klase i pozivamo metode izvedene klase. To u opštem slučaju uključuje kastovanje objekata izvedene klase u baznu klasu

  • Drugi razlog za kastovanje naviše kroz hijerarhiju je da bi se prosledio objekat neke od mogućih potklasa metodu. Zadavanjem da je parametar baznog tipa imamo fleksibilnost da metodu prosledimo objekat proizvoljne izvedene klase

  • npr. ako je parametar tipa Zivotinja, možemo proslediti objekat tipa Pas, Patka ili Mačka


Kada kastovati objekte1
Kada kastovati objekte?

  • Razlog zbog koga možda želimo da kastujemo naniže kroz hijerarhiju klasa je da bismo izvršili metod specifičan za određenu klasu.

  • Ako klasa Patka ima metod snesiJaje(), npr. ne možemo ga pozivati koristeći promenljivu tipa Zivotinja, čak i ako ona referiše na objekat klase Patka.

  • Kao što je rečeno, kastovanje naniže kroz hijerarhiju klasa uvek zahteva eksplicitno kastovanje

  • Primer:

    Patka patka = new Patka(”Pata”, ”Polarna patka”);

    Zivotinja ljubimac = patka; // kastovanje Patke u Zivotinju

    ljubimac.snesiJaje(); // Ovo se nece iskompajlirati!!!

    dobićemo poruku kompajlera da metod snesiJaje() nije nađen u klasi Zivotinja


Kada kastovati objekte2
Kada kastovati objekte?

  • Pošto znamo da je ovaj objekat stvarno Patka, možemo izmeniti prethodni fragment koda tako da radi, tako što bi poziv metoda trebalo da bude:

    ((Patka)ljubimac).snesiJaje(); // ovo radi

  • objekat na koji pokazuje ljubimac prvo se kastuje u tip Patka. Rezultat kastovanja se zatim koristi za poziv metoda snesiJaje(). Da objekat nije bio tipa Patka, kastovanje bi uzrokovalo izbacivanje izuzetka


Preporuka
Preporuka

  • Generalno, trebalo bi izbegavati eksplicitno kastovanje objekata koliko je to moguće, jer ono uvećava mogućnost nekorektnog kastovanja, što naše programe čini nepouzdanim.

  • Ako smo pažljivo dizajnirali naše klase, eksplicitna kastovanja nam neće prečesto biti neophodna.


Identifikovanje objekata
Identifikovanje objekata

  • Postoje okolnosti kada možda ne znamo tačno sa kojim tipom objekata rukujemo. To se može desiti ako se objekat izvedene klase prosledi metodu kao argument za parametar tipa bazne klase

  • U nekim situacijama možda je neophodno kastovati objekat u njegov stvarni tip, recimo da bi se pozvao metod specifičan za klasu.

  • Ako pokušamo da izvršimo kastovanje i ispostavi se da je to ”ilegalno”, biće izbačen izuzetak i naš program će se završiti, osim ako nismo obezbedili hvatanje izuzetaka. Jedan od načina da se to izbegne je proveriti da je objekat tipa koji očekujemo pre nego što izvršimo kastovanje


Identifikovanje objekata1
Identifikovanje objekata

  • Ranije smo videli da možemo da koristimo metod getClass() da bismo dobili Class objekat koji odgovara klasi i kako možemo da ga uporedimo sa instancom klase Class za klasu koju tražimo.

  • To se takođe može uraditi korišćenjem operatora instanceof

  • Pretpostavimo da imamo promenljivu ljubimac tipa Zivotinja i želimo da je kastujemo u tip Patka. Može ovako:

    Patka patka;

    if(ljubimac instanceof Patka) {

    patka = (Patka) ljubimac;

    patka.snesiJaje();

    }


Identifikovanje objekata2
Identifikovanje objekata

  • Ako ljubimac ne referiše na Patka objekat, pokušaj kastovanja objekta referisanog pomoću ljubimac u Patka doveo bi do izbacivanja izuzetka

  • Prethodni fragment koda može i kompaktnije da se zapiše:

    if(ljubimac instanceof Patka)

    ((Patka)ljubimac).snesiJaje();

  • KOJA JE RAZLIKA IZMEĐU instanceof i getClass()?

    Razlika je prilično suptilna:

    • instanceof operator proverava da li je kastovanje objekta referisanog levim operandom u tip zadat desnim operandom dopušteno. Rezultat će biti true ako je objekat istog tipa kao desni operand ili ako je tipa proizvoljne njegove potklase

    • Razlika se može ilustrovati neznatnom izmenom jednog jednostavnog primera ( pretpostavka je da se u ljubimac nalazi referenca na objekat tipa Sarplaninac. Želimo da pozovemo metod definisan u klasi Pas, pa je potrebno da proverimo da ljubimac zaista referiše na Pas objekat )


Instanceof vs getclass
instanceof vs. getClass()

  • if(ljubimac instanceof Pas)

    System.out.println(”Imate psa!”);

    else

    System.out.println(”Definitivno nije pas!”);

  • Dobićemo potvrdu da imamo Pas objekat čak i ako je to stvarno Sarplaninac objekat

  • Ovo je dobro za potrebe kastovanja!

  • Međutim, ako napišemo:

  • if(ljubimac.getClass() = = Pas.class)

    System.out.println(”Imate psa!”);

    else

    System.out.println(”Definitivno nije pas!”);

    izraz if će imati vrednost false jer je klasa objekta Sarplaninac, pa je njen Class objekat različit od onoga za Pas.class – morali bismo da napišemo Sarplaninac.class da bi izraz if imao vrednost true.


Zaklju ak instanceof ili getclass
Zaključak: instanceof ili getClass()

  • Za svrhe kastovanja treba uvek koristiti operator instanceof da bi se proverio tip reference

  • Kada je potrebno potvrditi tačan tip reference, treba proveriti Class objekat odgovarajući za referencu


Dizajniranje klasa
Dizajniranje klasa

  • Osnovni problem u OOP jeste odlučiti na koji način treba da budu povezane klase našeg programa.

  • Jedna mogućnost jeste da se kreira hijerarhija klasa njihovim izvođenjem iz bazne klase koju smo definisali i dodavanjem metoda i atributa da specijalizujemo potklase. Jedan primer ovoga su klasa Zivotinja i potklase izvedene iz nje

  • Druga mogućnost je definisati skup klasa koje nisu u hijerarhiji, ali koje imaju atribute koji su sami po sebi objekti. Npr. klasa Zoo može kao atribute imati objekte klasa izvedenih iz klase Zivotinja


Dizajniranje klasa1
Dizajniranje klasa

  • Možemo imati i hijerarhije klasa koje sadrže atribute koji su objekti – to već imamo kod klasa izvedenih iz Zivotinja pošto one imaju atribute tipa String.

  • Kod primera koje smo videli do sada, bilo je očigledno koji pristup odabrati, međutim, nije uvek tako.

  • Prilično često treba izabrati između definisanja klasa kao hijerarhije i definisanja klasa sa atributima koji su objekti. Šta je najbolji pristup?

  • Nema striktnog pravila. Postoje, ipak, neke smernice i neki konteksti u kojima je izbor očigledniji

  • Osim želje da se odraze odnosi između tipova i objekata koji važe u stvarnosti, potreba za korišćenjem polimorfizma je primarni razlog za upotrebu potklasa ili interferjsa. To je suština OO programiranja

  • Posedovanje povezanih objekata koji se mogu ekvivalentno tretirati može dosta uprostiti naše programe


Primer1
PRIMER

  • Mnoge situacije uključuju prosuđivanje o dizajnu naših klasa.

  • Razmotrimo opcije u praksi na jednostavnom primeru.

  • Želimo da definišemo klasu PolyLine da bismo predstavili geometrijske entitete koji se sastoje od povezanih duži(segmenata), tj. poligonalne linije

  • Deluje razumno da se tačke predstavljaju kao objekti klase Point. Tačke su dobro definisani objekti koji će se javljati u kontekstu svih vrsta geometrijskih entiteta


Primer2
Primer

  • Sledeće pitanje koje možemo da postavimo moglo bi da bude: treba li da izvedemo klasu PolyLine iz klase Point?

  • Odgovor je prilično očigledan: poligonalna linija jasno nije vrsta tačke, pa nije logično izvesti klasu PolyLine iz klase Point.

  • Ovo je elementarna demonstracija ”je”-testa. Ako možemo reći da: jedna vrsta objekta ”je” specijalizovana forma druge vrste objekta, imamo dobar slučaj za izvođenje klase ( ali ne uvek – mogu postojati i kontrarazlozi ). Ako ne možemo to reći – ništa od izvođenja!

  • Komplement ”je”-testa je ”ima”-test. Ako jedan objekat ”ima” komponentu koja je objekat druge klase, imamo situaciju za atribut koji je tipa klase.


Primer3
Primer

  • Objekat House ”ima” vrata, pa bi trebalo da promenljiva tipa Door bude član klase House.

  • Klasa PolyLine će sadržati nekoliko tačaka, što deluje obećavajuće, ali treba pobliže pogledati kako ćemo ih čuvati, pošto postoji nekoliko opcija.

    DIZAJNIRANJE KLASE PolyLine

  • Niz objekata tipa Point deluje kao dobar kandidat za atribut klase.Međutim, postoje mane toga. Uobičajeni zahtev za poligonalne linije je mogućnost dodavanja segmenta postojećem objektu. Sa nizom za smeštanje tačaka, morali bismo da kreiramo novi niz svaki put kada dodamo segment, a zatim da kopiramo sve tačke iz starog niza u novi. To može trošiti dosta vremena ako imamo PolyLine objekat sa velikim brojem segmenata


Dizajniranje klase polyline
DIZAJNIRANJE KLASE PolyLine

  • Imamo još jednu opciju, a to je povezana lista tačaka. U svojoj najjednostavnijoj formi, povezana lista objekata je uređenje u kome svaki objekat liste sadrži referencu na sledeći objekat kao atribut.

  • Sve dok imamo promenljivu koja sadrži referencu na prvi Point objekat, možemo pristupiti svim tačkama u listi


Dizajniranje klase polyline1
Dizajniranje klase PolyLine

  • Tačke se čuvaju kao članovi ListPoint objekta.

  • Osim konstruktora, klasa PolyLine će trebati i metod za dodavanje tačaka.

  • Možemo koristiti jedan od najmanje tri pristupa za definisanje klase ListPoint. Mogu se navesti razlozi u korist sva 3.

    • u klasi ListPoint koordinate x i y se mogu čuvati eksplicitno. Glavni razlog protiv ovoga bio bi da već imamo enkapsulirana svojstva tačke u klasi Point, zašto to ne iskoristiti?

    • možemo posmatrati ListPoint objekat kao nešto što sadrži referencu na Point objekat, plus članove koji referišu na prethodni i naredni objekat u klasi. To nije nerazuman pristup i lako se implementira.

    • ListPoint objekat možemo posmatrati i kao specijalizovanu vrstu Point objekta, pa bismo mogli da izvedemo ListPoint klasu iz klase Point. Da li je ovo razumno ili ne zavisi od našeg gledanja na to.


Dizajniranje klase polyline2
Dizajniranje klase PolyLine

  • Odlučimo se za drugu varijantu.

  • Klasa ListPoint se može implementirati sa atributom tipa Point, koji definiše osnovnu tačku i njene koordinate. ListPoint objekat će imati i atribut next, tipa ListPoint kome je svrha da sadrži referencu na sledeći objekat u klasi.

  • Za neki ListPoint objekat znaćemo da je poslednji element liste ako je vrednost njegovog next atributa null.

  • Point.java

  • ListPoint.java

  • ListPoint objekat je sredstvo za kreiranje liste Point objekata koji potiču od kojekuda, tako da ne moramo da brinemo oko dupliranja Point objekata smeštenih u listi. Možemo samo sačuvati referencu na Point objekat prosleđenu konstruktoru u atribut point. Atribut next treba da sadrži referencu na sledeći ListPoint u listi, i pošto on ovde nije definisan, postavljamo next na null.


Dizajniranje klase polyline3
Dizajniranje klase PolyLine

  • getNext() metod omogućuje da se odredi sledeća tačka u listi, pa je ovaj metod sredstvo pomoću kojeg se može iterirati kroz celu listu

  • PolyLine.java

  • Klasa PolyLine ima 2 atributa start i end i oni referišu na prvu i poslednju tačku u listi ili null ako je lista prazna

  • Čuvanje krajnje tačke u listi nije ključno, pošto uvek možemo da je nađemo idući kroz listu počev od start. Međutim, posedovanje reference na krajnju tačku štedi mnogo vremena kada želimo da dodamo tačku u listu.

  • Konstruktor prihvata niz Point objekata i počinje proces sklapanja objekta kreirajući listu koja sadrži jedan LinePoint objekat, kreiran od prvog elementa niza, a zatim koristi metod addPoint() da doda sve preostale tačke niza u listu.


Dizajniranje klase polyline4
Dizajniranje klase PolyLine

  • Dodavanje tačke u listu: sve što addPoint() metod radi je da kreira ListPoint objekat od Point objekta prosleđenog kao argument, postavlja atribut next stare krajnje tačke u listi da referiše na novu tačku i, konačno, smešta referencu na novu krajnju tačku u atribut end.

  • TestPolyLine.java

  • Ova klasa radi dovoljno dobro, ali nije sasvim objektno-orijentisana

  • Bolji pristup je napraviti povezanu listu opšte namene. ( Tu bi elementi liste bili objekti klase Object. Pošto je ona superklasasvake klase, u promenljivoj tipa Object može se čuvati proizvoljna vrsta objekta )


Final modifajer
final modifajer

  • final – za fiksiranje vrednosti statičkog atributa klase

  • Ključna reč final može se koristiti i u definiciji metoda i u definiciji klase

  • Ako želimo da sprečimo da se u potklasi predefiniše metod klase, taj metod treba deklarisati kao final u baznoj klasi.

  • Pokušaj da se predefiniše final metod u potklasi rezultovaće označavanjem novog metoda kao greške od stane kompajlera.

  • Očigledno, apstraktni metod ne može biti deklarisan kao final jer mora biti definisan u nekoj potklasi.

  • Ako deklarišemo klasu kao final, sprečićemo da proizvoljna potklasa može da se izvede iz nje.


Final modifajer1
final modifajer

  • public final class PolyLine{

    // Definicija klase kao ranije ...

    }

  • Ako onda pokušamo da izvedemo klasu iz ove klase, kompajler će prijaviti grešku.

  • Apstraktna klasa ne može biti deklarisana kao final pošto će to sprečiti da apstraktni metodi klase budu ikada definisani.

  • Deklarisanje klase kao final je drastičan korak koji sprečava da funkcionalnost klase bude proširena izvođenjem, pa treba da budemo potpuno sigurni da je to ono što želimo.


Interfejsi
Interfejsi

  • U klasama koje smo izveli iz klase Zivotinja, imali smo zajednički metod zvuk(), koji je individualno implementiran u svakoj od potklasa. Potpis metoda je bio isti u svakoj klasi i metod se mogao polimorfno pozivati.

  • Glavni razlog da se najpre definiše klasa Zivotinja, a zatim Pas, Macka itd. iz nje, jeste da bismo mogli da koristimo polimorfizam.

  • Kada je sve što želimo skup jednog ili više metoda koje treba implementirati u različitim klasama tako da možemo da ih zovemo koristeći polimorfizam, možemo koristiti tzv. interfejs.


Interfejsi1
Interfejsi

  • Interfejs je, u suštini, kolekcija povezanih konstanti i/ili apstraktnih metoda i u većini slučajeva sadrži samo metode. Interfejs ne definiše šta radi metod. On samo definiše njegov oblik – ime, parametre, povratni tip, tako da su po definiciji metodi u interfejsu apstraktni.

  • Da bismo koristili interfejs, implementiramo interfejs u klasi, tj. deklarišemo da klasa implementira interfejs i pišemo kod za svaki od metoda koji interfejs deklariše kao deo definicije klase.

  • Kada klasa implementira interfejs, sve konstante koje su eventualno definisane u definiciji interfejsa direktno su dostupne u klasi, upravo kao da su nasleđene iz bazne klase


Interfejsi2
Interfejsi

  • Interfejs može sadržati konstante, apstraktne metode ili i jedne i druge

  • Metodi u interfejsu su uvekpublic i abstract, pa ne moramo to eksplicitno da navodimo

  • Smatra se lošom programerskom praksom zadavati bilo kakav atribut za njih, i definitivno se ne mogu dodati drugi atributi osim tih podrazumevanih (public, abstract). Ovo povlači da metodi deklarisani u interfejsu nikada NEMOGU biti statički

  • Konstante u interfejsu su uvek public, static i final, pa ni za njih nema potrebe navoditi eksplicitno ove atribute


Interfejsi3
Interfejsi

  • Interfejs se deklariše kao i klasa, ali koristeći ključnu reč interface umesto class. Definiciju interfejsa čuvamo u fajlu sa ekstenzijom .java i imenom istim kao i ime interfejsa.

  • Ime koje damo interfejsu mora se razlikovati od imena ostalih interfejsa i klasa istog paketa.


Enkapsuliranje konstanti u programu
Enkapsuliranje konstanti u programu

  • Često se dešava da program koristi skup konstantnih vrednosti koje želimo da definišemo samo jednom

  • U verzijama Jave pre 5.0, uobičajeni pristup bio je da se definiše skup povezanih konstanti u interfejsu, a zatim implementira interfejs u svakoj klasi koja koristi neku od tih konstanti. Taj pristup je zastareo zbog mogućnosti static import-a

  • Mogućnost importovanja statičkih članova klase, uvedena u Javi 5, obezbeđuje odličan način rukovanja konstantama u programu.

  • Međutim, upotreba interfejsa u te svrhe je u prošlosti bila vrlo rasprostranjena

  • Upotreba static import-a za pristup konstantama definisanim u nekoj klasi je mnogo čistiji i bolji način da se skup konstanti učini dostupnim gde god je potreban.


Konstante u interfejsu
Konstante u interfejsu

  • public interface Konstante{ double PI = 3.14;

    double E = 2.72;

    double TRIPLE_E=3*E;

    }

  • Pošto su konstante u interfejsu uvek static i final ( i public, ali to u ovoj rečenici nije bitno), moramo uvek obezbediti inicijalne vrednosti za te konstante.

  • Vrednost jedne konstante može se izraziti u terminima neke prethodne kao što je to slučaj sa TRIPLE_E.

  • Pošto smo interfejs deklarisali kao public, konstante su dostupne i izvan paketa u kome se nalazi interfejs.


Konstante u interfejsu1
Konstante u interfejsu

  • Možemo pristupati konstantama definisanim u interfejsima na isti način kao i statičkim i public atributima klase – kvalifikovanjem njihovih imena imenom interfejsa

  • npr.

    public class MojaKlasa{

    ...

    return r * r * Konstante.PI;

    ...

    }

  • Pošto interfejs Konstante uključuje samo konstante, klasa im može pristupiti koristeći njihova nekvalifikovana imena deklarisanjem da klasa implementira ovaj interfejs. To je bila tehnika korišćena u prošlosti

  • npr.

    public MojaDrugaKlasa implements Konstante{

    ...

    return r * r * PI;

    ...

    }

  • Konstante definisane u interfejsuKonstantesu sada članovi klaseMojaDrugaKlasai biće nasleđeni u proizvoljnoj izvedenoj klasi


Konstante definisane u klasi
Konstante definisane u klasi

  • Možemo definisati klasu koja će sadržati isti skup konstanti kao interfejs:

  • package matematika;

    public class Konstante{

    public static final double PI = 3.14;

    public static final double E = 2.72;

    public static final double TRIPLE_E = 3 * E;

    }

  • Naravno, možemo pristupati članovima klase Konstante izvan te klase kvalifikovanim imenom klase, npr.

    Konstante.TRIPLE_E


Konstante definisane u klasi1
Konstante definisane u klasi

  • Alternativa i uobičajeniji pristup je importovanje statičkih članova klase u proizvoljnu klasu koja koristi neku od ovih konstanti. To će omogućiti korišćenje konstanti pomoću njihovih nekvalifikovanih imena. U ovom slučaju, klasa mora biti u imenovanom paketu, jer import deklaracija ne može da se primeni na bezimeni paket

  • npr.

    import static matematika.Konstante.*;

    public class MojaDrugaKlasa{

    ...

    return r * r * PI;

    }


Interfejsi koji deklari u metode
Interfejsi koji deklarišu metode

  • Primarna svrha interfejsa je da definiše eksterni oblik skupa metoda koji predstavljaju određenu funkcionalnost

  • Svaki metod deklarisan u interfejsu mora imati definiciju unutar klase koja implementira taj interfejs ako hoćemo da kreiramo konkretne objekte te klase

  • Pošto su metodi u interfejsu po definiciji public, moramo koristiti ključnu reč public kada ih definišemo u našoj klasi – inače se kod neće iskompajlirati. Implementacija metoda interfejsa u klasi ne sme imati pristupni atribut koji je restriktivniji od implicitnog u deklaraciji apstraktnog metoda, a ne postoji manje restriktivan atribut od public.


Interfejsi koji deklari u metode1
Interfejsi koji deklarišu metode

  • Klasa može implementirati više od jednog interfejsa. U tom slučaju, pišemo imena svih interfejsa koje klasa implementira razdvojene zapetama nakon ključne reči implements. Npr.

  • public class MojaKlasa implements Int1, Int2, Int3 {...}

  • Ova klasa implementira 3 interfejsa.

  • Telo klase sadržaće definicije metoda deklarisanih u sva 3 interfejsa

  • Ne mora se implementirati svaki metod interfejsa, ali onda postoje neke posledice toga


Delimi na implementacija interfejsa
Delimična implementacija interfejsa

  • Moguće je izostaviti implementaciju jednog ili većeg broja metoda interfejsa u klasi koja implementira interfejs, ali u tom slučaju klasa nasleđuje neke apstraktne metode od interfejsa, pa moramo deklaristi samu klasu kao apstraktnu:

  • import static matematika.Konstante.E;

    import static matematika.Konstante.PI;

    public abstract class MojaKlasa implements Naredbe{...}

    i neka npr. klasa MojaKlasa implementira samo neke od metoda interfejsa Naredbe

  • Ne možemo kreirati objekte (apstraktne) klase MojaKlasa

  • Da bismo dospeli do korisne klase, moramo definisati potklasu klase MojaKlasa koja implementira preostale metode interfejsa.

  • Deklaracija klase kao abstract je obavezna kada ne implementiramosve metode deklarisane u interfejsu. Kompajler će se buniti ako to zaboravimo.


Cloneable interfejs
Cloneable interfejs

  • Rečeno je ranije da moramo da implementiramo interfejs Cloneable da bismo koristili nasleđeni metod clone().

  • Zapravo, ovaj interfejs je prazan, bez metoda ili konstanti, pa je sve što je potrebno da bi se implementirao u klasi, navesti da ga ta klasa implementira.

  • To znači da je samo potrebno napisati nešto nalik:

    public MojaKlasa implements Cloneable{...}

  • Jedina svrha interfejsa Cloneable je da glumi fleg koji signalizira da li smo spremni da dozvolimo da objekti naše klase budu klonirani ili ne.

  • Čak i ako smo definisali public clone() metod, kompajler neće dopustiti da se taj metod poziva za objekte naše klase osim ako takođe ne zadamo da naša klasa implementira Cloneable interfejs.


Izvo enje iz interfejsa
Izvođenje iz interfejsa

  • Možemo definisati jedan interfejs na osnovu drugog korišćenjem ključne reči extends za identifikovanje imena baznog interfejsa. To je istog oblika koji koristimo da izvedemo jednu klasu iz druge

  • Interfejs koji se izvodi dobija sve metode i konstante od interfejsa iz koga se izvodi

    • public interface Konverzija extends Konstante{...}

  • Interfejs iz koga se vrši izvođenje naziva se i super-interfejsom za interfejs koji se izvodi.


Interfejsi i vi estruko nasle ivanje
Interfejsi i višestruko nasleđivanje

  • Za razliku od klase koja može da nasledi samo jednu klasu, interfejs može da nasledi proizvoljan broj interfejsa.

  • Da bismo definisali interfejs koji nasleđuje članove nekoliko drugih interfejsa, zadajemo imena tih interfejsa razdvojena zapetama nakon ključne reči extends, npr.

  • public interface MojInterfejs extends TvojInterfejs, NasInterfejs{...}

  • Sada MojInterfejs nasleđuje sve metode i konstante članove interfejsa TvojInterfejs i NasInterfejs

  • To se naziva višestrukim nasleđivanjem

  • U Javi, klase ne podržavaju, a interfejsi podržavaju višestruko nasleđivanje


Interfejsi i vi estruko nasle ivanje1
Interfejsi i višestruko nasleđivanje

  • Potrebna je pažnja prilikom korišćenja ove mogućnosti. Ako 2 ili više super-interfejsa deklarišu metod sa istim potpisom, taj metod mora imati isti povratni tip u svim interfejsima koji ga deklarišu. Ako ne, kompajler će prijaviti grešku. Ovo zbog toga što bi bilo nemoguće da klasa implementira oba metoda pošto imaju isti potpis. Ako je metod deklarisan identično u svim interfejsima koji ga deklarišu, onda će jedna definicija u klasi zadovoljiti sve interfejse

  • Kao što je rečeno ranije, svaki metod u klasi mora imati jednistven potpis, a povratni tip nije deo toga


Kori enje interfejsa
Korišćenje interfejsa

  • Za šta treba koristiti interfejse?

  • Interfejs koji deklariše metode definiše standardni skup operacija. Razne klase mogu dodati takav standardni interfejs implementirajući ga. Tako objekti raznih klasa mogu da dele zajednički skup operacija. Naravno, data operacija u jednoj klasi može biti implementirana posve različito od načina na koji je implementirana u drugoj klasi. Ali, način na koji se poziva operacija je isti za objekte svih klasa koje implementiraju interfejs.

  • Najvažnija upotreba interfejsa: pošto interfejs definiše tip, možemo izvršiti polimorfizam kroz skup klasa koje implementiraju isti interfejs. To je jako korisno. Pogledajmo


Interfejsi i polimorfizam
Interfejsi i polimorfizam

  • Nije moguće kreirati objekte tipa interfejsa, ali moguće je kreirati promenljivu tipa interfejsa. Npr.

  • Konstante konst = null; // promenljiva tipa interfejsa Konstante

  • Ako ne možemo kreirati objekte tipa Konstante, kakva korist od toga? Koristimo tu promenljivu za smeštanje reference na objekat proizvoljne klase koja implementira interfejs Konstante.

  • To znači da ovu promenljivu možemo koristiti kako bismo polimorfno pozivali metode deklarisane u interfejsu Konstante

  • Videćemo kako to izgleda na pogodnom primeru koji se odnosi na kućnu audio/video opremu i daljinsko upravljanje


Pogodan primer interfejsi i polimorfizam
Pogodan primer – interfejsi i polimorfizam

  • TV, hi-fi, VCR, DVD player i svaki od njih ima svoj daljinski upravljač.

  • Svi daljinski upravljači verovatno imaju neki zajednički podskup dugmadi – power on/off, volume up, volume down, mute, itd.

  • Želimo ”fancy” univerzalni daljinski upravljač – vrstu jedinstvene definicije daljinskog upravljača koji će odgovarati svoj opremi

  • Univerzalni daljinski ima mnoštvo sličnosti sa interfejsom. Sam po sebi, univerzalni daljinski ne radi ništa. On definiše skup dugmadi za standardne operacije, ali operacija za svako dugme mora biti specifično programirana da odgovara svakoj vrsti uređaja kojim želimo da upravljamo


Primer univerzalni daljinski
Primer – univerzalni daljinski

  • TV, VCR, DVD itd. možemo predstaviti klasama, a svaka od njih će koristiti isti interfejs daljinskog upravljanja – tj. skup dugmadi – ali svaka na drugačiji način

  • RemoteControl.java

    public interface RemoteControl{...}

  • U interfejsu ne postoji definicija nijednog metoda

  • Metodi deklarisani u interfejsu su uvek apstraktni po definiciji, a takodje su i public.

  • Sada, proizvoljna klasa koja zahteva korišćenje funkcionalnosti obezbeđene RemoteControl interfejsom samo ima da deklariše da implementira RemoteControl interfejs i da uključi definicije za svaki od metoda iz interfejsa


Primer univerzalni daljinski1
Primer – univerzalni daljinski

  • TV.java

  • import static java.lang.Math.max;

    import static java.lang.Math.min;

    public class TV implements RemoteControl {...}

  • Ova klasa implementira sve metode deklarisane u interfejsu RemoteControl, i svaki metod ispisuje poruku tako da znamo kada je pozvan.

  • VCR.java

  • Klasa VCR takođe implementira RemoteControl

  • Naravno, možemo nastaviti i definisati klase za druge vrste uređaja koje koriste daljinski, ali ove dve su dovoljne za demonstraciju principa


Primer univerzalni daljinski2
Primer – univerzalni daljinski

  • TestRemoteControl.java

    • import static java.lang.Math.random;

      public class TestRemoteControl{...}

  • Ovo je klasa koja operiše i TV i VCR objektima preko promenljive tipa RemoteControl

  • Promenljiva remote je tipa RemoteControl pa je možemo koristiti za smeštanje reference na objekat proizvoljne klase kojaimplementira RemoteControl interfejs

  • Unutar for-petlje kreiramo na slučajan način TV ili VCR objekat

  • Pošto se tip objekta određuje u vreme izvršavanja i na slučajan način, izlaz iz programa demonstrira polimorfizam u akciji kroz promenljivu tipa interfejsa


Kori enje vi e interfejsa
Korišćenje više interfejsa

  • RemoteControl objekat u prethodnom primeru može se koristiti za poziv samo onih metoda koji su deklarisani u interfejsu.

  • Ako klasa implementira neki drugi interfejs osim RemoteControl, onda bi za poziv metoda deklarisanih u tom interfejsu trebalo ili koristiti promenljivu tipa tog interfejsa za čuvanje reference na objekat ili kastovati referencu na objekat u tip njegove stvarne klase

  • Neka je klasa definisana sa:

    public class MojaKlasa implements RemoteControl, AbsoluteControl{

    // Definicija klase koja uključuje metode iz oba interfejsa

    }


Kori enje vi e interfejsa1
Korišćenje više interfejsa

  • Pošto klasa implementira RemoteControl i AbsoluteControl, možemo smestiti objekat tipa MojaKlasa u promenljivu bilo kog od tipova ova 2 interfejsa, npr.

    AbsoluteControl ac = new MojaKlasa();

  • Sada možemo koristiti promenljivu ac za pozivanje metoda deklarisanih u AbsoluteControl interfejsu. Međutim, ne možemo pozivati metode deklarisane u RemoteControl interfejsu koristeći ac, čak i ako referenca na objekat koju čuva ima ove metode.

  • Jedna mogućnost je kastovati referencu u njen originalni klasni tip:

    ((MojaKlasa)ac).powerOnOff();


Kori enje vi e interfejsa2
Korišćenje više interfejsa

  • Pošto kastujemo referencu u tip MojaKlasa, možemo zvati proizvoljan metod definisan u toj klasi. Međutim, ovako ne možemo dobiti polimorfno ponašanje. Kompajler će odrediti koji metod se poziva u vreme kompajliranja

  • Da bismo pozivali metode iz RemoteControl polimorfno, moraćemo da imamo referencu sačuvanu kao taj tip (RemoteControl). Znajući da je objekat tipa klase koja implementira RemoteControl interfejs, možemo od reference smeštene u ac dobiti referencu tipa RemoteControl:

    if(ac instanceof RemoteControl)

    ((RemoteControl)ac).mute();

  • Čak i ako interfejsi RemoteControl i AbsoluteControl nisu ni u kakvoj vezi, možemo kastovati referencu iz ac u tip RemoteControl. To je moguće jer je objekat referisan pomoću ac zapravo tipa MojaKlasa, koji implementira oba interfejsa.


Parametri metoda tipa interfejsa
Parametri metoda tipa interfejsa

  • Parametar metoda može biti tipa interfejsa.

  • To specijalno znači da se kao argument može proslediti objekat proizvoljne klase koja implementira taj interfejs

  • Zadavanjem da je tip parametra interfejs, nagoveštavamo da je metod zainteresovan samo za metode interfejsa. Sve dok je objekat tipa koji implementira te metode, on je prihvatljiv kao argument.

  • Ova tehnika deklarisanja parametra interfejsnog tipa se intenzivno koristi unutar biblioteke klasa.

  • Klase String, StringBuilder i StringBuffer implementiraju CharSequence interfejs, a postoji mnoštvo njihovih metoda koji imaju parametre tipa ovog interfejsa


ad