Sisäkkäiset luokat ovat luokkia, jotka ilmoitetaan muiden luokkien tai laajuuksien jäseniksi. Luokkien pesiminen on yksi tapa järjestää koodisi paremmin. Oletetaan esimerkiksi, että sinulla on ei-sisäkkäinen luokka (tunnetaan myös nimellä a huippuluokan), joka tallentaa objektit kooltaan muutettavissa olevaan ryhmään, jota seuraa iteraattoriluokka, joka palauttaa jokaisen objektin. Sen sijaan, että saastuttaisi ylätason luokan nimitilaa, voit julistaa iteraattoriluokan kooltaan muutettavan taulukkorakenneluokan jäseneksi. Tämä toimii, koska nämä kaksi liittyvät läheisesti toisiinsa.
Java-tilassa sisäkkäiset luokat luokitellaan joko staattiset jäsenluokat tai sisäiset luokat. Sisäiset luokat ovat ei-staattisia jäsenkursseja, paikallisia kursseja tai nimettömiä luokkia. Tässä opetusohjelmassa opit työskentelemään staattisten jäsenluokkien ja kolmen tyyppisen sisäisen luokan kanssa Java-koodissasi.
Vältä muistivuotoja sisäkkäisissä luokissa
Katso myös tähän opetusohjelmaan liittyvä Java-vinkki, jossa opit, miksi sisäkkäiset luokat ovat alttiita muistivuodoille.
Staattiset luokat Java-kielellä
Minussa Java 101 opetusohjelma Luokat ja Java-objektit, opit ilmoittamaan staattiset kentät ja staattiset menetelmät luokan jäseniksi. Jaavan luokan ja objektien alustuksessa opit ilmoittamaan staattiset alustusohjelmat luokan jäseniksi. Nyt opit ilmoittamaan staattiset luokat. Tunnetaan virallisesti nimellä staattiset jäsenluokat, nämä ovat sisäkkäisiä luokkia, jotka ilmoitat samalla tasolla kuin nämä muut staattiset entiteetit staattinen
avainsana. Tässä on esimerkki staattisen jäsenluokan ilmoituksesta:
luokka C {staattinen int f; staattinen void m () {} staattinen {f = 2; } staattinen luokka D {// jäsenet}}
Tämä esimerkki esittelee ylätason luokan C
staattisella kentällä f
, staattinen menetelmä m ()
, staattinen alustus ja staattinen jäsenluokka D.
. Huomaa, että D.
on jäsenenä C
. Staattinen kenttä f
, staattinen menetelmä m ()
, ja staattinen alustus ovat myös ryhmän jäseniä C
. Koska kaikki nämä elementit kuuluvat luokkaan C
, se tunnetaan nimellä sulkeva luokka. Luokka D.
tunnetaan nimellä suljettu luokka.
Kotelointi ja pääsyn säännöt
Vaikka se on suljettu, staattinen jäsenluokka ei voi käyttää sulkevan luokan ilmentymäkenttiä ja käyttää sen ilmentymämenetelmiä. Se voi kuitenkin käyttää ympäröivän luokan staattisia kenttiä ja käyttää sen staattisia menetelmiä, jopa ilmoitetut jäsenet yksityinen
. Osoituksena luettelo 1 ilmoittaa Kotelointiluokka
sisäkkäin SM-luokka
.
Listaus 1. Staattisen jäsenluokan ilmoittaminen (EnclosingClass.java, versio 1)
luokka EnclosingClass {private static String s; yksityinen staattinen void m1 () {System.out.println (s); } staattinen void m2 () {SMClass.accessEnclosingClass (); } staattinen luokka SMClass {static void accessEnclosingClass () {s = "Soitettu SMClassin accessEnclosingClass () -metodista"; m1 (); } void accessEnclosingClass2 () {m2 (); }}}
Listaus 1 julistaa ylätason luokan nimeltä Kotelointiluokka
luokan kentällä s
, luokan menetelmät m1 ()
ja m2 ()
ja staattinen jäsenluokka SM-luokka
. SM-luokka
julistaa luokan menetelmän accessEnclosingClass ()
ja instanssimenetelmä accessEnclosingClass2 ()
. Huomaa seuraava:
m2 ()
kutsui käyttäjänSM-luokka
onaccessEnclosingClass ()
menetelmä edellyttääSM-luokka.
etuliite koskaaccessEnclosingClass ()
ilmoitetaanstaattinen
.accessEnclosingClass ()
pääsee käsiksiKotelointiluokka
ons
kenttä ja soita senm1 ()
menetelmä, vaikka molemmat on ilmoitettuyksityinen
.
Listaus 2 näyttää lähdekoodin SMCDemo
sovellusluokka, joka osoittaa, kuinka kutsua SM-luokka
on accessEnclosingClass ()
menetelmä. Se osoittaa myös kuinka instantisoida SM-luokka
ja vedota sen accessEnclosingClass2 ()
instanssimenetelmä.
Listaus 2. Staattisen jäsenluokan menetelmien kutsuminen (SMCDemo.java)
public class SMCDemo {public static void main (String [] args) {EnclosingClass.SMClass.accessEnclosingClass (); EnclosingClass.SMClass smc = uusi EnclosingClass.SMClass (); smc.accessEnclosingClass2 (); }}
Kuten luettelossa 2 on esitetty, jos haluat käyttää ylätason luokan menetelmää suljetun luokan sisällä, sinun on etuliitettävä suljetun luokan nimi sen sulkevan luokan nimellä. Samoin suljetun luokan luomiseksi sinun on etuliitettävä kyseisen luokan nimi sen sulkevan luokan nimellä. Tämän jälkeen voit käyttää instanssimenetelmää normaalilla tavalla.
Kokoa luettelot 1 ja 2 seuraavasti:
javac * .java
Kun käännät liitettävän luokan, joka sisältää staattisen jäsenluokan, kääntäjä luo luokkatiedoston staattiselle jäsenluokalle, jonka nimi koostuu sen sulkevan luokan nimestä, dollarin merkki-merkistä ja staattisen jäsenluokan nimestä. Tässä tapauksessa tulosten kokoaminen EnclosingClass $ SMCClass.class
ja EnclosingClass.class
.
Suorita sovellus seuraavasti:
java SMCDemo
Ota huomioon seuraava tulos:
Soitettu SMClassin accessEnclosingClass () -menetelmästä Soitettu SMClassin accessEnclosingClass () -menetelmästä
Esimerkki: Staattiset luokat ja Java 2D
Java tavallinen luokan kirjasto on ajonaikainen luokkatiedostojen kirjasto, joka tallentaa kootut luokat ja muut viitetyypit. Kirjasto sisältää lukuisia esimerkkejä staattisista jäsenluokista, joista osa löytyy Java 2D: n geometrisista muotoluokista java.awt.geom
paketti. (Opit paketeista seuraavassa Java 101 opetusohjelma.)
Ellipse2D
luokka löytyi java.awt.geom
kuvaa ellipsin, jonka rajaa suorakulmio (x, y) vasemmassa yläkulmassa yhdessä leveyden ja korkeuden ulottuvuuksien kanssa. Seuraava koodinpätkä osoittaa, että tämän luokan arkkitehtuuri perustuu Kellua
ja Kaksinkertainen
staattiset jäsenluokat, jotka molemmat alaluokka Ellipse2D
:
julkinen abstrakti luokka Ellipse2D ulottuu RectangularShape {julkinen staattinen luokka Float jatkuu Ellipse2D toteuttaa sarjallisilla {julkinen kelluva x, y, leveys, korkeus; public Float () {} public Float (float x, float y, float w, float h) {setFrame (x, y, w, h); } public double getX () {return (double) x; } // ylimääräisiä instanssimenetelmiä} julkinen staattinen luokka Tuplalaajennus laajentaa Ellipse2D-työkalua Serialisoitava {julkinen kaksinkertainen x, y, leveys, korkeus; public Double () {} public Double (double x, double y, double w, double h) {setFrame (x, y, w, h); } public double getX () {return x; } // ylimääräiset instanssimenetelmät} julkinen totuusarvo sisältää (double x, double y) {// ...} // Float-, Double- ja muiden // Ellipse2D-alaluokkien jakamat lisätilamenetelmät}
Kellua
ja Kaksinkertainen
luokat jatkuvat Ellipse2D
, joka tarjoaa kelluvan pisteen ja kaksinkertaisen tarkkuuden kelluvan pisteen Ellipse2D
toteutukset. Kehittäjät käyttävät Kellua
vähentää muistin kulutusta, varsinkin kun tarvitset tuhansia tai enemmän näitä objekteja yhden 2D-kohtauksen rakentamiseen. Käytämme Kaksinkertainen
kun vaaditaan suurempaa tarkkuutta.
Et voi instantisoida abstraktia Ellipse2D
luokka, mutta voit myös joko Kellua
tai Kaksinkertainen
. Voit myös laajentaa Ellipse2D
kuvaamaan mukautettua muotoa, joka perustuu ellipsiin.
Oletetaan esimerkiksi, että haluat esitellä a Ympyrä2D
luokka, jota ei ole läsnä java.awt.geom
paketti. Seuraava koodinpätkä näyttää kuinka luodaan Ellipse2D
objekti, jossa on liukuluku-toteutus:
Ellipse2D e2d = uusi Ellipse2D.Float (10,0f, 10,0f, 20,0f, 30,0f);
Seuraava koodinpätkä näyttää kuinka luodaan Ellipse2D
objekti, jossa on kaksitarkka liukulukutoteutus:
Ellipse2D e2d = uusi Ellipse2D.Double (10,0, 10,0, 20,0, 30,0);
Voit nyt vedota mihin tahansa menetelmässä ilmoitettuun Kellua
tai Kaksinkertainen
kutsumalla palautetun menetelmän Ellipse2D
viite (esim. e2d.getX ()
). Samalla tavalla voit käyttää mitä tahansa tavallista menetelmää Kellua
ja Kaksinkertainen
, ja jotka ilmoitetaan Ellipse2D
. Esimerkiksi:
e2d. sisältää (2.0, 3.0)
Se täydentää staattisten jäsenluokkien johdannon. Seuraavaksi tarkastelemme sisäisiä luokkia, jotka ovat ei-staattisia jäsenluokkia, paikallisia luokkia tai nimettömiä luokkia. Opit työskentelemään kaikkien kolmen sisäisen luokan tyypin kanssa.
lataa Hanki koodi Lataa lähdekoodi esimerkkejä tästä opetusohjelmasta. Luonut Jeff Friesen JavaWorldille.Sisäluokat, tyyppi 1: Ei-staattiset jäsenluokat
Olet oppinut aiemmin Java 101 sarja kuinka julistaa ei-staattiset (esiintymä) kentät, menetelmät ja konstruktorit luokan jäseniksi. Voit myös ilmoittaa ei-staattiset jäsenluokat, jotka ovat sisäkkäisiä ei-staattisia luokkia, jotka ilmoitat samalla tasolla kuin instanssikentät, -menetelmät ja -rakentajat. Harkitse tätä esimerkkiä:
luokka C {int f; mitätön m () {} C () {f = 2; } luokka D {// jäsenet}}
Tässä esitellään huipputason luokka C
instanssikentän kanssa f
, esimerkkimenetelmä m ()
, konstruktori ja ei-staattinen jäsenluokka D.
. Kaikki nämä entiteetit ovat luokan jäseniä C
, joka sulkee ne. Toisin kuin edellisessä esimerkissä, nämä ilmentymäkokonaisuudet liittyvät tapauksiaC
eikä C
luokka itse.
Jokainen ei-staattisen jäsenluokan esiintymä liittyy implisiittisesti sen sulkevan luokan esiintymään. Ei-staattisen jäsenluokan ilmentymämenetelmät voivat kutsua sulkevan luokan ilmentymämenetelmiä ja käyttää sen ilmentymäkenttiä. Tämän pääsyn osoittamiseksi luettelo 3 ilmoittaa Kotelointiluokka
sisäkkäin NSMClass
.
Listaus 3. Ilmoita suljettu luokka sisäkkäin olevalla ei-staattisella jäsenluokalla (EnclosingClass.java, versio 2)
luokka EnclosingClass {private String s; private void m () {System.out.println (s); } luokka NSMClass {void accessEnclosingClass () {s = "Soitettu NSMClassin accessEnclosingClass () -metodista"; m (); }}}
Listaus 3 julistaa ylätason luokan nimeltä Kotelointiluokka
instanssikentän kanssa s
, esimerkkimenetelmä m ()
ja ei-staattinen jäsenluokka NSMClass
. Lisäksi, NSMClass
julistaa instanssimenetelmän accessEnclosingClass ()
.
Koska accessEnclosingClass ()
on ei-staattinen, NSMClass
täytyy instantisoida ennen kuin tätä menetelmää voidaan käyttää. Tämän instantisoinnin on tapahduttava Kotelointiluokka
, kuten luettelossa 4 on esitetty.
Listaus 4. NSMCDemo.java
public class NSMCDemo {public static void main (String [] args) {EnclosingClass ec = uusi EnclosingClass (); ec.uusi NSMClass (). accessEnclosingClass (); }}
Listaus 4: stä main ()
menetelmä ensin ilmentää Kotelointiluokka
ja tallentaa viitteensä paikalliseen muuttujaan ec
. main ()
menetelmä käyttää sitten Kotelointiluokka
viite etuliitteenä Uusi
operaattorin kanssa, jotta se voi toimia heti NSMClass
. NSMClass
viittausta käytetään sitten soittamiseen accessEnclosingClass ()
.
Pitäisikö minun käyttää sanaa 'uusi' viittaamalla oheiseen luokkaan?
Etuliite Uusi
viitaten sulkevaan luokkaan on harvinaista. Sen sijaan soitat tyypillisesti suljetun luokan konstruktorille konstruktorista tai sen sulkuluokan instanssimenetelmästä.
Kokoa luettelot 3 ja 4 seuraavasti:
javac * .java
Kun käännät suljettavaa luokkaa, joka sisältää ei-staattisen jäsenluokan, kääntäjä luo luokkatiedoston ei-staattiselle jäsenluokalle, jonka nimi koostuu sen sulkevan luokan nimestä, dollarin merkki-merkistä ja ei-staattisesta jäsenluokasta nimi. Tässä tapauksessa tulosten kokoaminen EnclosingClass $ NSMCClass.class
ja EnclosingClass.class
.
Suorita sovellus seuraavasti:
java NSMCDemo
Ota huomioon seuraava tulos:
Soitettu NSMClassin accessEnclosingClass () -menetelmästä
Milloin (ja miten) saada tämä
Suljetun luokan koodi voi saada viittauksen sen sulkevan luokan esiintymään kvalifioimalla varatun sanan Tämä
mukana olevan luokan nimen ja jäsenen käyttöoperaattorin (.
). Esimerkiksi, jos koodi sisällä accessEnclosingClass ()
tarvitaan viittauksen saamiseen Kotelointiluokka
esimerkiksi se täsmentäisi EnclosingClass. Tämä
. Koska kääntäjä luo koodin tämän tehtävän suorittamiseksi, tämän etuliitteen määrittäminen on harvinaista.
Esimerkki: Ei-staattiset jäsenluokat HashMapissa
Vakioluokakirjasto sisältää ei-staattiset jäsenluokat sekä staattiset jäsenluokat. Tässä esimerkissä tarkastellaan HashMap
luokka, joka on osa Java Collections Frameworkia java.util
paketti. HashMap
, joka kuvaa kartan hash-taulukkopohjaista toteutusta, sisältää useita ei-staattisia jäsenluokkia.
Esimerkiksi KeySet
ei-staattinen jäsenluokka kuvaa joukkoa näkymä kartan sisältämistä avaimista. Seuraava koodi katkaisee liitteen KeySet
luokka sen HashMap
sulkuluokka:
julkinen luokka HashMap laajentaa AbstractMap-sovellusta Map, Cloneable, Serializable {// eri jäsenten lopullinen luokka KeySet laajentaa AbstractSet {// eri jäsenet} // eri jäsenet}
ja
syntaksit ovat esimerkkejä geneeriset lääkkeet, sarja asiaankuuluvia kieliominaisuuksia, jotka auttavat kääntäjää valvomaan tyyppiturvallisuutta. Esittelen geneeriset tuotteet tulevassa Java 101 opetusohjelma. Toistaiseksi sinun tarvitsee vain tietää, että nämä syntaksit auttavat kääntäjää toteuttamaan kartalle ja näppäimistöön tallennettavien avainobjektien tyypin ja kartalle tallennettavien arvo-objektien tyypin.
HashMap
tarjoaa a keySet ()
menetelmä, joka ilmentää KeySet
tarvittaessa ja palauttaa tämän tai välimuistissa olevan ilmentymän. Tässä on täydellinen menetelmä: