Unutarnja nastava

P: Pa za što su uopće korisni unutarnji razredi?

O: Unutarnji razredi gnijezde se unutar ostalih razreda. Normalna klasa izravni je član paketa, klasa najviše razine. Unutarnji tečajevi, koji su postali dostupni s Javom 1.1, dolaze u četiri okusa:

  • Statičke klase članova
  • Članske klase
  • Lokalni razredi
  • Anonimni satovi

Kratko ćemo pogledati svaku po redu.

Ukratko, klasa statičkog člana je statički član klase. Kao i svaka druga statička metoda, i klasa statičkih članova ima pristup svim statičkim metodama nadređene ili najviše razine klase.

Poput statičke klase člana, i klasa člana je definirana kao član klase. Za razliku od statičke raznolikosti, klasa člana specifična je za instancu i ima pristup svim metodama i članovima, čak i roditeljskoj thisreferenci.

Lokalne klase su deklarirane unutar bloka koda i vidljive su samo unutar tog bloka, baš kao i bilo koja druga varijabla metode.

Napokon, anonimni razred je lokalni razred koji nema ime.

Da bih odgovorio na vaše konkretno pitanje, usredotočit ću se na članske i anonimne unutarnje razrede jer će se s njima vjerojatno susresti i koristiti. Po meni se prednosti unutarnjih klasa mogu podijeliti u tri kategorije: objektno orijentirana prednost, organizacijska prednost i prednost povratnog poziva.

Predmetno orijentirana prednost

Po mom skromnom mišljenju, najvažnija značajka unutarnje klase je da vam omogućuje pretvaranje stvari u predmete koje obično ne biste pretvorili u predmete. To omogućuje da vaš kôd bude još više objektno orijentiran nego što bi bio bez unutarnjih klasa.

Pogledajmo razred članova. Budući da je njegova instanca član nadređene instance, ona ima pristup svakom članu i metodi u nadređenoj. Na prvi pogled ovo se možda ne čini puno; već imamo takav pristup unutar metode u roditeljskoj klasi. Međutim, klasa članova omogućuje nam da izuzmemo logiku iz roditelja i objektiviziramo je. Na primjer, klasa stabla može imati metodu i mnoge pomoćne metode koje obavljaju pretragu ili šetnju stablom. S objektno orijentirane točke gledišta, stablo je stablo, a ne algoritam pretraživanja. Međutim, potrebno vam je blisko znanje o strukturi podataka stabla da biste izvršili pretragu.

Unutarnja klasa omogućuje nam uklanjanje te logike i stavljanje u vlastitu klasu. Dakle, s objektno orijentiranog gledišta izuzeli smo funkcionalnost tamo gdje ona ne pripada i stavili smo je u vlastitu klasu. Korištenjem unutarnje klase uspješno smo odvojili algoritam pretraživanja od stabla. Sada, da bismo promijenili algoritam pretraživanja, možemo jednostavno zamijeniti novu klasu. Mogao bih nastaviti, ali to otvara naš kôd mnogim prednostima koje pružaju objektno orijentirane tehnike.

Organizacijska prednost

Objektno orijentirani dizajn nije stvar svih, ali na sreću, unutarnja nastava pruža više. S organizacijskog stajališta, unutarnji tečajevi omogućuju nam daljnju organizaciju strukture paketa korištenjem prostora imena. Umjesto da se sve izbacuje u ravni paket, klase se mogu dalje ugnijezditi unutar klasa. Izričito, bez unutarnjih klasa, bili smo ograničeni na sljedeću hijerarhijsku strukturu:

paket1 klasa 1 klasa 2 ... klasa n ... paket n 

Unutarnjim tečajevima možemo učiniti sljedeće:

paket 1 klasa 1 klasa 2 klasa 1 klasa 2 ... klasa n 

Ako se pažljivo koriste, unutarnje klase mogu pružiti strukturnu hijerarhiju koja prirodnije odgovara vašim razredima.

Prednost povratnog poziva

Klase unutarnjih članova i anonimne klase pružaju prikladnu metodu za definiranje povratnih poziva. Najočitiji primjer odnosi se na GUI kod. Međutim, primjena povratnog poziva može se proširiti na mnoge domene.

Većina Java GUI-a ima neku vrstu komponente koja potiče actionPerformed()poziv metode. Nažalost, većina programera jednostavno ima svoj glavni prozor ActionListener. Kao rezultat, sve komponente dijele istu actionPerformed()metodu. Da bi se utvrdilo koja je komponenta izvršila radnju, u actionPerformed()metodi je obično div, ružan prekidač .

Evo primjera monolitne implementacije:

javna klasa SomeGUI proširuje JFrame implementira ActionListener {zaštićen JButton button1; zaštićeni gumb JButton2; ... zaštićeni gumb JButtonN; public void actionPerformed (ActionEvent e) {if (e.getSource () == button1) {// uradi nešto} drugo ako (e.getSource () == button2) {... dobijete sliku

Kad god vidite prekidače ili velike if/ if elseblokove, u vašem umu bi trebala zazvoniti glasna zvona alarma. Općenito, takvi su konstrukti loše objektno orijentirani dizajn, jer promjena u jednom odjeljku koda može zahtijevati odgovarajuću promjenu u naredbi prekidača. Klase unutarnjih članova i anonimne klase omogućuju nam da se maknemo od promijenjene actionPerformed()metode.

Umjesto toga, možemo definirati unutarnju klasu koja se implementira ActionListenerza svaku komponentu koju želimo slušati. To može rezultirati mnogim unutarnjim klasama. Međutim, možemo izbjeći velike izjave o prebacivanju i imati dodatni bonus u kapsuliranju naše akcijske logike. Štoviše, taj pristup može poboljšati izvedbu. U preklopniku gdje postoji n usporedbi, možemo očekivati n / 2 usporedbe u prosječnom slučaju. Unutarnji tečajevi omogućuju nam uspostavljanje korespondencije 1: 1 između izvođača i slušatelja radnje. U velikom GUI-u takve optimizacije mogu značajno utjecati na izvedbu. Anonimni pristup može izgledati ovako:

javna klasa SomeGUI proširuje JFrame {... deklaracije članova gumba ... zaštićena praznina buildGUI () {button1 = novi JButton (); button2 = novi JButton (); ... button1.addActionListener (new java.awt.event.ActionListener () {public void actionPerformed (java.awt.event.ActionEvent e) {// učiniti nešto}})); .. ponovite za svaki gumb

Koristeći klase unutarnjih članova, isti bi program izgledao ovako:

javna klasa SomeGUI proširuje JFrame {... deklaracije članova gumba // klase definicija unutarnje klase Button1Handler implementira ActionListener {public void actionPerformed (ActionEvent e) {// učini nešto}} ... definira klasu unutarnjeg člana za svaki gumb zaštićen void buildGUI () {// inicijalizira gumbe button1 = new JButton (); button2 = novi JButton (); ... // registriranje instance slušatelja radnje unutarnje klase // za svaki gumb button1.addActionListener (novi Button1Handler ()); .. ponovite za svaki gumb

Budući da unutarnje klase imaju pristup svemu u roditelju, možemo logiku koja bi se pojavila u monolitnoj actionPerformed()implementaciji premjestiti u unutarnju klasu.

Radije koristim klase članova kao povratne pozive. Međutim, to je stvar osobnih preferencija. Jednostavno osjećam da previše anonimnih satova pretrpa kod. Također smatram da anonimni razredi mogu postati nezgrapni ako su veći od jednog ili dva retka.

Mane?

Kao i u bilo čemu drugom, i dobro morate uzeti za loše. Unutarnji razredi imaju svoje nedostatke. S gledišta održavanja, neiskusni programeri Jave mogu smatrati da je unutarnja klasa teško razumljiva. Korištenje unutarnjih klasa također će povećati ukupan broj klasa u vašem kodu. Štoviše, s razvojnog gledišta, većina Java alata pomalo nedostaje u podršci unutarnjim klasama. Na primjer, koristim IBM VisualAge za Javu za svoje svakodnevno kodiranje. Iako će se unutarnje klase kompajlirati unutar VisualAgea, ne postoji preglednik ili predložak unutarnje klase. Umjesto toga, morate jednostavno upisati unutarnju klasu izravno u definiciju klase. To nažalost otežava pregledavanje unutarnje klase. Također je teško tipkati jer gubite mnogo VisualAgea 's pomaže u dovršenju koda kada upišete definiciju klase ili koristite unutarnju klasu.

Tony Sintes viši je savjetnik u ObjectWaveu, specijaliziran za telekomunikacije. Sintes, programer Java 1.1, programer i programer Java 2, certificiran za Sun, s Javom surađuje od 1997.

Saznajte više o ovoj temi

  • "Specifikacija internih klasa" tvrtke Sun pruža detaljan uvid u unutarnje klase

    //java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html

Ovu priču, "Unutarnji razredi" izvorno je objavio JavaWorld.