Programmering

Objekter og matriser

Velkommen til nok en utgave av Under panseret. Denne kolonnen fokuserer på Java's underliggende teknologier. Det tar sikte på å gi utviklere et glimt av mekanismene som får Java-programmene til å kjøre. Denne månedens artikkel tar en titt på bytekodene som omhandler objekter og matriser.

Objektorientert maskin

Den virtuelle Java-maskinen (JVM) jobber med data i tre former: objekter, objektreferanser og primitive typer. Objekter befinner seg på den søppel som samles opp. Objektreferanser og primitive typer ligger enten på Java-stakken som lokale variabler, på bunken som eksempelvariabler av objekter, eller i metodeområdet som klassevariabler.

I den virtuelle Java-maskinen blir minnet allokert på søppeloppsamlet bunke bare som objekter. Det er ingen måte å tildele minne til en primitiv type på bunken, bortsett fra som en del av et objekt. Hvis du vil bruke en primitiv type der en Gjenstand referanse er nødvendig, kan du tildele et innpakningsobjekt for typen fra java.lang pakke. For eksempel er det en Heltall klasse som pakker inn en int skriv med et objekt. Bare objektreferanser og primitive typer kan ligge på Java-stakken som lokale variabler. Objekter kan aldri ligge på Java-stakken.

Den arkitektoniske separasjonen av objekter og primitive typer i JVM gjenspeiles i Java-programmeringsspråket, der objekter ikke kan erklæres som lokale variabler. Bare objektreferanser kan erklæres som sådan. Ved erklæring refererer en objektreferanse til ingenting. Først etter at referansen er eksplisitt initialisert - enten med en referanse til et eksisterende objekt eller med en oppfordring til ny - refererer referansen til et faktisk objekt.

I JVM-instruksjonssettet blir alle objekter instantiert og tilgang til med samme sett med opkoder, bortsett fra matriser. I Java er matriser fullverdige objekter, og som alle andre objekter i et Java-program, blir de opprettet dynamisk. Array-referanser kan brukes hvor som helst som en referanse til typen Gjenstand er påkrevd, og enhver metode for Gjenstand kan påberopes på en matrise. Likevel, på den virtuelle Java-maskinen, håndteres matriser med spesielle bytekoder.

Som med alle andre objekter, kan matriser ikke deklareres som lokale variabler; bare matrisehenvisninger kan. Matrixobjekter i seg selv inneholder alltid enten en rekke primitive typer eller en rekke objektreferanser. Hvis du erklærer en rekke objekter, får du en rekke objektreferanser. Objektene selv må eksplisitt opprettes med ny og tilordnet elementene i matrisen.

Opkoder for objekter

Instantiering av nye objekter oppnås via

ny

opcode. To enbyte-operander følger

ny

opcode. Disse to bytene kombineres for å danne en 16-biters indeks i det konstante bassenget. Det konstante bassengelementet ved den angitte forskyvningen gir informasjon om klassen til det nye objektet. JVM oppretter en ny forekomst av objektet på dyngen og skyver referansen til det nye objektet på bunken, som vist nedenfor.

Objektoppretting
OpcodeOperand (er)Beskrivelse
nyindexbyte1, indexbyte2skaper et nytt objekt på dyngen, skyver referanse

Den neste tabellen viser opkodene som setter og henter objektfelt. Disse opkodene, putfield og getfield, fungerer bare på felt som er instansvariabler. Statiske variabler er tilgjengelige av putstatisk og getstatisk, som blir beskrevet senere. Putfield- og getfield-instruksjonene tar hver sin to byte operander. Operandene kombineres for å danne en 16-biters indeks i det konstante bassenget. Det konstante bassenget ved denne indeksen inneholder informasjon om feltets type, størrelse og forskyvning. Objektreferansen er hentet fra stabelen i både putfield- og getfield-instruksjonene. Putfield-instruksjonen tar forekomstvariabelverdien fra stabelen, og getfield-instruksjonen skyver den hentede forekomstvariabelverdien til stabelen.

