Programmering

Objekter og arrays

Velkommen til en anden udgave af Under kølerhjelmen. Denne kolonne fokuserer på Java's underliggende teknologier. Det sigter mod at give udviklere et glimt af de mekanismer, der får deres Java-programmer til at køre. Denne måneds artikel tager et kig på de bytekoder, der beskæftiger sig med objekter og arrays.

Objektorienteret maskine

Den virtuelle Java-maskine (JVM) arbejder med data i tre former: objekter, objektreferencer og primitive typer. Genstande ligger på den bunke, der er indsamlet skrald. Objektreferencer og primitive typer findes enten på Java-stakken som lokale variabler, på bunken som eksempelvariabler for objekter eller i metodeområdet som klassevariabler.

I den virtuelle Java-maskine tildeles hukommelse kun på objekter, der er indsamlet skrald. Der er ingen måde at allokere hukommelse til en primitiv type på bunken undtagen som en del af et objekt. Hvis du vil bruge en primitiv type, hvor en Objekt der er brug for reference, kan du tildele et indpakningsobjekt til typen fra java.lang pakke. For eksempel er der en Heltal klasse, der indpakker en int skriv med et objekt. Kun objektreferencer og primitive typer kan findes på Java-stakken som lokale variabler. Objekter kan aldrig opholde sig på Java-stakken.

Den arkitektoniske adskillelse af objekter og primitive typer i JVM afspejles i Java-programmeringssproget, hvor objekter ikke kan erklæres som lokale variabler. Kun objekthenvisninger kan erklæres som sådan. Efter erklæring henviser en objektreference til intet. Først efter henvisningen er eksplicit initialiseret - enten med en henvisning til et eksisterende objekt eller med et kald til ny - henviser henvisningen til et faktisk objekt.

I JVM-instruktionssættet instantieres alle objekter og fås adgang til det samme sæt opkoder undtagen arrays. I Java er arrays fuldgyldige objekter, og ligesom ethvert andet objekt i et Java-program oprettes dynamisk. Arrayreferencer kan bruges hvor som helst som en henvisning til typen Objekt er påkrævet, og enhver metode til Objekt kan påberåbes på en matrix. Alligevel håndteres arrays med specielle bytekoder i den virtuelle Java-maskine.

Som med ethvert andet objekt kan arrays ikke erklæres som lokale variabler; kun matrixreferencer kan. Matrixobjekter selv indeholder altid enten en række primitive typer eller en række objektreferencer. Hvis du erklærer en matrix med objekter, får du en matrix med objektreferencer. Objekterne selv skal eksplicit oprettes med ny og tildelt elementerne i arrayet.

Opkoder for objekter

Instantiering af nye objekter opnås via

ny

opkode. To en-byte operander følger

ny

opkode. Disse to bytes kombineres for at danne et 16-bit indeks i den konstante pool. Det konstante puljeelement ved den angivne forskydning giver information om klassen for det nye objekt. JVM opretter en ny forekomst af objektet på bunken og skubber henvisningen til det nye objekt på stakken som vist nedenfor.

Objekt oprettelse
OpkodeOperand (er)Beskrivelse
nyindexbyte1, indexbyte2skaber et nyt objekt på bunken, skubber reference

Den næste tabel viser de opkoder, der placerer og henter objektfelter. Disse opkoder, putfield og getfield, fungerer kun på felter, der er instansvariabler. Statiske variabler fås ved hjælp af putstatic og getstatic, som er beskrevet senere. Putfield- og getfield-instruktionerne tager hver to en-byte-operander. Operanderne kombineres for at danne et 16-bit indeks i den konstante pool. Elementet med konstant pool i dette indeks indeholder oplysninger om feltets type, størrelse og forskydning. Objektreferencen er taget fra stakken i både putfield- og getfield-instruktionerne. Putfield-instruktionen tager instansvariabelværdien fra stakken, og getfield-instruktionen skubber den hentede instansvariabelværdi på stakken.

