Programmering

Initiering af klasse og objekt i Java

Klasser og objekter i Java skal initialiseres, før de bruges. Du har tidligere lært, at klassefelter initialiseres til standardværdier, når klasser indlæses, og at objekter initialiseres via konstruktører, men der er mere ved initialisering. Denne artikel introducerer alle Java-funktioner til initialisering af klasser og objekter.

download Hent koden Download kildekoden for eksempel applikationer i denne vejledning. Oprettet af Jeff Friesen til JavaWorld.

Sådan initialiseres en Java-klasse

Før vi udforsker Java's support til klasseinitialisering, lad os sammenfatte trinene til initialisering af en Java-klasse. Overvej at liste 1.

Notering 1. Initialisering af klassefelter til standardværdier

klasse SomeClass {statisk boolsk b; statisk byte ved; statisk karakter c; statisk dobbelt d; statisk flyde f; statisk int i; statisk lang l; statisk kort s; statisk strengstreng; }

Liste 1 erklærer klasse SomeClass. Denne klasse erklærer ni felter af typer boolsk, byte, char, dobbelt, flyde, int, lang, kortog Snor. Hvornår SomeClass er indlæst, er hvert felts bits sat til nul, som du fortolker som følger:

falsk 0 \ u0000 0,0 0,0 0 0 0 null

De tidligere klassefelter blev implicit initialiseret til nul. Du kan dog også eksplicit initialisere klassefelter ved direkte at tildele værdier til dem som vist i liste 2.

Notering 2. Initialisering af klassefelter til eksplicitte værdier

klasse SomeClass {statisk boolsk b = sand; statisk byte ved = 1; statisk tegn c = 'A'; statisk dobbelt d = 2,0; statisk svømmer f = 3.0f; statisk int i = 4; statisk lang l = 5000000000L; statisk kort s = 20000; statisk streng st = "abc"; }

Hver opgaves værdi skal være typekompatibel med klassefeltets type. Hver variabel gemmer værdien direkte med undtagelse af St.. Variabel St. gemmer en henvisning til en Snor objekt, der indeholder abc.

Henviser til klasse felter

Når du initialiserer et klassefelt, er det lovligt at initialisere det til værdien af ​​et tidligere initialiseret klassefelt. For eksempel initialiserer Listing 3 y til xværdi. Begge felter initialiseres til 2.

Fortegnelse 3. Henvisning til et tidligere erklæret 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 omvendte er dog ikke lovligt: ​​du kan ikke initialisere et klassefelt til værdien af ​​et efterfølgende deklareret klassefelt. Java-kompilatoroutputene ulovlig forwardhenvisning når det møder dette scenario. Overvej liste 4.

Fortegnelse 4. Forsøg på at henvise til et efterfølgende deklareret 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); }}

Compileren rapporterer ulovlig forwardhenvisning når det møder statisk int x = y;. Dette skyldes, at kildekoden er samlet ovenfra og ned, og compileren endnu ikke har set y. (Det vil også sende denne meddelelse, hvis y blev ikke eksplicit initialiseret.)

Klasse initialiseringsblokke

I nogle tilfælde vil du muligvis udføre komplekse klassebaserede initialiseringer. Du gør dette, når en klasse er blevet indlæst, og før der oprettes nogen objekter fra den klasse (forudsat at klassen ikke er en hjælpeklasse). Du kan bruge en klasseinitialiseringsblok til denne opgave.

EN klasse initialiseringsblok er en blok med udsagn forud for statisk nøgleord, der er introduceret i klassens krop. Når klassen indlæses, udføres disse udsagn. Overvej at liste 5.

Notering 5. Initialisering af arrays med sinus- og cosinusværdier

klasse Grafik {statisk dobbelt [] sines, cosinus; statisk {sines = ny dobbelt [360]; cosinus = ny dobbelt [360]; for (int i = 0; i <sines.length; i ++) {sines [i] = Math.sin (Math.toRadians (i)); cosinus [i] = Math.cos (Math.toRadians (i)); }}}

Liste 5 erklærer en Grafik klasse, der erklærer sines og cosinus array variabler. Det erklærer også en klasseinitialiseringsblok, der opretter 360-element-arrays, hvis referencer er tildelt sines og cosinus. Det bruger derefter en til erklæring om at initialisere disse matrixelementer til de relevante sinus- og cosinusværdier ved at kalde Matematik klassens synd() og cos () metoder. (Matematik er en del af Java's standard klassebibliotek. Jeg diskuterer denne klasse og disse metoder i en fremtidig artikel.)

Performance trick

Fordi ydeevne er vigtig for grafikapplikationer, og fordi det er hurtigere at få adgang til et matrixelement end at kalde en metode, bruger udviklere til præstations-tricks, såsom oprettelse og initialisering af arrays af sines og cosinus.

Kombination af klassefeltinitialisering og klasseinitialiseringsblokke

Du kan kombinere flere klassefeltinitialiserere og klasseinitialiseringsblokke i en applikation. Liste 6 giver et eksempel.

Fortegnelse 6. Udførelse af klasseinitialisering i top-down-rækkefølge

klasse MCFICIB {statisk int x = 10; statisk dobbelt 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); } offentlig statisk ugyldig hoved (String [] args) {}}

Liste 6 erklærer og initialiserer et par klassefelter (x og y) og erklærer et par statisk initialisere. Kompilér denne liste som vist:

javac MCFICIB.java

Kør derefter den resulterende applikation:

java MCFICIB

Du skal overholde følgende output:

x = 10 temp = 37,0 y = 15

Denne output afslører, at klasseinitialisering udføres i top-down-rækkefølge.

() metoder

Ved kompilering af klasseinitialiserings- og klasseinitialiseringsblokke gemmer Java-kompilatoren den kompilerede bytekode (i top-down-rækkefølge) i en særlig metode ved navn (). Vinkelbeslagene forhindrer a navnekonflikt: du kan ikke erklære en () metode i kildekode, fordi < og > tegn er ulovlige i en identifikationssammenhæng.

Efter indlæsning af en klasse kalder JVM denne metode, inden den ringer hoved () (hvornår hoved () er til stede).

Lad os tage et kig ind MCFICIB.klasse. Følgende delvise demontering afslører de lagrede oplysninger til x, Midlertidigog y felter:

Felt # 1 00000290 Adgangsflag ACC_STATIC 00000292 Navn x 00000294 Descriptor I 00000296 Attributter Antal 0 Felt # 2 00000298 Adgangsflag ACC_STATIC 0000029a Navn temp 0000029c Descriptor D 0000029e Attributter Antallet 0 Felt # 3 000002a0 Adgangsflag ACC_STATIC 000002a 000002a 000002a 000002a 0

Det Deskriptor linje identificerer JVM'erne type deskriptor til marken. Typen er repræsenteret med et enkelt bogstav: jeg til int og D til dobbelt.

Følgende delvise demontering afslører bytecode instruktions sekvensen for () metode. Hver linje starter med et decimaltal, der identificerer den nulbaserede forskydningsadresse for den efterfølgende instruktion:

 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 ny 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 / ud Ljava / io / PrintStream; 59 ny 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 return

Instruktionssekvensen fra forskydning 0 til forskydning 2 svarer til følgende klassefeltinitialisering:

statisk int x = 10;

Instruktionssekvensen fra forskydning 5 til forskydning 8 svarer til følgende klasse feltinitialisering:

statisk dobbelt temp = 98,6;

Instruktionssekvensen fra forskydning 11 til forskydning 80 svarer til følgende klasseinitialiseringsblok:

statisk {System.out.println ("x =" + x); temp = (temp - 32) * 5,0 / 9,0; // konverter til Celsius System.out.println ("temp =" + temp); }

Instruktionssekvensen fra forskydning 83 til forskydning 88 svarer til følgende klassefeltinitialisering:

statisk int y = x + 5;

Instruktionssekvensen fra forskydning 91 til forskydning 115 svarer til følgende klasseinitialiseringsblok:

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

Endelig blev Vend tilbage instruktion ved offset 118 returnerer eksekvering fra () til den del af JVM, der kaldte denne metode.

Du skal ikke bekymre dig om, hvad bytekoden betyder

Takeaway fra denne øvelse er at se, at al kode i Listing 6s klasse felt initialisering og klasse initialisering blokke er placeret i () metode og udføres i top-down rækkefølge.

Sådan initialiseres objekter

Når en klasse er indlæst og initialiseret, vil du ofte oprette objekter fra klassen. Som du lærte i min nylige introduktion til programmering med klasser og objekter initialiserer du et objekt via den kode, du placerer i en klasses konstruktør. Overvej liste 7.

Fortegnelse 7. Brug af konstruktøren til at initialisere et objekt

klasse By {privat strengnavn; int befolkning; By (strengnavn, intpopulation) {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); // Output: New York: 8491079}}

Fortegnelse 7 erklærer en By klasse med navn og befolkning felter. Når en By objekt oprettes, By (strengnavn, intpopulation) konstruktør kaldes til at initialisere disse felter til den kaldte konstruktørs argumenter. (Jeg har også tilsidesat Objekt's offentlig String toString () metode til bekvemt at returnere bynavnet og befolkningsværdien som en streng. System.out.println () kalder i sidste ende denne metode til at returnere objektets strengrepræsentation, som den udsender.)

Inden konstruktøren kaldes, hvilke værdier gør navn og befolkning indeholde? Du kan finde ud af det ved at indsætte System.out.println (dette.navn); System.out.println (denne.population); i starten af ​​konstruktøren. Efter kompilering af kildekoden (javac City.java) og kører applikationen (java by), ville du observere nul til navn og 0 til befolkning. Det ny operatøren nulstiller et objekts objekt (forekomst) felter, før han udfører en konstruktør.

Som med klassefelter kan du eksplicit initialisere objektfelter. For eksempel kan du specificere String name = "New York"; eller int-population = 8491079;. Der er dog normalt intet at vinde ved at gøre dette, fordi disse felter initialiseres i konstruktøren. Den eneste fordel, jeg kan tænke på, er at tildele en standardværdi til et objektfelt; denne værdi bruges, når du ringer til en konstruktør, der ikke initialiserer feltet:

int numDoors = 4; // standardværdi tildelt numDoors Car (strengmærke, strengmodel, int år) {dette (mærke, model, år, numDoors); } Bil (String-mærke, String-model, int-år, int numDøre) {this.make = make; this.model = model; dette.år = år; this.numDoors = numDoors; }

Objektinitialisering spejler klasseinitialisering

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