Få tilgang til forekomstvariabler
OpcodeOperand (er)Beskrivelse
putfieldindexbyte1, indexbyte2angi felt, indikert av indeks, av objekt til verdi (begge tatt fra stabelen)
getfieldindexbyte1, indexbyte2skyver felt, indikert av indeks, av objektet (tatt fra bunken)

Klassevariabler er tilgjengelige via getstatic og putstatic opcodes, som vist i tabellen nedenfor. Både getstatisk og putstatisk tar to en-byte-operander, som kombineres av JVM for å danne en 16-biters usignert forskyvning i det konstante bassenget. Det konstante bassenget på det stedet gir informasjon om ett statisk felt i en klasse. Fordi det ikke er noe spesielt objekt assosiert med et statisk felt, er det ingen objektreferanse brukt av verken getstatic eller putstatic. Den putstatiske instruksjonen tar verdien å tildele fra bunken. Den getstatiske instruksjonen skyver den hentede verdien på bunken.

Tilgang til klassevariabler
OpcodeOperand (er)Beskrivelse
putstatiskindexbyte1, indexbyte2angi felt, indikert av indeks, av objekt til verdi (begge tatt fra stabelen)
getstatiskindexbyte1, indexbyte2skyver felt, indikert av indeks, av objektet (tatt fra bunken)

Følgende opkoder kontrollerer for å se om objektreferansen på toppen av bunken refererer til en forekomst av klassen eller grensesnittet indeksert av operandene som følger opkoden. Kontrollkastinstruksjonen kaster CheckCastException hvis objektet ikke er en forekomst av den angitte klassen eller grensesnittet. Ellers gjør checkcast ingenting. Objektreferansen forblir på bunken, og kjøringen fortsetter ved neste instruksjon. Denne instruksjonen sikrer at rollebesetninger er trygge på kjøretid og utgjør en del av JVMs sikkerhetsteppe.

Instansens instans spretter objektreferansen fra toppen av bunken og skyver sant eller usant. Hvis objektet faktisk er en forekomst av den spesifiserte klassen eller grensesnittet, blir sant presset på bunken, ellers blir false skubbet på bunken. Instansen av instruksjonen brukes til å implementere tilfelle av nøkkelord for Java, som lar programmerere teste om et objekt er en forekomst av en bestemt klasse eller grensesnitt.

Type kontroll
OpcodeOperand (er)Beskrivelse
checkcastindexbyte1, indexbyte2Kaster ClassCastException hvis objektref på stabel ikke kan kastes til klasse ved indeks
tilfelle avindexbyte1, indexbyte2Pushes true hvis objectref på stack er en forekomst av klasse ved indeks, ellers skyver false

Opkoder for matriser

Instantiering av nye matriser oppnås via ny matrise, anewarray og multianewarray opcodes. Newarray-opoden brukes til å lage matriser av andre primitive typer enn objektreferanser. Den spesifikke primitive typen spesifiseres av en enkelt byte-operand etter den nye matrise-opoden. Newarray-instruksjonen kan lage matriser for byte, kort, char, int, lang, float, double eller boolean.

Anewarray-instruksjonen lager en rekke objektreferanser. To en-byte-operander følger anakekoden og kombineres for å danne en 16-biters indeks i det konstante bassenget. En beskrivelse av klassen av objektet som matrisen skal opprettes for, finnes i den konstante puljen ved den spesifiserte indeksen. Denne instruksjonen tildeler plass til matrisen med objektreferanser og initialiserer referansene til null.

Instruksjonen for multianwarray brukes til å tildele flerdimensjonale matriser - som ganske enkelt er matriser av matriser - og kan tildeles ved gjentatt bruk av anewarray og newarray-instruksjonene. Multianeway-instruksjonen komprimerer ganske enkelt bytekodene som trengs for å lage flerdimensjonale matriser til en instruksjon. To enbyte-operander følger multikanal-opokoden og kombineres for å danne en 16-biters indeks i det konstante bassenget. En beskrivelse av objektklassen som matrisen skal opprettes for, finnes i den konstante puljen ved den spesifiserte indeksen. Umiddelbart etter de to en-byte-operandene som danner den konstante bassengindeksen, er en en-byte-operand som spesifiserer antall dimensjoner i denne flerdimensjonale matrisen. Størrelsene for hver dimensjon vises fra bunken. Denne instruksjonen tildeler plass til alle matriser som er nødvendige for å implementere flerdimensjonale matriser.