Adgang til instansvariabler
OpkodeOperand (er)Beskrivelse
putfieldindexbyte1, indexbyte2sæt felt, angivet med indeks, af objekt til værdi (begge taget fra stakken)
getfieldindexbyte1, indexbyte2skubber felt, angivet med indeks, af objektet (taget fra stakken)

Klassevariabler er tilgængelige via getstatic og putstatic opcodes, som vist i nedenstående tabel. Både getstatisk og putstatisk tager to en-byte-operander, som kombineres af JVM for at danne en 16-bit usigneret forskydning i den konstante pool. Det konstante puljeelement på dette sted giver information om et statisk felt i en klasse. Da der ikke er noget bestemt objekt forbundet med et statisk felt, er der ingen objektreference, der hverken bruges af getstatic eller putstatic. Den putstatiske instruktion tager værdien at tildele fra stakken. Den getstatiske instruktion skubber den hentede værdi på stakken.

Adgang til klassevariabler
OpkodeOperand (er)Beskrivelse
putstatiskeindexbyte1, indexbyte2sæt felt, angivet med indeks, af objekt til værdi (begge taget fra stakken)
getstaticindexbyte1, indexbyte2skubber felt, angivet med indeks, af objektet (taget fra stakken)

De følgende opkoder kontrollerer for at se, om objektreferencen øverst på stakken henviser til en forekomst af klassen eller grænsefladen indekseret af operanderne efter opkoden. Checkcast-instruktionen kaster CheckCastException hvis objektet ikke er en forekomst af den angivne klasse eller grænseflade. Ellers gør checkcast intet. Objektreferencen forbliver på stakken, og udførelsen fortsættes ved den næste instruktion. Denne instruktion sikrer, at rollebesætninger er sikre på kørselstid og udgør en del af JVM's sikkerhedstæppe.

Instansen af ​​instruktionen popper objektreferencen fra toppen af ​​stakken og skubber sand eller falsk. Hvis objektet faktisk er en forekomst af den angivne klasse eller grænseflade, skubbes sandt på stakken, ellers skubbes falsk på stakken. Instansen af ​​instruktion bruges til at implementere forekomst af nøgleord for Java, som gør det muligt for programmører at teste, om et objekt er en forekomst af en bestemt klasse eller grænseflade.

Type kontrol
OpkodeOperand (er)Beskrivelse
checkcastindexbyte1, indexbyte2Kaster ClassCastException, hvis objektref på stak ikke kan kastes til klasse ved indeks
forekomst afindexbyte1, indexbyte2Skubber sandt, hvis objektref på stak er en instans af klasse ved indeks, ellers skubber falsk

Opkoder til arrays

Instantiering af nye arrays opnås via newarray, anewarray og multianewarray opcodes. Newarray-opkoden bruges til at oprette arrays af andre primitive typer end objektreferencer. Den bestemte primitive type specificeres af en enkelt byte-operand efter den nye matrix-opcode. Newarray-instruktionen kan oprette arrays for byte, short, char, int, long, float, double eller boolean.

Anewarray-instruktionen opretter en række objektreferencer. To en-byte-operander følger anewarray-opkoden og kombineres for at danne et 16-bit indeks i den konstante pool. En beskrivelse af den klasse af objekt, som arrayet skal oprettes til, findes i den konstante pool ved det angivne indeks. Denne instruktion tildeler plads til arrayet af objektreferencer og initialiserer referencerne til null.

Multianwarray-instruktionen bruges til at allokere flerdimensionelle arrays - som simpelthen er arrays of arrays - og kan tildeles ved gentagen brug af anewarray og newarray-instruktionerne. Multianewarray-instruktionen komprimerer simpelthen de bytekoder, der er nødvendige for at skabe flerdimensionelle arrays til en instruktion. To enbyte-operander følger multianewarray-opkoden og kombineres for at danne et 16-bit indeks i den konstante pool. En beskrivelse af den klasse af objekt, som arrayet skal oprettes til, findes i den konstante pool ved det angivne indeks. Umiddelbart efter de to en-byte-operander, der danner det konstante poolindeks, er en en-byte-operand, der specificerer antallet af dimensioner i dette flerdimensionale array. Størrelserne for hver dimension vises fra stakken. Denne instruktion tildeler plads til alle arrays, der er nødvendige for at implementere de flerdimensionelle arrays.

