Programmering

Initiering av klasse og objekt i Java

Klasser og objekter i Java må initialiseres før de brukes. Du har tidligere lært at klassefelt initialiseres til standardverdier når klasser lastes inn og at objekter initialiseres via konstruktører, men initialisering er mer. Denne artikkelen introduserer alle Java-funksjonene for initialisering av klasser og objekter.

last ned Få koden Last ned kildekoden for eksempel applikasjoner i denne opplæringen. Skapt av Jeff Friesen for JavaWorld.

Hvordan initialisere en Java-klasse

Før vi utforsker Java's støtte for klasseinitialisering, la oss oppsummere trinnene for initialisering av Java-klasse. Vurder oppføring 1.

Oppføring 1. Initialisering av klassefelt til standardverdier

klasse SomeClass {statisk boolsk b; statisk byte av; statisk røye c; statisk dobbel d; statisk flottør f; statisk int i; statisk lang l; statisk kort s; statisk streng; }

Oppføring 1 erklærer klasse SomeClass. Denne klassen erklærer ni felt av typer boolsk, byte, røye, dobbelt, flyte, int, lang, kort, og String. Når SomeClass er lastet, blir hvert felt bit satt til null, som du tolker som følger:

usant 0 \ u0000 0,0 0,0 0 0 0 null

De forrige klassefeltene ble implisitt initialisert til null. Du kan imidlertid også eksplisitt initialisere klassefelt ved å tilordne verdier direkte til dem, som vist i oppføring 2.

Oppføring 2. Initialisering av klassefelt til eksplisitte verdier

klasse SomeClass {statisk boolsk b = sann; statisk byte av = 1; statisk røye c = 'A'; statisk dobbel d = 2,0; statisk flottør f = 3.0f; statisk int i = 4; statisk lang l = 5000000000L; statisk kort s = 20000; statisk streng st = "abc"; }

Hver oppgaves verdi må være typekompatibel med klassefeltets type. Hver variabel lagrer verdien direkte, med unntak av St.. Variabel St. lagrer en referanse til en String objekt som inneholder abc.

Henviser til klassefelt

Når du initialiserer et klassefelt, er det lovlig å initialisere det til verdien av et tidligere initialisert klassefelt. For eksempel initialiserer Listing 3 y til xverdi. Begge feltene er initialisert til 2.

Oppføring 3. Henvisning til et tidligere erklært felt

klasse SomeClass {statisk int x = 2; statisk int y = x; public static void main (String [] args) {System.out.println (x); System.out.println (y); }}

Det motsatte er imidlertid ikke lovlig: du kan ikke initialisere et klassefelt til verdien av et senere deklarert klassefelt. Java-kompilatorutgangene ulovlig fremoverhenvisning når det møter dette scenariet. Vurder oppføring 4.

Oppføring 4. Forsøk på å referere til et senere deklarert felt

klasse SomeClass {statisk int x = y; statisk int y = 2; public static void main (String [] args) {System.out.println (x); System.out.println (y); }}

Kompilatoren vil rapportere ulovlig fremoverhenvisning når den møter statisk int x = y;. Dette er fordi kildekoden er samlet ovenfra og ned, og kompilatoren ennå ikke har sett y. (Det vil også sende denne meldingen hvis y ble ikke eksplisitt initialisert.)

Initialiseringsblokker for klasse

I noen tilfeller vil du kanskje utføre komplekse klassebaserte initialiseringer. Du vil gjøre dette etter at en klasse er lastet og før noen objekter blir opprettet fra den klassen (forutsatt at klassen ikke er en verktøyklasse). Du kan bruke en klasseinitialiseringsblokk for denne oppgaven.

EN klasse initialiseringsblokk er en blokk med utsagn foran statisk nøkkelord som er introdusert i klassens kropp. Når klassen lastes inn, blir disse utsagnene utført. Vurder oppføring 5.

Oppføring 5. Initialisering av matriser med sinus- og cosinusverdier

class Grafikk {statisk dobbel [] sines, cosinus; statisk {sines = ny dobbel [360]; cosinus = ny dobbel [360]; for (int i = 0; i <sines.length; i ++) {sines [i] = Math.sin (Math.toRadians (i)); cosines [i] = Math.cos (Math.toRadians (i)); }}}

Oppføring 5 erklærer a Grafikk klasse som erklærer sines og cosinus arrayvariabler. Den erklærer også en klasseinitialiseringsblokk som oppretter 360-element-matriser hvis referanser er tildelt sines og cosinus. Den bruker deretter en til uttalelse for å initialisere disse matriseelementene til passende sinus- og cosinusverdier, ved å kalle Matte klassen synd() og cos () metoder. (Matte er en del av Java sitt standard klassebibliotek. Jeg vil diskutere denne klassen og disse metodene i en fremtidig artikkel.)

Prestasjonstriks

Fordi ytelse er viktig for grafiske applikasjoner, og fordi det er raskere å få tilgang til et arrayelement enn å kalle en metode, bruker utviklere til ytelsestriks som å lage og initialisere matriser med sinus og cosinus.

Kombinere initialisering av klasse felt og initialisering av klasse

Du kan kombinere flere klasse feltinitialiserere og klasseinitialiseringsblokker i et program. Oppføring 6 gir et eksempel.

Oppføring 6. Utføre klasseinitialisering i topp-ned-rekkefølge

klasse MCFICIB {statisk int x = 10; statisk dobbel temp = 98,6; statisk {System.out.println ("x =" + x); temp = (temp - 32) * 5.0 / 9.0; // konverter til Celsius System.out.println ("temp =" + temp); } statisk int y = x + 5; statisk {System.out.println ("y =" + y); } public static void main (String [] args) {}}

Oppføring 6 erklærer og initialiserer et par klassefelt (x og y), og erklærer et par statisk initialiserer. Sett sammen denne listen som vist:

javac MCFICIB.java

Kjør deretter den resulterende applikasjonen:

java MCFICIB

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

x = 10 temp = 37,0 y = 15

Denne utgangen avslører at initialisering av klassen utføres i topp-og-ned-rekkefølge.

() metoder

Ved kompilering av klasseinitialiserere og klasseinitialiseringsblokker lagrer Java-kompilatoren den kompilerte bykoden (i topp-ned-rekkefølge) i en spesiell metode som heter (). Vinkelbeslagene forhindrer a navnekonflikt: du kan ikke erklære a () metoden i kildekoden fordi < og > tegn er ulovlige i en identifikasjonssammenheng.

Etter å ha lastet inn en klasse, kaller JVM denne metoden før den ringer hoved() (når hoved() er tilstede).

La oss se på innsiden MCFICIB.klasse. Følgende delvis demontering avslører den lagrede informasjonen for x, temp, og y Enger:

Felt # 1 00000290 Access Flags ACC_STATIC 00000292 Navn x 00000294 Descriptor I 00000296 Attributter Count 0 Field # 2 00000298 Access Flags ACC_STATIC 0000029a Navn temp 0000029c Descriptor D 0000029e Attributter Count 0 Field # 3 000002a0 Access Flags ACC_STATIC 000002a 000002a 000002a 000002a 0

De Deskriptor linje identifiserer JVM-ene type deskriptor for feltet. Typen er representert med en enkelt bokstav: Jeg til int og D til dobbelt.

Følgende delvis demontering avslører bytecode instruksjonssekvensen for () metode. Hver linje starter med et desimaltall som identifiserer den nullbaserte forskyvningsadressen til den påfølgende instruksjonen:

 0 bipush 10 2 putstatic MCFICIB / x I 5 ldc2_w # 98.6 8 putstatic MCFICIB / temp D 11 getstatic java / lang / System / out Ljava / io / PrintStream; 14 new java / lang / StringBuilder 17 dup 18 invokespecial java / lang / StringBuilder / () V 21 ldc "x =" 23 invokevirtual java / lang / StringBuilder / append (Ljava / lang / String;) Ljava / lang / StringBuilder; 26 getstatic MCFICIB / x I 29 invokevirtual java / lang / StringBuilder / append (I) Ljava / lang / StringBuilder; 32 invokevirtual java / lang / StringBuilder / toString () Ljava / lang / String; 35 invokevirtual java / io / PrintStream / println (Ljava / lang / String;) V 38 getstatic MCFICIB / temp D 41 ldc2_w # 32 44 dsub 45 ldc2_w # 5 48 dmul 49 ldc2_w # 9 52 ddiv 53 putstatic MCFICIB / temp D 56 getstatic java / lang / System / ut Ljava / io / PrintStream; 59 new java / lang / StringBuilder 62 dup 63 invokespecial java / lang / StringBuilder / () V 66 ldc "temp =" 68 invokevirtual java / lang / StringBuilder / append (Ljava / lang / String;) Ljava / lang / StringBuilder; 71 getstatic MCFICIB / temp D 74 invokevirtual java / lang / StringBuilder / append (D) Ljava / lang / StringBuilder; 77 invokevirtual java / lang / StringBuilder / toString () Ljava / lang / String; 80 invokevirtual java / io / PrintStream / println (Ljava / lang / String;) V 83 getstatic MCFICIB / x I 86 iconst_5 87 iadd 88 putstatic MCFICIB / y I 91 getstatic java / lang / System / out Ljava / io / PrintStream; 94 new java / lang / StringBuilder 97 dup 98 invokespecial java / lang / StringBuilder / () V 101 ldc "y =" 103 invokevirtual java / lang / StringBuilder / append (Ljava / lang / String;) Ljava / lang / StringBuilder; 106 getstatic MCFICIB / y I 109 invokevirtual java / lang / StringBuilder / append (I) Ljava / lang / StringBuilder; 112 invokevirtual java / lang / StringBuilder / toString () Ljava / lang / String; 115 invokevirtual java / io / PrintStream / println (Ljava / lang / String;) V 118 retur

Instruksjonssekvensen fra forskyvning 0 til forskyvning 2 tilsvarer følgende klassefeltinitialisering:

statisk int x = 10;

Instruksjonssekvensen fra forskyvning 5 til forskyvning 8 tilsvarer følgende klassefeltinitialisering:

statisk dobbel temp = 98,6;

Instruksjonssekvensen fra forskyvning 11 til forskyvning 80 tilsvarer følgende klasseinitialiseringsblokk:

statisk {System.out.println ("x =" + x); temp = (temp - 32) * 5.0 / 9.0; // konverter til Celsius System.out.println ("temp =" + temp); }

Instruksjonssekvensen fra forskyvning 83 til forskyvning 88 tilsvarer følgende klassefeltinitialisering:

statisk int y = x + 5;

Instruksjonssekvensen fra forskyvning 91 til forskyvning 115 tilsvarer følgende klasseinitialiseringsblokk:

statisk {System.out.println ("y =" + y); }

Til slutt, komme tilbake instruksjon ved forskyvning 118 returnerer kjøring fra () til den delen av JVM som kalte denne metoden.

Ikke bekymre deg for hva bytekoden betyr

Takeaway fra denne øvelsen er å se at all kode i Listing 6s klassefeltinitialiserere og klasseinitialiseringsblokker ligger i () metode, og utføres i ovenfra og ned rekkefølge.

Hvordan initialisere objekter

Etter at en klasse er lastet inn og initialisert, vil du ofte lage objekter fra klassen. Som du lærte i min siste introduksjon til programmering med klasser og objekter, initialiserer du et objekt via koden du plasserer i en klasses konstruktør. Vurder oppføring 7.

Oppføring 7. Bruk konstruktøren til å initialisere et objekt

klasse By {privat strengnavn; int befolkning; By (strengnavn, intpopulasjon) {this.name = navn; this.population = befolkning; } @ Override public String toString () {return name + ":" + population; } offentlig statisk ugyldig hoved (String [] args) {City newYork = new City ("New York", 8491079); System.out.println (newYork); // Utgang: New York: 8491079}}

Oppføring 7 erklærer a By klasse med Navn og befolkning Enger. Når en By objektet er opprettet, By (strengnavn, intpopulasjon) constructor kalles til å initialisere disse feltene til den kallte konstruktørens argumenter. (Jeg har også overstyrt Gjenstands offentlig streng til streng () metode for å enkelt returnere bynavnet og befolkningsverdien som en streng. System.out.println () til slutt kaller denne metoden for å returnere objektets strengrepresentasjon, som den sender ut.)

Før konstruktøren blir kalt, hvilke verdier gjør Navn og befolkning inneholde? Du kan finne ut av det ved å sette inn System.out.println (dette.navnet); System.out.println (denne.populasjonen); i starten av konstruktøren. Etter å ha samlet kildekoden (javac City.java) og kjører applikasjonen (java by), ville du observere null til Navn og 0 til befolkning. De ny operatøren nullstiller objektets (forekomst) felt for et objekt før han utfører en konstruktør.

Som med klassefelt, kan du eksplisitt initialisere objektfelt. For eksempel kan du spesifisere Strengnavn = "New York"; eller int befolkning = 8491079;. Imidlertid er det vanligvis ingenting å tjene på å gjøre dette, fordi disse feltene vil bli initialisert i konstruktøren. Den eneste fordelen jeg kan tenke meg er å tilordne en standardverdi til et objektfelt; denne verdien brukes når du ringer til en konstruktør som ikke initialiserer feltet:

int numDoors = 4; // standardverdi tildelt numDoors Car (strengmerke, strengmodell, int år) {dette (merke, modell, år, numDoors); } Car (String make, String model, int year, int numDoors) {this.make = make; this.model = modell; dette.år = år; this.numDoors = numDoors; }

Objektinitialisering speiler initialisering av klasse

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