Opprette nye matriser
OpcodeOperand (er)Beskrivelse
newarrayen typepopper lengde, tildeler ny matrise med primitive typer av typen angitt med atype, skyver objektref til ny matrise
anewarrayindexbyte1, indexbyte2popper lengde, tildeler en ny matrise av objekter i klassen som er indikert av indeksbyte1 og indeksbyte2, skyver objektref av ny matrise
multianwarrayindexbyte1, indexbyte2, dimensjonerpopper dimensjoner antall matriselengder, tildeler en ny flerdimensjonal matrise av klasse angitt med indeksbyte1 og indeksbyte2, skyver objektref til ny matrise

Den neste tabellen viser instruksjonen som spretter en matereferanse fra toppen av stabelen og skyver lengden på den matrisen.

Få matrikelengde
OpcodeOperand (er)Beskrivelse
rekkevidde(ingen)popper objektref av en matrise, skyver lengden på den matrisen

Følgende opkoder henter et element fra en matrise. Array-indeksen og array-referansen poppes fra stakken, og verdien ved den spesifiserte indeksen til den spesifiserte arrayen skyves tilbake på stakken.

Henter et matriseelement
OpcodeOperand (er)Beskrivelse
baload(ingen)popper indeks og arrayref av en rekke bytes, skyver arrayref [index]
kaload(ingen)popper indeks og arrayref av en rekke tegn, skyver arrayref [index]
salat(ingen)popper indeks og arrayref av en rekke shorts, skyver arrayref [index]
iaload(ingen)popper indeks og arrayref av en rekke ints, skyver arrayref [index]
laload(ingen)popper indeks og arrayref av en rekke longs, skyver arrayref [index]
faload(ingen)popper indeks og arrayref av en rekke floats, skyver arrayref [index]
daload(ingen)popper indeks og arrayref av en rekke dobler, skyver arrayref [index]
aaload(ingen)popper indeks og arrayref av en rekke objectrefs, skyver arrayref [index]

Den neste tabellen viser opkodene som lagrer en verdi i et matriseelement. Verdien, indeksen og matrisereferansen vises fra toppen av bunken.

Lagring i et array-element
OpcodeOperand (er)Beskrivelse
bastore(ingen)popper verdi, indeks og arrayref for en array med byte, tilordner arrayref [index] = verdi
castore(ingen)popper verdi, indeks og arrayref av en rekke tegn, tilordner arrayref [index] = verdi
sastore(ingen)popper verdi, indeks og arrayref for en rekke shorts, tilordner arrayref [index] = verdi
iastore(ingen)popper verdi, indeks og arrayref for en rekke ints, tilordner arrayref [index] = verdi
lastore(ingen)pops verdi, indeks og arrayref for en array med longs, tilordner arrayref [index] = verdi
fastore(ingen)popper verdi, indeks og arrayref for en array med floats, tilordner arrayref [index] = verdi
dastore(ingen)popper verdi, indeks og arrayref for en array med dobler, tilordner arrayref [index] = verdi
aastore(ingen)popper verdi, indeks og arrayref for en array med objektrefs, tilordner arrayref [index] = verdi

Tredimensjonalt array: en virtuell Java-simulering av maskiner

Appleten nedenfor viser en Java-virtuell maskin som utfører en sekvens av bykoder. Bytekodesekvensen i simuleringen ble generert av javac for initAnArray () metoden i klassen vist nedenfor:

klasse ArrayDemo {statisk ugyldig 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; }}}}} 

Bytekodene generert av javac til initAnArray () er vist nedenfor:

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