Java Primitiver versus Objects

Oversikt

i denne opplæringen viser vi fordeler og ulemper med Å bruke Java primitive typer og deres innpakket kolleger.

Java Type System

Java har et todelt type system bestående av primitiver som int, boolsk og referansetyper som Heltall, Boolsk. Hver primitiv type tilsvarer en referansetype.

hvert objekt inneholder en enkelt verdi av den tilsvarende primitive typen. Wrapper-klassene er uforanderlige (slik at deres tilstand ikke kan endres når objektet er konstruert) og er endelige (slik at vi ikke kan arve fra dem).

Under hetten utfører Java en konvertering mellom primitive og referansetyper hvis en faktisk type er forskjellig fra den deklarerte:

Integer j = 1; // autoboxingint i = new Integer(1); // unboxing

prosessen med å konvertere en primitiv type til en referanse kalles autoboxing, den motsatte prosessen kalles unboxing.

Fordeler og Ulemper

beslutningen om hvilket objekt som skal brukes, er basert på hvilken applikasjonsytelse vi prøver å oppnå, hvor mye tilgjengelig minne vi har, mengden tilgjengelig minne og hvilke standardverdier vi skal håndtere.

hvis vi ikke møter noen av dem, kan vi ignorere disse hensynene, selv om det er verdt å kjenne dem.

3.1. Enkelt Element Minne Fotavtrykk

bare for referansen har de primitive typevariablene følgende innvirkning på minnet:

  • boolsk – 1 bit
  • byte – 8 biter
  • kort, char – 16 biter
  • int, float – 32 biter
  • lang, dobbel – 64 biter

i praksis kan disse verdiene variere avhengig Av Den Virtuelle maskinimplementeringen. I ORACLES VM er den boolske typen for eksempel kartlagt til int-verdier 0 og 1, så det tar 32 biter, som beskrevet her: Primitive Typer og Verdier.

Variabler av disse typene lever i stakken og dermed nås raskt. For detaljer, anbefaler vi vår opplæring På Java-minnemodellen.

referansetypene er objekter, de lever på bunken og er relativt sakte å få tilgang til. De har en viss overhead om sine primitive kolleger.

de konkrete verdiene til overhead er generelt JVM-spesifikke. Her presenterer vi resultater for en 64-biters virtuell maskin med disse parametrene:

java 10.0.1 2018-04-17Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10)Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode)

for å få et objekts interne struktur, kan Vi bruke Java Object Layout tool (se vår annen veiledning om hvordan du får størrelsen på et objekt).

det viser seg at en enkelt forekomst av en referansetype på DENNE JVM opptar 128 biter unntatt Lang Og Dobbel som opptar 192 biter:

  • Boolsk – 128 biter
  • Byte – 128 biter
  • Kort, Tegn – 128 biter
  • Heltall, Float – 128 biter
  • Lang, Dobbelt – 192 biter

vi kan se At en enkelt variabel av boolsk type opptar så mye plass SOM 128 primitive, mens en heltallvariabel opptar Så mye plass som fire int.

3.2. Minnefotavtrykk for Arrays

situasjonen blir mer interessant hvis vi sammenligner hvor mye minne opptar arrays av de aktuelle typene.

når vi lager arrays med det forskjellige antall elementer for hver type, får vi et plott:

som viser at typene er gruppert i fire familier med hensyn til hvordan minnet m(s) avhenger av antall elementer s i arrayet:

  • lang, dobbel: m(s) = 128 + 64 s
  • kort, char: m(s) = 128 + 64
  • byte, boolsk: m(s) = 128 + 64
  • resten: m (s) = 128 + 64

hvor firkantede parenteser angir standard takfunksjon.Overraskende, arrays av de primitive typene long og double forbruker mer minne enn deres wrapper klasser Long Og Double.

Vi kan se enten at enkeltelementarrayer av primitive typer er nesten alltid dyrere (unntatt lang og dobbel) enn den tilsvarende referansetypen.

3.3. Ytelse

Ytelsen Til En Java-kode er ganske subtilt, det avhenger veldig mye av maskinvaren som koden kjører på, på kompilatoren som kan utføre visse optimaliseringer, på tilstanden til den virtuelle maskinen, på aktiviteten til andre prosesser i operativsystemet.

som vi allerede har nevnt, lever de primitive typene i stakken mens referansetypene lever i bunken. Dette er en dominerende faktor som bestemmer hvor fort objektene får tilgang.for å demonstrere hvor mye operasjonene for primitive typer er raskere enn de for wrapper klasser, la oss lage en fem millioner element array der alle elementene er like bortsett fra den siste; så utfører vi et oppslag for det elementet:

while (!pivot.equals(elements)) { index++;}

og sammenligne ytelsen til denne operasjonen for saken når arrayet inneholder variabler av primitive typer og for saken når den inneholder objekter av referansetypene.

Vi bruker det velkjente jmh benchmarking-verktøyet (se vår veiledning om hvordan du bruker det), og resultatene av oppslagsoperasjonen kan oppsummeres i dette diagrammet:

Selv For en så enkel operasjon kan Vi se at det kreves mer tid til å utføre operasjonen for wrapper-klasser.

i tilfelle mer kompliserte operasjoner som summering, multiplikasjon eller divisjon, kan forskjellen i hastighet skyrocket.

3.4. Standardverdier

Standardverdier for de primitive typene er 0 (i den tilsvarende representasjonen, dvs. 0, 0.0d etc) for numeriske typer, false for den boolske typen, \u0000 for char-typen. For wrapper-klassene er standardverdien null.

det betyr at de primitive typene kan skaffe verdier bare fra sine domener, mens referansetypene kan skaffe seg en verdi (null) som på en eller annen måte ikke tilhører deres domener.

Selv om det ikke anses som en god praksis å la variabler ikke initialiseres, kan vi noen ganger tildele en verdi etter opprettelsen.

i en slik situasjon, når en primitiv type variabel har en verdi som er lik sin type standard, bør vi finne ut om variabelen virkelig er initialisert.

Det er ikke noe slikt problem med en wrapper klasse variabler siden nullverdien er ganske tydelig indikasjon på at variabelen ikke er initialisert.

Bruk

som vi har sett, er de primitive typene mye raskere og krever mye mindre minne. Derfor vil vi kanskje foretrekke å bruke dem.på den annen side tillater ikke Gjeldende Java-språkspesifikasjon bruk av primitive typer i parametrized types (generics), I Java-samlingene eller Reflection API.

når søknaden vår trenger samlinger med et stort antall elementer, bør vi vurdere å bruke arrays med så mer «økonomisk» type som mulig, som det er illustrert på plottet ovenfor.

Konklusjon

Det denne opplæringen illustrerte vi at objektene I Java er tregere og har større minnepåvirkning enn deres primitive analoger.

som alltid kan kodesnutter finnes i vårt lager På GitHub.

Kom i Gang Med Våren 5 Og Våren Boot 2, Gjennom Lær Våren kurset:

>> SJEKK UT KURSET

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *