Programmering

Statiske klasser og indre klasser i Java

Nestede klasser er klasser som blir erklært som medlemmer av andre klasser eller omfang. Nestende klasser er en måte å bedre organisere koden din. Si for eksempel at du har en klasse som ikke er nestet (også kjent som en toppklasse) som lagrer objekter i en størrelse som kan endres, etterfulgt av en iteratorklasse som returnerer hvert objekt. I stedet for å forurense toppnivåens klasserom, kan du erklære klassen iterator som medlem av den størrelsesbestemte gruppesamlingsklassen. Dette fungerer fordi de to er nært beslektede.

I Java er nestede klasser kategorisert som en av dem statiske medlemsklasser eller indre klasser. Indre klasser er ikke-statiske medlemsklasser, lokale klasser eller anonyme klasser. I denne opplæringen lærer du hvordan du arbeider med statiske medlemsklasser og de tre typer indre klasser i Java-koden din.

Unngå minnelekkasjer i nestede klasser

Se også Java-tipset som er knyttet til denne opplæringen, der du får vite hvorfor nestede klasser er sårbare for minnelekkasjer.

Statiske klasser i Java

I min Java 101 tutorial Klasser og objekter i Java, lærte du hvordan du kan erklære statiske felt og statiske metoder som medlemmer av en klasse. I klasse- og objektinitialisering i Java lærte du hvordan du kan erklære statiske initialiserere som medlemmer av en klasse. Nå lærer du å erklære statiske klasser. Formelt kjent som statiske medlemsklasser, dette er nestede klasser som du erklærer på samme nivå som disse andre statiske enhetene, ved hjelp av statisk nøkkelord. Her er et eksempel på en statisk erklæring om medlemsklasse:

 klasse C {statisk int f; statisk tomrom m () {} statisk {f = 2; } statisk klasse D {// medlemmer}} 

Dette eksemplet introduserer toppnivåklasse C med statisk felt f, statisk metode m (), en statisk initialisering og statisk medlemsklasse D. Legg merke til det D er medlem av C. Det statiske feltet f, statisk metode m (), og den statiske initialisereren er også medlemmer av C. Siden alle disse elementene tilhører klassen C, det er kjent som omsluttende klasse. Klasse D er kjent som lukket klasse.

Regler for innhegning og tilgang

Selv om den er vedlagt, kan en statisk medlemsklasse ikke få tilgang til klassens forekomstfelt og påkalle forekomstmetodene. Imidlertid kan den få tilgang til den omsluttende klassens statiske felt og påberope seg de statiske metodene, til og med de medlemmene som blir erklært privat. For å demonstrere erklærer Oppføring 1 en Omsluttende klasse med en nestet SMClass.

Oppføring 1. Erklære en statisk medlemsklasse (EnclosingClass.java, versjon 1)

 klasse EnclosingClass {privat statisk streng s; privat statisk tomrom m1 () {System.out.println (s); } statisk tomrom m2 () {SMClass.accessEnclosingClass (); } static class SMClass {static void accessEnclosingClass () {s = "Called from SMClass's accessEnclosingClass () method"; m1 (); } ugyldig tilgangEnclosingClass2 () {m2 (); }}} 

Oppføring 1 erklærer en klasse på toppnivå som heter Omsluttende klasse med klassefelt s, klassemetoder m1 () og m2 (), og statisk medlemsklasse SMClass. SMClass erklærer klassemetode accessEnclosingClass () og instansemetode accessEnclosingClass2 (). Legg merke til følgende:

  • m2 ()påkalling av SMClasss accessEnclosingClass () metoden krever SMClass. prefikset fordi accessEnclosingClass () blir erklært statisk.
  • accessEnclosingClass () er i stand til å få tilgang Omsluttende klasses s feltet og kaller det m1 () metoden, selv om begge er erklært privat.

Oppføring 2 presenterer kildekoden til en SMCDemo applikasjonsklasse som demonstrerer hvordan man kan påberope seg SMClasss accessEnclosingClass () metode. Det demonstrerer også hvordan man kan instantiere SMClass og påkalle sin accessEnclosingClass2 () eksempel metode.

Oppføring 2. Påkalle metoder for en statisk medlemsklasse (SMCDemo.java)

 public class SMCDemo {public static void main (String [] args) {EnclosingClass.SMClass.accessEnclosingClass (); EnclosingClass.SMClass smc = ny EnclosingClass.SMClass (); smc.accessEnclosingClass2 (); }} 

Som vist i oppføring 2, hvis du vil påkalle en toppklasses metode fra en lukket klasse, må du foran den vedlagte klassens navn med navnet på den vedlagte klassen. For å starte en lukket klasse må du også foran navnet på den klassen med navnet på den lukkende klassen. Du kan deretter påberope forekomstmetoden på vanlig måte.

Sett sammen liste 1 og 2 som følger:

 javac * .java 

Når du kompilerer en omsluttende klasse som inneholder en statisk medlemsklasse, oppretter kompilatoren en klassefil for den statiske medlemsklassen hvis navn består av den vedlagte klassens navn, et dollartegnetegn og navnet på den statiske medlemsklassen. I dette tilfellet resulterer kompilering i EnclosingClass $ SMCClass.class og EnclosingClass.class.

Kjør applikasjonen som følger:

 java SMCDemo 

Du bør følge følgende utdata:

 Kalt fra SMClass's accessEnclosingClass () -metode Kalles fra SMClass's accessEnclosingClass () -metode 

Eksempel: Statiske klasser og Java 2D

Java-er standard klassebibliotek er et kjøretidsbibliotek med klassefiler som lagrer kompilerte klasser og andre referansetyper. Biblioteket inneholder mange eksempler på statiske medlemsklasser, hvorav noen finnes i Java 2D geometriske formklasser som ligger i java.awt.geom pakke. (Du lærer om pakker i det neste Java 101 opplæringen.)

De Ellipse2D klasse funnet i java.awt.geom beskriver en ellipse, som er definert av et innrammende rektangel i form av et (x, y) øvre venstre hjørne sammen med bredde og høyde. Det følgende kodefragmentet viser at denne klassens arkitektur er basert på Flyte og Dobbelt statiske medlemsklasser, som begge underklasser Ellipse2D:

 offentlig abstrakt klasse Ellipse2D utvider RectangularShape {offentlig statisk klasse Float utvider Ellipse2D implementerer Serialiserbar {offentlig float x, y, bredde, høyde; public Float () {} public Float (float x, float y, float w, float h) {setFrame (x, y, w, h); } offentlig dobbel getX () {retur (dobbel) x; } // tilleggsforekomstmetoder} offentlig statisk klasse Dobbelt utvider Ellipse2D implementerer Serialiserbar {offentlig dobbel x, y, bredde, høyde; public Double () {} public Double (double x, double y, double w, double h) {setFrame (x, y, w, h); } offentlig dobbel getX () {return x; } // tilleggsforekomstmetoder} offentlig boolsk inneholder (dobbelt x, dobbelt y) {// ...} // tilleggs instansmetoder delt av Float, Double og andre // Ellipse2D-underklasser} 

De Flyte og Dobbelt klasser utvide Ellipse2D, som gir flytende punkt og dobbelt presisjon flytende punkt Ellipse2D implementeringer. Utviklere bruker Flyte for å redusere minneforbruket, spesielt fordi du kanskje trenger tusenvis eller flere av disse objektene for å konstruere en enkelt 2D-scene. Vi bruker Dobbelt når større nøyaktighet er nødvendig.

Du kan ikke instantiere det abstrakte Ellipse2D klasse, men du kan instantiere heller Flyte eller Dobbelt. Du kan også utvide Ellipse2D for å beskrive en tilpasset form som er basert på en ellipse.

La oss som et eksempel si at du vil introdusere en Circle2D klasse, som ikke er tilstede i java.awt.geom pakke. Følgende kodefragment viser hvordan du vil lage et Ellipse2D objekt med flytende punktimplementering:

 Ellipse2D e2d = ny Ellipse2D.Float (10.0f, 10.0f, 20.0f, 30.0f); 

Neste kodefragment viser hvordan du vil lage et Ellipse2D objekt med en dobbel presisjon implementering av flytende punkt:

 Ellipse2D e2d = ny Ellipse2D.Double (10.0, 10.0, 20.0, 30.0); 

Du kan nå påberope deg hvilken som helst av metodene som er angitt i Flyte eller Dobbelt ved å påkalle metoden på den returnerte Ellipse2D referanse (f.eks. e2d.getX ()). På samme måte kan du påberope deg hvilken som helst av metodene som er felles for Flyte og Dobbelt, og som er erklært i Ellipse2D. Et eksempel er:

 e2d.contains (2.0, 3.0) 

Det fullfører introduksjonen til statiske medlemsklasser. Deretter ser vi på indre klasser, som er ikke-statiske medlemsklasser, lokale klasser eller anonyme klasser. Du lærer hvordan du kan jobbe med alle tre typer indre klasser.

last ned Få koden Last ned kildekoden for eksempler i denne veiledningen. Skapt av Jeff Friesen for JavaWorld.

Indre klasser, type 1: Ikke-statiske medlemsklasser

Du har lært tidligere i Java 101 serier hvordan man kan erklære ikke-statiske (forekomst) felt, metoder og konstruktører som medlemmer av en klasse. Du kan også erklære ikke-statiske medlemsklasser, som er nestede ikke-statiske klasser som du erklærer på samme nivå som forekomstfelt, metoder og konstruktører. Tenk på dette eksemplet:

 klasse C {int f; ugyldig m () {} C () {f = 2; } klasse D {// medlemmer}} 

Her introduserer vi toppklasse C med forekomstfelt f, eksempel metode m (), en konstruktør og ikke-statisk medlemsklasse D. Alle disse enhetene er medlemmer av klassen C, som omslutter dem. Imidlertid, i motsetning til i forrige eksempel, er disse instansene tilknyttet forekomster avC og ikke med C klassen selv.

Hver forekomst av den ikke-statiske medlemsklassen er implisitt assosiert med en forekomst av den omsluttende klassen. Den ikke-statiske medlemsklassens forekomstmetoder kan ringe den vedlagte klassens forekomstmetoder og få tilgang til forekomstfeltene. For å demonstrere denne tilgangen erklærer Listing 3 en Omsluttende klasse med en nestet NSMClass.

Oppføring 3. Erklære en omslutningsklasse med en nestet ikke-statisk medlemsklasse (EnclosingClass.java, versjon 2)

 class EnclosingClass {private String s; privat tomrom m () {System.out.println (s); } class NSMClass {void accessEnclosingClass () {s = "Called from NSMClass's accessEnclosingClass () method"; m (); }}} 

Oppføring 3 erklærer en toppklasse som heter Omsluttende klasse med forekomstfelt s, eksempel metode m (), og ikke-statisk medlemsklasse NSMClass. Dessuten, NSMClass erklærer forekomstmetode accessEnclosingClass ().

Fordi accessEnclosingClass () er ikke-statisk, NSMClass må instansieres før denne metoden kan kalles. Denne instantiseringen må skje via en forekomst av Omsluttende klasse, som vist i oppføring 4.

Oppføring 4. NSMCDemo.java

 public class NSMCDemo {public static void main (String [] args) {EnclosingClass ec = new EnclosingClass (); ec.new NSMClass (). accessEnclosingClass (); }} 

Oppføring 4-er hoved() metoden starter umiddelbart Omsluttende klasse og lagrer referansen i lokal variabel ec. De hoved() metoden bruker deretter Omsluttende klasse referanse som et prefiks til ny operatøren, for å instansiere NSMClass. De NSMClass referanse blir deretter brukt til å ringe accessEnclosingClass ().

Bør jeg bruke 'nytt' med referanse til den vedlagte klassen?

Prefiksering ny med en referanse til den vedlagte klassen er sjelden. I stedet vil du vanligvis ringe en lukket klasses konstruktør fra en konstruktør eller en instansemetode i den vedlagte klassen.

Sett sammen liste 3 og 4 som følger:

 javac * .java 

Når du kompilerer en omsluttende klasse som inneholder en ikke-statisk medlemsklasse, oppretter kompilatoren en klassefil for den ikke-statiske medlemsklassen hvis navn består av den vedlagte klassenavnet, et dollartegnetegn og den ikke-statiske medlemsklassen Navn. I dette tilfellet resulterer kompilering i EnclosingClass $ NSMCClass.class og EnclosingClass.class.

Kjør applikasjonen som følger:

 java NSMCDemo 

Du bør følge følgende utdata:

 Kalt fra NSMClasss tilgangEnclosingClass () -metode 

Når (og hvordan) å kvalifisere 'dette'

En lukket klasses kode kan få en referanse til sin innelukkende klasse forekomst ved å kvalifisere reservert ord dette med klassenes navn og medlemstilgangsoperatøren (.). For eksempel hvis kode i accessEnclosingClass () nødvendig for å få en referanse til dens Omsluttende klasse eksempel, vil det spesifisere EnclosingClass.this. Fordi kompilatoren genererer kode for å utføre denne oppgaven, er det sjelden å spesifisere dette prefikset.

Eksempel: Ikke-statiske medlemsklasser i HashMap

Standardklassebiblioteket inkluderer ikke-statiske medlemsklasser så vel som statiske medlemsklasser. For dette eksemplet ser vi på HashMap klasse, som er en del av Java Collections Framework i java.util pakke. HashMap, som beskriver en hash-tabellbasert implementering av et kart, inkluderer flere ikke-statiske medlemsklasser.

For eksempel KeySet ikke-statisk medlemsklasse beskriver en settbasert utsikt av nøklene i kartet. Følgende kodefragment relaterer det vedlagte KeySet klasse til sin HashMap inngående klasse:

 offentlig klasse HashMap utvider AbstractMap implementerer Map, Cloneable, Serializable {// diverse medlemmer sluttklasse KeySet utvider AbstractSet {// forskjellige medlemmer} // forskjellige medlemmer} 

De og syntakser er eksempler på generiske legemidler, en serie relaterte språkfunksjoner som hjelper kompilatoren med å håndheve typesikkerhet. Jeg introduserer generiske legemidler i en kommende Java 101 opplæringen. Foreløpig trenger du bare å vite at disse syntaksen hjelper kompilatoren med å håndheve typen nøkkelobjekter som kan lagres på kartet og i tastesettet, og typen verdiobjekter som kan lagres på kartet.

HashMap gir en keySet () metode som instantierer KeySet når det er nødvendig, og returnerer denne forekomsten eller en hurtigbufret forekomst. Her er den komplette metoden:

$config[zx-auto] not found$config[zx-overlay] not found