Da saznate u čemu je razlika između rano (statično) I kasno (dinamično) vezivanja u Javi, prvo morate razumjeti šta je to vezivanje . Povezivanje znači da postoji veza između veze i koda. Na primjer, varijabla koju referencirate je vezana za kod u kojem je definirana. Slično tome, metoda koja se poziva je vezana za lokaciju u kodu gdje je definirana.

Postoje dvije vrste povezivanja metoda u jeziku Java: rano povezivanje (takođe nazvano statičko) i kasno povezivanje (respektivno, dinamičko) vezivanje . Pozivanje metode u Javi znači da je metoda vezana za određeni kod, bilo u vrijeme kompajliranja ili u vrijeme izvođenja, kada se program pokrene i kreiraju objekti. Kao što ime sugerira, statičko povezivanje je statičnije po prirodi jer se dešava u vrijeme kompajliranja, što znači da kod „zna“ koju metodu treba pozvati nakon kompajliranja Java izvornog koda u datoteke klasa. A pošto se ovo odnosi na ranu fazu životnog ciklusa programa, naziva se i rano uvezivanje. S druge strane, dinamičko povezivanje se dešava u toku rada, nakon što program pokrene Java virtuelna mašina. U ovom slučaju, koju metodu treba pozvati određuje određeni objekt, tako da informacije nisu dostupne u vrijeme kompajliranja jer se objekti kreiraju u vrijeme izvođenja. A pošto se to dešava kasno u životnom ciklusu programa, to se u Javi naziva kasno povezivanje. Pogledajmo još nekoliko razlika kako bismo ovo bolje razumjeli i mogli odgovoriti na ovo vrlo popularno pitanje postavljeno u Java intervjuima.

Rano i kasno uvezivanje u Javi

Postoje mnoge razlike između statičkog i dinamičkog povezivanja u Javi, ali najvažnije je kako ih JVM koristi. Da li ste se ikada zapitali kako JVM odlučuje koju metodu će pozvati kada postoji više metoda sa istim imenom u opsegu? Ako ste ikada koristili preopterećenje ili nadjačavanje metoda, znate da u Javi možete imati više metoda s istim imenom. U slučaju Jave virtuelna mašina JVM koristi i statičko i dinamičko vezivanje za odabir željene metode.

Primjer statičkog i dinamičkog povezivanja u Javi

U ovom programu ćete vidjeti da se povezivanje virtuelnih metoda ne događa u vrijeme kompajliranja korištenjem statičkog vezivanja, jer bi to pozvalo metodu iz superklase, kao što se dešava sa statičkim metodama koje su rano vezane. Ako se pozove metoda iz podklase, korišten je određeni objekt za povezivanje funkcije u vrijeme izvođenja, pa se stoga dinamičko vezivanje koristi za povezivanje virtualnih funkcija. javna klasa Main ( public static void main (String args) (// Primjer statičkog i dinamičkog povezivanja u Javi Aktuelno osiguranje = novo CarInsurance () ;// Vezivanje zasnovano na dinamičkom objektu int premium = trenutno. premium();// Statičko vezivanje zasnovano na klasi
Kategorija stringa = trenutna. kategorija();

Sistem. van. println("premium: " + premium);

Sistem. van. println("kategorija: " + kategorija) ;
  1. ) ) klasa Osiguranje (javno statično konačno int LOW = 100 ; javna int premija () (vraćanje LOW; ) javna statička kategorija stringa () (vraćanje "Osiguranje" ; ) ) klasa CarInsurance produžava osiguranje (javno statično konačno int HIGH = 200 ; public int premium () ( return HIGH; ) public static String kategorija () ( return "Auto Insurance" ; ) ) Rezultati izvršenja: premium : 200 kategorija : Osiguranje Kao što vidite, pozivanje metode premium() rezultiralo je izvršenjem metodu iz potklase, dok je pozivanje metode category() rezultiralo izvršenjem metode superklase. To je zato što je premium() virtuelna metoda koja se rješava kasnim povezivanjem, dok je kategorija() statička metoda koja se rješava statičkim povezivanjem u vrijeme kompajliranja na ime klase.

  2. Budući da se statičko povezivanje javlja rano u životnom ciklusu programa, ono se naziva rano povezivanje. Isto tako, dinamičko povezivanje se naziva i kasno povezivanje jer se javlja kasnije u izvršavanju programa.

  3. Statičko vezivanje se koristi u jeziku Java za rješavanje preopterećenih metoda, dok se dinamičko vezivanje koristi u jeziku Java za rješavanje nadjačanih metoda.

  4. Slično, privatne, statičke i terminalne metode rješavaju se pomoću statičkog vezivanja jer se ne mogu nadjačati, dok se sve virtualne metode rješavaju korištenjem dinamičkog povezivanja.

  5. U slučaju statičkog povezivanja, ne koriste se konkretni objekti, već informacije o tipu, odnosno tip referentne varijable se koristi za otkrivanje željene metode. S druge strane, dinamičko povezivanje koristi određeni objekat da pronađe željeni metod u Javi.
Evo dobre vježbe zasnovane na konceptima statičkog i dinamičkog povezivanja u Javi. Možete li odgovoriti na pitanje: "Šta će biti izlaz kada se izvrši sljedeći program?" Šta će ovaj program proizvesti? Kolekcija, Set ili HashSet? To je sve što smo hteli da vam kažemo o razlikama između njih rano (statično) I kasno (dinamično) uvezivanje u Javi. Ovo je jedno od najboljih Java pitanja za telefonski intervju jer pruža dosta mogućnosti za testiranje dubine znanja kandidata. Uvijek zapamtite to privatni , statički I konačne metode komunicirati koristeći statičko vezivanje , A virtuelno – dinamično . Slično tome, najbolji primjer statičkog vezivanja je preopterećenje metode, dok je nadjačavanje dinamičko.

23. mart 2010 dec5e

U PHP 5.3 ovo se pojavilo zanimljiva prilika, poput kasnog statičkog povezivanja. Ono što slijedi je malo slobodan prijevod opisa iz službenog priručnika.

Od PHP 5.3.0, jezik je uveo funkciju zvanu kasno statičko vezivanje, koja se može koristiti za referenciranje pozivajuće klase u kontekstu statičkog nasljeđivanja.

Ova karakteristika je nazvana "kasno statičko vezivanje". "Kasno povezivanje" znači da static:: neće biti razriješen u odnosu na klasu u kojoj je metoda definirana, ali će biti procijenjena u vrijeme izvođenja. "Statično povezivanje" znači da se može koristiti u pozivima statičke metode(ali ne samo na njih).

Ograničenja za sebe::

Primjer #1: Upotreba self::

Primjer će ispisati:

Korištenje kasnog statičkog povezivanja

Kasnije statičko povezivanje pokušava riješiti ovo ograničenje uvođenjem ključna riječ, koji se odnosi na klasu prvobitno pozvanu tokom izvršavanja. To jest, ključna riječ koja će omogućiti da se B referencira iz test() u prethodnom primjeru. Odlučeno je da se ne uvodi nova riječ, već da se koristi već rezervirana statička .

Primjer #2: Jednostavna upotreba static::

Primjer će ispisati:

Napomena: static:: ne radi kao $this za statičke metode! $this-> prati pravila nasljeđivanja, ali static:: ne. Ova razlika je pojašnjena u nastavku.

Primjer #3: Upotreba static:: u nestatičnom kontekstu

test(); ?>

Primjer će ispisati:

Napomena: Kasno statičko vezivanje zaustavlja proces rješavanja poziva. Statički pozivi koristeći ključne riječi roditelj:: ili self:: prosljeđuju informacije o pozivu.

Primer #4: Prebacivanje i neprenos poziva

Primjer će ispisati

Edge Cases

Ima ih mnogo na razne načine pozovite metodu u PHP-u, kao što su povratni pozivi ili magične metode. Budući da se kasno statičko vezivanje rješava u vrijeme izvođenja, to može dovesti do neočekivanih rezultata u takozvanim rubnim slučajevima.

Primjer #5 Kasno statičko vezivanje u magijskim metodama

foo; ?>

Ovaj paragraf, uprkos svojoj kratkoći, veoma je važan - skoro sav profesionalan programiranje u Javi se zasniva na upotrebi polimorfizma. Istovremeno, studentima je ova tema jedna od najtežih za razumijevanje. Stoga se preporučuje da pažljivo pročitate ovaj odlomak nekoliko puta.

Metode klase su označene statičkim modifikatorom iz razloga - za njih, prilikom kompajliranja programskog koda, statičko povezivanje. To znači da u kontekstu koje klase je ime metode navedeno u izvornom kodu, veza se postavlja na metodu te klase u prevedenom kodu. Odnosno, sprovodi se vezivanje naziva metode na mjestu poziva sa izvršnim kodom ovu metodu. Ponekad statičko povezivanje pozvao rano vezivanje, budući da se javlja u fazi kompilacije programa. Statičko povezivanje u Javi se koristi u još jednom slučaju - kada je klasa deklarisana sa finalnim modifikatorom (“final”, “final”).

Objektne metode u Javi su dinamičke, odnosno podložne su dinamičko povezivanje. Javlja se u fazi izvršavanja programa direktno tokom poziva metode, a u fazi pisanja ove metode nije unapred poznato iz koje klase će poziv biti upućen. Ovo je određeno tipom objekta za koji ovaj kod radi - kojoj klasi objekt pripada, iz koje klase se poziva metoda. Ovo vezivanje se javlja dugo nakon što je kod metode kompajliran. Stoga se ova vrsta vezivanja često naziva kasno uvezivanje.

Programski kod zasnovan na pozivu dinamičke metode, posjeduje imovinu polimorfizam– isti kod radi različito u zavisnosti od toga koji tip objekta ga zove, ali radi iste stvari na nivou apstrakcije u vezi sa izvorni kod metoda.

Da bismo objasnili ove riječi, koje na prvo čitanje nisu baš jasne, razmotrimo primjer iz prethodnog pasusa - rad metode moveTo. Neiskusni programeri smatraju da ovu metodu treba zaobići u svakoj klasi potomaka. Ovo se zapravo može uraditi i sve će raditi kako treba. Ali takav kod će biti izuzetno suvišan - na kraju krajeva, implementacija metode će biti u svim klasama potomaka Slika potpuno isto:

public void moveTo(int x, int y)(hide(); this.x=x; this.y=y; show(); );

Štaviše, ovaj slučaj ne koristi prednost polimorfizma. Tako da to nećemo učiniti.

Često je zbunjujuće i zašto apstraktna klasa Slika napisati implementaciju ove metode. Uostalom, pozivi metodama skrivanja i prikazivanja koji se koriste u njemu, na prvi pogled, trebali bi biti pozivi apstraktne metode– odnosno, izgleda da uopšte ne mogu da rade!

Ali metode skrivanja i prikazivanja su dinamičke, što, kao što već znamo, znači da se povezivanje naziva metode i njenog izvršnog koda vrši u fazi izvršavanja programa. Stoga je činjenica da su ove metode specificirane u kontekstu klase Slika, ne znači da će biti pozvani iz razreda Slika! Štaviše, možete garantovati da metode skrivanja i prikazivanja nikada neće biti pozvane iz ove klase. Neka imamo varijable dot1 tipa Dot i circle1 tipa Circle, a njima se dodeljuju reference na objekte odgovarajućih tipova. Pogledajmo kako se ponašaju pozivi dot1.moveTo(x1,y1) i circle1.moveTo(x2,y2).

Kada se pozove dot1.moveTo(x1,y1), dolazi do poziva iz klase Slika moveTo metod. Zaista, ova metoda u klasi Dot nije nadjačana, što znači da je naslijeđena od Slika. U metodi moveTo, prva naredba je poziv dinamičke metode skrivanja. Implementacija ove metode je preuzeta iz klase čija je instanca objekt dot1 koji poziva ovu metodu. Odnosno, iz klase Dot. Dakle, poenta je skrivena. Zatim se mijenjaju koordinate objekta, nakon čega se on poziva dinamička metoda show. Implementacija ove metode je preuzeta iz klase čija je instanca objekt dot1 koji poziva ovu metodu. Odnosno, iz klase Dot. Tako se na novoj lokaciji prikazuje tačka.

Za pozivanje circle1.moveTo(x2,y2) sve je apsolutno slično - dinamičke metode hide i show pozivaju se iz klase čiji je objekt circle1 instanca, odnosno iz klase Circle. Dakle, to je krug koji je skriven na starom mjestu i prikazan na novom.

To jest, ako je objekat tačka, tačka se pomera. A ako je predmet krug, krug se kreće. Štaviše, ako jednog dana neko napiše, na primer, klasu Ellipse koja je potomak Circle i kreira objekat Elipsa elipsa=nova elipsa(…), zatim pozivanjem ellipse.moveTo(…) premjestit će se elipsa na novu lokaciju. I to će se dogoditi u skladu s načinom na koji se metode skrivanja i prikazivanja implementiraju u klasi Ellipse. Imajte na umu da će kompajlirani polimorfni kod klase raditi odavno Slika. Polimorfizam je osiguran činjenicom da se reference na ove metode ne stavljaju u kod metode moveTo u vrijeme kompajliranja - one su konfigurirane za metode s takvim imenima iz klase objekta koji poziva odmah u trenutku kada se metoda moveTo poziva.

Postoje dvije vrste objektno orijentiranih programskih jezika: dinamičke metode– zapravo dinamičan i virtuelno. Po principu rada potpuno su slični i razlikuju se samo po karakteristikama implementacije. Zovi virtuelne metode brže. Pozivanje dinamičkih je sporije, ali tabela usluga dinamičke metode(DMT – Tabela dinamičkih metoda) zauzima nešto manje memorije od tabele virtuelne metode(VMT – Tabela virtuelnih metoda).

To može izgledati kao izazov dinamičke metode nije vremenski efikasan zbog dužine vremena potrebnog za traženje imena. U stvari, tokom poziva se ne vrši traženje imena, već se koristi mnogo brži mehanizam koristeći pomenutu tabelu virtuelnih (dinamičkih) metoda. Ali nećemo se zadržavati na specifičnostima implementacije ovih tabela, budući da u Javi ne postoji razlika između ovih vrsta metoda.

6.8. Osnovna klasa Object

Klasa Object je osnovna klasa za sve Java klase. Stoga su sva njegova polja i metode naslijeđene i sadržane u svim klasama. Klasa Object sadrži sljedeće metode:

  • public Boolean jednak (Object obj)– vraća true u slučaju kada su vrijednosti objekta iz kojeg je metoda pozvana i objekta koji je prošao kroz obj referencu na listi parametara jednake. Ako objekti nisu jednaki, vraća se false. U klasi Object, jednakost se tretira kao referentna jednakost i ekvivalentna je operatoru poređenja "==" . Ali kod potomaka ova metoda se može nadjačati i može upoređivati ​​objekte po njihovom sadržaju. Na primjer, ovo se događa za objekte numeričkih klasa ljuske. Ovo se lako može provjeriti pomoću koda poput ovog:

    Dvostruki d1=1,0,d2=1,0; System.out.println("d1==d2 ="+(d1==d2)); System.out.println("d1.equals(d2) ="+(d1.equals(d2)));

    Prvi red izlaza će dati d1==d2 =false , a drugi će dati d1. jednako (d2)=tačno

  • javni int hashCode()– pitanja hash code objekt. Haš kod je uslovno jedinstveni numerički identifikator povezan sa elementom. Iz sigurnosnih razloga, ne možete dati adresu objekta aplikacijskom programu. Stoga, u Javi, hash kod zamjenjuje adresu objekta u slučajevima kada je u neku svrhu potrebno pohraniti tablice adresa objekata.
  • zaštićeni objekt klon() izbacuje CloneNotSupportedException – metoda kopira objekat i vraća vezu na kreirani klon (duplikat) objekta. U potomcima klase Object, potrebno ju je redefinisati, a takođe i naznačiti da klasa implementira interfejs Clonable. Pokušaj pozivanja metode iz objekta koji se ne može klonirati uzrokuje podizanje izuzetka CloneNotSupportedException("Klon nije podržan"). Interfejsi i situacije izuzetaka će biti razmotrene kasnije.

    Postoje dvije vrste kloniranja: plitko (plitko), kada se vrijednosti polja originalnog objekta kopiraju jedan na jedan u klon, i duboko (duboko), u kojem se kreiraju novi objekti za polja referentni tip, klonirajući objekte na koje se originalna polja odnose. U plitkom kloniranju, i original i klon će referencirati iste objekte. Ako objekt ima samo polja primitivni tipovi, nema razlike između plitkog i dubokog kloniranja. Implementaciju kloniranja vrši programer koji razvija klasu, nema automatskog mehanizma za kloniranje. I to je u fazi razvoja klase da odlučite koju opciju kloniranja odabrati. U velikoj većini slučajeva to je potrebno duboko kloniranje.

  • javni završni razred getClass()– vraća referencu na metaobjekat klase tipa. Uz njegovu pomoć, možete dobiti informacije o klasi kojoj objekt pripada i pozvati njegove metode klase i polja klase.
  • zaštićena void finalize() throws Throwable – poziva se prije nego se objekt uništi. Mora se nadjačati u onim potomcima Object-a u kojima je potrebno izvršiti neke pomoćne radnje prije uništavanja objekta (zatvoriti datoteku, prikazati poruku, nacrtati nešto na ekranu, itd.). Ova metoda je detaljnije opisana u odgovarajućem paragrafu.
  • javni niz toString()– vraća string reprezentaciju objekta (što je adekvatnije moguće). U klasi Object, ova metoda proizvodi niz potpuno kvalificiranog imena objekta (sa imenom paketa), nakon čega slijedi znak "@", a zatim heksadecimalni hash kod objekta. Većina standardnih klasa poništava ovu metodu. Za numeričke klase vraća se string reprezentacija broja, za string klase – sadržaj stringa, za klase znakova – sam karakter (a ne string reprezentacija njegovog koda!). Na primjer, sljedeći isječak koda

    Object obj=new Object(); System.out.println(" obj.toString() daje "+obj.toString()); Double d=new Double(1.0); System.out.println(" d.toString() daje "+d.toString()); Znak c="A"; System.out.println("c.toString() daje "+c.toString());

    će dati zaključak

    obj.toString() daje java.lang.Object@fa9cf d.toString() daje 1.0 c.toString() daje A

Postoje i metode obavijesti(), obavijesti sve(), i nekoliko preopterećenih varijanti metode čekaj, dizajniran za rad sa nitima. O njima se raspravlja u odjeljku o temama.

6.9. Dizajneri. Rezervisane riječi super i ovo. Blokovi inicijalizacije

Kao što je već spomenuto, objekti u Javi se kreiraju korištenjem rezervirane riječi new, nakon čega slijedi konstruktor - poseban potprogram koji kreira objekt i inicijalizira polja kreiranog objekta. Tip povratka nije specificiran za njega i nije ni metoda objekta (poziva se kroz ime klase kada objekat još ne postoji) niti metoda klase (objekt i njegova polja su dostupni u konstruktoru preko reference this) . U stvari, konstruktor, u kombinaciji sa operatorom new, vraća referencu na objekat koji se kreira i može se smatrati posebnim tipom metode koja kombinuje karakteristike metoda klase i metoda objekta.

Ako objekt ne zahtijeva nikakvu dodatnu inicijalizaciju kada je kreiran, možete koristiti konstruktor, koji je po defaultu prisutan za svaku klasu. Ovo je ime klase, praćeno praznim zagradama - bez liste parametara. Nema potrebe specificirati takav konstruktor kada se razvija klasa;

Ako je potrebna inicijalizacija, obično se koriste konstruktori sa listom parametara. Pogledali smo primjere takvih konstruktora za klase Dot i Circle. Klase Dot i Circle su naslijeđene od apstraktne klase, u kojoj nije bilo konstruktora. Ako postoji nasljeđivanje od neapstraktne klase, odnosno one koja već ima konstruktor (čak i zadani konstruktor), javlja se određena specifičnost. Prva izjava u konstruktoru mora biti poziv konstruktoru iz nadklase. Ali to se ne radi kroz ime ove klase, već pomoću rezervirane riječi super(iz "superklase"), nakon čega slijedi lista parametara potrebnih za konstruktor bake i djeda. Ovaj konstruktor inicijalizira polja podataka koja su naslijeđena od superklase (uključujući bilo koje ranije pretke).