Oprettelse af nye arrays
OpkodeOperand (er)Beskrivelse
newarrayatypepopper længde, tildeler nyt array af primitive typer af typen angivet med atype, skubber objektref af det nye array
anewarrayindexbyte1, indexbyte2popper længde, tildeler en ny matrix af objekter af klasse angivet med indexbyte1 og indexbyte2, skubber objectref til nyt array
multianwarrayindexbyte1, indexbyte2, dimensionerpopper dimensioner antal array længder, tildeler et nyt multidimensionalt array af klasse angivet med indexbyte1 og indexbyte2, skubber objektref til nyt array

Den næste tabel viser instruktionen, der popper en matrixreference fra toppen af ​​stakken og skubber længden af ​​den matrix.

Få array længde
OpkodeOperand (er)Beskrivelse
arraylængde(ingen)popper objektref af en matrix, skubber længden af ​​den matrix

De følgende opkoder henter et element fra en matrix. Arrayindekset og arrayreferencen poppes fra stakken, og værdien ved det specificerede indeks for det specificerede array skubbes tilbage på stakken.

Henter et matrixelement
OpkodeOperand (er)Beskrivelse
baload(ingen)popper indeks og arrayref af en array af bytes, skubber arrayref [index]
caload(ingen)popper indeks og arrayref af en række tegn, skubber arrayref [index]
salade(ingen)popper indeks og arrayref af en række shorts, skubber arrayref [index]
iaload(ingen)popper indeks og arrayref af en række ints, skubber arrayref [index]
laload(ingen)popper indeks og arrayref af en matrix af longs, skubber arrayref [index]
faload(ingen)popper indeks og arrayref af en matrix af floats, skubber arrayref [index]
daload(ingen)popper indeks og arrayref af en matrix med dobbelt, skubber arrayref [index]
aaload(ingen)popper indeks og arrayref af en matrix af objectrefs, skubber arrayref [index]

Den næste tabel viser de opkoder, der gemmer en værdi i et matrixelement. Værdien, indekset og matrixreferencen poppes fra toppen af ​​stakken.

Lagring i et array-element
OpkodeOperand (er)Beskrivelse
bastore(ingen)popper værdi, indeks og arrayref for en array af bytes, tildeler arrayref [index] = værdi
castore(ingen)popper værdi, indeks og arrayref for en matrix af tegn, tildeler arrayref [index] = værdi
sastore(ingen)popper værdi, indeks og arrayref for en matrix af shorts, tildeler arrayref [index] = værdi
iastore(ingen)popper værdi, indeks og arrayref for en matrix af ints, tildeler arrayref [index] = værdi
lastore(ingen)pops-værdi, indeks og arrayref for en array med longs, tildeler arrayref [index] = værdi
fastore(ingen)popper værdi, indeks og arrayref for en matrix af floats, tildeler arrayref [index] = værdi
dastore(ingen)popper værdi, indeks og arrayref for en matrix med dobbelt, tildeler arrayref [index] = værdi
aastore(ingen)popper værdi, indeks og arrayref for en matrix af objektrefs, tildeler arrayref [index] = værdi

Tredimensionalt array: en Java virtuel maskinsimulering

Appletten nedenfor demonstrerer en Java-virtuel maskine, der udfører en sekvens af bytekoder. Bytecodesekvensen i simuleringen blev genereret af javac til initAnArray () metode i klassen vist nedenfor:

klasse ArrayDemo {statisk ugyldigt initAnArray () {int [] [] [] threeD = ny int [5] [4] [3]; for (int i = 0; i <5; ++ i) {for (int j = 0; j <4; ++ j) {for (int k = 0; k <3; ++ k) {threeD [ i] [j] [k] = i + j + k; }}}}} 

Bykoderne genereret af javac til initAnArray () er vist nedenfor: