Java Primitives versus Objects

áttekintés

ebben az oktatóanyagban bemutatjuk a Java primitív típusok és a csomagolt társaik használatának előnyeit és hátrányait.

Java Type System

Java van egy két-szeres típusú rendszer, amely primitívek, mint például int, logikai és Referencia típusok, mint egész, logikai. Minden primitív típus megfelel egy referencia típusnak.

minden objektum a megfelelő primitív típus egyetlen értékét tartalmazza. A wrapper osztályok változatlanok (úgy, hogy az állapotuk nem változhat, ha az objektum létrejön), és véglegesek (így nem örökölhetünk tőlük).

a motorháztető alatt a Java konverziót hajt végre a primitív és a referencia típusok között, ha egy tényleges típus eltér a deklarált típustól:

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

a primitív típus referenciává történő átalakításának folyamatát autoboxingnak nevezik, az ellenkező folyamatot unboxingnak nevezik.

előnyök és hátrányok

a döntés, hogy milyen objektumot kell használni, azon alapul, hogy milyen alkalmazásteljesítményt próbálunk elérni, mennyi rendelkezésre álló memória van, a rendelkezésre álló memória mennyisége és milyen alapértelmezett értékeket kell kezelnünk.

Ha egyikkel sem szembesülünk, figyelmen kívül hagyhatjuk ezeket a megfontolásokat, bár érdemes megismerni őket.

3.1. Egyetlen elem memória lábnyom

csak a referencia, a primitív típusú változók a következő hatással van a memóriára:

  • logikai – 1 bit
  • bájt – 8 Bit
  • rövid, char – 16 bit
  • int, float-32 bit
  • hosszú, dupla-64 bit

a gyakorlatban ezek az értékek a virtuális gép implementációjától függően változhatnak. Az Oracle virtuális gépében például a logikai típus int értékekre van leképezve 0 és 1, tehát az itt leírtak szerint 32 bitet vesz igénybe: primitív típusokat és értékeket.

Az ilyen típusú változók a veremben élnek, így gyorsan elérhetők. A részletekért javasoljuk a Java memória modell bemutatóját.

a referenciatípusok objektumok, a halomban élnek, és viszonylag lassan férnek hozzá. Van egy bizonyos felső kapcsolatos primitív társaik.

a rezsi konkrét értékei általában JVM-specifikusak. Itt egy 64 bites virtuális gép eredményeit mutatjuk be ezekkel a paraméterekkel:

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)

az objektum belső struktúrájának megszerzéséhez használhatjuk a Java objektum elrendezés eszközt(lásd egy másik bemutatónkat az objektum méretének megszerzéséről).

kiderült, hogy egyetlen példánya egy referencia típusú, ezen a JVM foglal 128 bit, kivéve a Hosszú, Dupla, amely elfoglalja a 192 bit:

  • Boolean – 128 bit
  • Byte – 128 bit
  • Rövid, Karakter – 128 bit
  • Integer, Float – 128 bit
  • a Hosszú, Dupla – 192 bit

láthatjuk, hogy egy változót a Boolean típusú foglal annyi helyet, mint 128 primitívebbek, míg egy Integer változó foglal annyi helyet, mint négy int is.

3.2. Memória lábnyom tömbök

a helyzet érdekesebbé válik, ha összehasonlítjuk, hogy mennyi memória foglalja el a vizsgált típusok tömbjeit.

Ha létrehozunk tömbök a különböző elemek száma minden típus, kapunk egy telek:

ez azt bizonyítja, hogy a típusok csoportosítva négy családok tekintetében, hogy a memória m(s) attól függ, hogy az elemek száma s a tömb:

  • a hosszú, kettős: m(s) = 128 + 64 s
  • rövid, char: m(s) = 128 + 64
  • byte, logikai érték: m(s) = 128 + 64
  • a többi: m(s) = 128 + 64

ahol a szögletes zárójelek a standard mennyezeti funkciót jelölik.

meglepő módon a primitív típusok hosszú és kettős tömbjei több memóriát fogyasztanak, mint a hosszú és kettős wrapper osztályaik.

láthatjuk, hogy a primitív típusú egyelemes tömbök szinte mindig drágábbak (kivéve a hosszú és kettős), mint a megfelelő referenciatípus.

3, 3. Teljesítmény

a teljesítmény A Java kód elég egy apró kérdés, ez nagymértékben függ attól, hogy a hardver, amelyen a kód fut, a fordító, hogy lehet végezni bizonyos optimalizálás, az állam, a virtuális gép, a tevékenység más folyamatok az operációs rendszer.

mint már említettük, a primitív típusok a veremben élnek, míg a referenciatípusok a halomban élnek. Ez egy domináns tényező, amely meghatározza, hogy az objektumok milyen gyorsan érhetők el.

bizonyítani, hogy mennyi a műveletek a primitív típusok gyorsabb, mint azok, a wrapper osztályok, hozzunk létre egy öt millió elem tömb, amelyben minden elem egyenlő, kivéve az utolsót, majd végezzük el a keresést, az adott elem:

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

lehetőséget, majd hasonlítsa össze a teljesítményét, ez a művelet az esetben, ha a tömb tartalmazza a változók a primitív típusok, valamint az esetben, ha tartalmazza az objektumok referencia típusú.

a jól ismert JMH benchmarking eszközt használjuk (lásd a használati útmutatónkat), és a keresési művelet eredményeit ebben a táblázatban foglalhatjuk össze:

még egy ilyen egyszerű művelet esetén is láthatjuk, hogy több időre van szükség a wrapper osztályok műveletének végrehajtásához.

bonyolultabb műveletek, például összegzés, szorzás vagy osztás esetén a sebességkülönbség az egekbe szökhet.

3, 4. Alapértelmezett értékek

a primitív típusok alapértelmezett értékei 0 (a megfelelő ábrázolásban, azaz 0, 0.0d stb.) numerikus típusok esetén hamis a logikai típusnál, \u0000 a char típusnál. A csomagolási osztályok esetében az alapértelmezett érték null.

Ez azt jelenti, hogy a primitív típusok csak a domainjeikből szerezhetnek értékeket, míg a referenciatípusok olyan értéket (null) szerezhetnek, amely bizonyos értelemben nem tartozik a domainjeikhez.

bár nem tekinthető jó gyakorlatnak a változók inicializálatlan hagyása, néha értéket rendelhetünk annak létrehozása után.

ilyen helyzetben, amikor egy primitív típusú változó értéke megegyezik az alapértelmezett típusával, meg kell tudnunk, hogy a változó valóban inicializálódott-e.

nincs ilyen probléma a wrapper osztályváltozókkal, mivel a null érték elég nyilvánvaló jele annak, hogy a változót nem inicializálták.

használat

mint láttuk, a primitív típusok sokkal gyorsabbak, és sokkal kevesebb memóriát igényelnek. Ezért érdemes inkább használni őket.

másrészt, a jelenlegi Java nyelv specifikáció nem teszi lehetővé a primitív típusok használatát a parametrizált típusokban( generikusokban), a Java gyűjteményekben vagy a reflexiós API-ban.

amikor alkalmazásunk nagy számú elemet tartalmazó gyűjteményeket igényel, fontolóra kell vennünk a “gazdaságosabb” típusú tömbök használatát, amint azt a fenti telek szemlélteti.

következtetés

Ez a bemutató, azt illusztráltuk, hogy a tárgyak Java lassabb, és nagyobb memória hatása, mint a primitív analógok.

mint mindig, a kódrészletek megtalálhatók a GitHub adattárában.

Kezdje a tavaszi 5-ös és a tavaszi Boot 2-vel A Learn Spring tanfolyamon keresztül:

>>nézze meg a tanfolyamot

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük