á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