Na primjer, napišimo klasu FilledCircle - potomak Circle, čija će instanca biti nacrtana kao krug u boji. paket java_gui_example; import java.awt.*; javna klasa FilledCircle proširuje Circle( /** Kreira novu instancu FilledCircle */ public FilledCircle(Graphics g,Color bgColor, int) ( super(g,bgColor,r); this.color=color; ) public void show())(Boja oldC=graphics.getColor(); graphics.setColor(color); graphics.setXORMode(bgColor); grafika. fillOval (x,y,size,size) graphics.setColor() public void hide())(Boja oldC=graphics.getColor(); graphics.setColor(); setXORMode( graphics.fillOval(x,y,size,size) graphics.setPaintMode();

Općenito, logika za kreiranje složenih objekata: prvo se kreira i inicijalizira roditeljski dio objekta, počevši od dijela naslijeđenog od klase Object, pa dalje duž hijerarhije, završavajući dijelom koji pripada samoj klasi. Zbog toga je obično prva izjava konstruktora poziv konstruktoru bake i djeda super ( lista parametara), budući da pristup neinicijaliziranom dijelu objekta koji pripada roditeljskoj klasi može dovesti do nepredvidivih posljedica.

U ovoj nastavi koristimo napredniji način crtanja i „skrivanja“ oblika u odnosu na prethodne razrede. Zasnovan je na XOR (ekskluzivnom ili) načinu crtanja. Ovaj način rada se postavlja metodom setXORMode. U ovom slučaju, ponovljeni izlaz figure na isto mjesto dovodi do vraćanja originalne slike u izlaznu oblast. Prijelaz u normalan način slikanja vrši se metodom setPaintMode.

Vrlo često se koriste u konstruktorima

Uvezivanje- zamjena posebnih poziva funkcija u programske kodove - metode klase. Ima smisla samo za izvedene klase.

Obično kompajler ima potrebne informacije da odredi na koju se funkciju misli. Na primjer, ako program naiđe na poziv obj.f(), kompajler na jedinstven način bira funkciju f() ovisno o tipu odredišnog obj. Ako program koristi pokazivače na instance class:ptr->f(), izbor metode funkcije - klase određen je tipom pokazivača.

Ako se odabir funkcije vrši u vrijeme kompajliranja, imamo posla statičko povezivanje.

U ovom slučaju, funkcija - metoda osnovne klase - će biti pozvana za pokazivač na osnovnu klasu, čak i ako je pokazivaču na osnovnu klasu dodijeljena vrijednost adrese instance izvedene klase.

Ako se izbor funkcije vrši u fazi izvršavanja programa, imamo posla dinamičko povezivanje.

U ovom slučaju, ako se tokom izvršavanja programa pokazivaču na osnovnu klasu dodijeli adresa instance osnovne klase, biće pozvana metoda osnovne klase; Ako je pokazivaču na osnovnu klasu dodijeljena adresa instance izvedene klase, bit će pozvana metoda izvedene klase.

Virtualne funkcije

Po defaultu, izvedene klase su statički povezane. Ako se dinamičko povezivanje treba koristiti za bilo koju metodu klase, takve metode moraju biti deklarirane virtuelno .

Virtualne funkcije:

    imati virtualnu ključnu riječ u prototipu u osnovnoj klasi;

    obavezne funkcije člana klase:

    Sve izvedene klase moraju imati isti prototip (navođenje riječi virtual u izvedenim klasama nije potrebno).

Ako bilo koja metoda u izvedenim klasama ima isto ime kao u osnovnoj klasi, ali različitu listu parametara, imamo preopterećene funkcije.

Primjer: klase Point i Circle.

virtualni void print();

class Circle: public Point(

void print(); // možete virtualno void print();

void Point::print()

cout<< "Point (" << x << ", " << y << ")";

void Circle::print()

cout<< "Circle with center in "; Point::print();

cout<< "and radius " << rad;

Upotreba:

Tačka p1(3,5), p2(1,1), *pPtr;

Krug c1(1), c2(p2, 1);

pPtr = pPtr->print(); // dobiti: Bod (3, 5)

pPtr = pPtr->print(); // dobiti:

Krug sa centrom u tački (1, 1) i poluprečnikom 1

Primjer dinamičkog povezivanja: Lista

Najčešća upotreba dinamičkog povezivanja je sa klasama kontejnera koje sadrže pokazivač na osnovnu klasu; Takve klase kontejnera mogu uključivati ​​informacije koje se odnose i na osnovnu i na bilo koju izvedenu klasu.

Razmotrimo primjer - listu koja sadrži i tačke i krugove.

// konstruktor

Stavka():info(NULL), sljedeća(NULL)()

Stavka(Tačka *p):info(p), sljedeća(NULL)()

Lista():glava(NULL)()

void insert(Tačka *p)(p->sljedeća = glava; glava = p;)

void List::print()

for(Item *cur = glava; cur; cur = cur->next)(

cur->info->print();

cout<< endl;

Korištenje klase:

Tačka *p = nova tačka(1,2);

mylist.insert(p);

p = novi ciklus(1,2,1);

mylist.insert(p);

Krug sa centrom u tački (1, 2) i poluprečnikom 1

Ovaj paragraf, uprkos svojoj sažetosti, veoma je važan - skoro sve profesionalno programiranje u Javi zasniva se na upotrebi polimorfizma. Istovremeno, studentima je ova tema jedna od najtežih za razumijevanje. Stoga se preporučuje da pažljivo pročitate ovaj odlomak nekoliko puta.

Metode klase su označene statičkim modifikatorom iz razloga - za njih, prilikom kompajliranja programskog koda, statičko povezivanje. To znači da se u kontekstu koje klase je ime metode naznačeno u izvornom kodu, postavlja veza na metodu te klase u prevedenom kodu. Odnosno, sprovodi se vezivanje naziva metode na mjestu poziva sa izvršnim kodom ovu metodu. Ponekad se naziva statičko povezivanje rano vezivanje, budući da se javlja u fazi kompilacije programa. Statičko vezivanje u Javi se koristi u još jednom slučaju - kada je klasa deklarirana sa finalnim modifikatorom (“final”, “final”),

Objektne metode u Javi su dinamičke, odnosno podložne su dinamičko povezivanje. Javlja se u fazi izvršavanja programa direktno tokom poziva metode, a u fazi pisanja ove metode nije unapred poznato iz koje klase će biti upućen poziv. Ovo je određeno tipom objekta za koji ovaj kod radi - kojoj klasi objekt pripada, iz koje klase se poziva metoda. Ovo vezivanje se javlja dugo nakon što je kod metode kompajliran. Stoga se ova vrsta vezivanja često naziva kasno uvezivanje.

Programski kod zasnovan na pozivanju dinamičkih metoda ima svojstvo polimorfizam– isti kod radi različito u zavisnosti od toga koji tip objekta ga zove, ali radi iste stvari na nivou apstrakcije u vezi sa izvornim kodom metode.

Da bismo objasnili ove riječi, koje na prvo čitanje nisu baš jasne, pogledajmo primjer iz prethodnog pasusa - rad metode moveTo. Neiskusni programeri smatraju da ovu metodu treba zaobići u svakoj klasi potomaka. Ovo se zapravo može uraditi i sve će raditi kako treba. Ali takav će kod biti izuzetno suvišan - na kraju krajeva, implementacija metode će biti potpuno ista u svim izvedenim klasama slike:

public void moveTo(int x, int y)(

Štaviše, ovaj slučaj ne koristi prednost polimorfizma. Tako da to nećemo učiniti.

Takođe je često zbunjujuće zašto implementaciju ove metode treba napisati u apstraktnoj klasi Figure. Na kraju krajeva, pozivi metodama skrivanja i prikazivanja koji se koriste u njemu, na prvi pogled bi trebali biti pozivi apstraktnim metodama - to jest, čini se da uopće ne mogu raditi!

Ali metode skrivanja i prikazivanja su dinamičke, što, kao što već znamo, znači da se povezivanje naziva metode i njenog izvršnog koda vrši u fazi izvršavanja programa. Stoga, činjenica da su ove metode specificirane u kontekstu klase Figure ne znači da će biti pozvane iz klase Figure! Štaviše, možete garantovati da metode skrivanja i prikazivanja nikada neće biti pozvane iz ove klase. Neka imamo varijable dot1 tipa Dot i circle1 tipa Circle, a dodijeljene su im veze prema objektima odgovarajućih tipova. Pogledajmo kako se ponašaju pozivi dot1.moveTo(x1,y1) i circle1.moveTo(x2,y2).

Kada se pozove dot1.moveTo(x1,y1), poziva se metoda moveTo iz klase Figure. Zaista, ova metoda u klasi Dot nije nadjačana, što znači da je naslijeđena od Figure. U metodi moveTo, prva naredba je poziv dinamičke metode skrivanja. Implementacija ove metode je preuzeta iz klase čiji je objekt dot1 koji poziva ovu metodu instanca. Odnosno, iz klase Dot. Dakle, poenta je skrivena. Zatim se mijenjaju koordinate objekta, nakon čega se poziva metoda dinamičkog prikaza. Implementacija ove metode je preuzeta iz klase čiji je objekt dot1 koji poziva ovu metodu instanca. Odnosno, iz klase Dot. Tako se na novoj lokaciji prikazuje tačka.

Za pozivanje circle1.moveTo(x2,y2) sve je apsolutno slično - dinamičke metode hide i show pozivaju se iz klase čiji je objekt circle1 instanca, odnosno iz klase Circle. Dakle, to je krug koji je skriven na starom mjestu i prikazan na novom.

To jest, ako je objekat tačka, tačka se pomera. A ako je predmet krug, krug se kreće. Štaviše, ako jednog dana neko napiše, na primer, klasu Ellipse koja je potomak Circle, i kreira objekat Ellipse ellipse=new Ellipse(...), tada će poziv ellipse.moveTo(...) pomeriti elipsu u nova lokacija. I to će se dogoditi u skladu s načinom na koji se metode skrivanja i prikazivanja implementiraju u klasi Ellipse. Imajte na umu da će polimorfni kod klase Figure koja je prevedena davno raditi. Polimorfizam je osiguran činjenicom da se reference na ove metode ne stavljaju u kod metode moveTo u vrijeme kompajliranja - one su konfigurirane za metode s takvim imenima iz klase objekta koji poziva odmah u trenutku kada se metoda moveTo poziva.

U objektno orijentisanim programskim jezicima postoje dvije vrste dinamičkih metoda – same dinamičke metode i virtuelno. Po principu rada potpuno su slični i razlikuju se samo po karakteristikama implementacije. Pozivanje virtuelnih metoda je brže. Pozivanje dinamičkih je sporije, ali tabela dinamičkih metoda (DMT) zauzima nešto manje memorije od tabele virtuelnih metoda (VMT).

Može se činiti da pozivanje dinamičkih metoda nije vremenski efikasno zbog dužine vremena potrebnog za traženje imena. U stvari, tokom poziva se ne vrši traženje imena, već se koristi mnogo brži mehanizam koristeći pomenutu tabelu virtuelnih (dinamičkih) metoda. Ali nećemo se zadržavati na specifičnostima implementacije ovih tabela, jer Java ne razlikuje ove vrste metoda.

Osnovna klasa Object

Klasa Object je osnovna klasa za sve Java klase. Stoga su sva njegova polja i metode naslijeđene i sadržane u svim klasama. Klasa Object sadrži sljedeće metode:

public Boolean jednak (Object obj)– vraća true u slučaju kada su vrijednosti objekta iz kojeg je metoda pozvana i objekta koji je prošao kroz obj referencu na listi parametara jednake. Ako objekti nisu jednaki, vraća se false. U klasi Object, jednakost se tretira kao referentna jednakost i ekvivalentna je operatoru poređenja “==”. Ali kod potomaka ova metoda se može nadjačati i može upoređivati ​​objekte po njihovom sadržaju. Na primjer, ovo se događa za objekte numeričkih klasa ljuske. Ovo se lako može provjeriti pomoću koda poput ovog:

Dvostruki d1=1,0,d2=1,0;

System.out.println("d1==d2 ="+(d1==d2));

System.out.println("d1.equals(d2) ="+(d1.equals(d2)));

Prvi red izlaza će dati d1==d2 =false, a drugi d1.equals(d2) =true

javni int hashCode()- pitanja hash code objekt. Haš kod je uslovno jedinstveni numerički identifikator povezan sa elementom. Iz sigurnosnih razloga, ne možete dati adresu objekta aplikacijskom programu. Stoga, u Javi, hash kod zamjenjuje adresu objekta u slučajevima kada je u neku svrhu potrebno pohraniti tablice adresa objekata.

protected Object clone() izbacuje CloneNotSupportedException– metoda kopira objekat i vraća vezu na kreirani klon (duplikat) objekta. U potomcima klase Object, potrebno ju je redefinisati, a takođe naznačiti da klasa implementira interfejs Clonable. Pokušaj pozivanja metode iz objekta koji ne podržava kloniranje uzrokuje izbacivanje CloneNotSupportedException. Interfejsi i situacije izuzetaka će biti razmotrene kasnije.

Postoje dvije vrste kloniranja: plitko (plitko), kada se vrijednosti polja originalnog objekta kopiraju jedan na jedan u klon, i duboko (duboko), u kojem se kreiraju novi objekti za polja referentni tip, kloniranje objekata na koje se originalna polja odnose. U plitkom kloniranju, i original i klon će referencirati iste objekte. Ako objekt ima polja samo primitivnih tipova, nema razlike između plitkog i dubokog kloniranja. Implementaciju kloniranja vrši programer koji razvija klasu, nema automatskog mehanizma za kloniranje. I u fazi razvoja klase trebate odlučiti koju opciju kloniranja odabrati. U velikoj većini slučajeva potrebno je duboko kloniranje.

javni završni razred getClass()– vraća referencu na metaobjekat klase tipa. Uz njegovu pomoć možete dobiti informacije o klasi kojoj objekt pripada i pozvati njegove metode klase i polja klase.

protected void finalize() baca Throwable– Poziva se prije nego se objekt uništi. Mora se nadjačati u onim potomcima Object-a u kojima je potrebno izvršiti neke pomoćne radnje prije uništavanja objekta (zatvoriti datoteku, prikazati poruku, nacrtati nešto na ekranu, itd.). Ova metoda je detaljnije opisana u odgovarajućem paragrafu.

javni niz toString()– vraća string reprezentaciju objekta (što je adekvatnije moguće). U klasi Object, ova metoda proizvodi niz potpuno kvalificiranog imena objekta (sa imenom paketa), nakon čega slijedi znak '@', a zatim heksadecimalni heš kod objekta. Većina standardnih klasa poništava ovu metodu. Za numeričke klase vraća se string reprezentacija broja, za string klase – sadržaj stringa, za klase znakova – sam karakter (a ne string reprezentacija njegovog koda!). Na primjer, sljedeći isječak koda

Object obj=new Object();

System.out.println(" obj.toString() daje "+obj.toString());

Double d=new Double(1.0);

System.out.println(" d.toString() daje "+d.toString());

Znak c="A";

System.out.println("c.toString() daje "+c.toString());

će dati zaključak

obj.toString() daje java.lang.Object@fa9cf

d.toString() daje 1.0

c.toString() daje A

Postoje i metode obavijesti(), obavijesti sve(), i nekoliko preopterećenih varijanti metode čekaj, dizajniran za rad sa nitima. O njima se govori u odjeljku o tokovima.


Povezane informacije.