Na akkor még egyszer, hogy minden tiszta legyen.
Van natív kód, amit valamilyen nyelvből lefordítanak, pl c++, de valóban, akár javából is (bár az nem gyakori jelenség, lévén, hogy a nyelv menedzselt nyelv, és igazából túl sok értelme emiatt aztán nincs is).
Van a byte kód, amikor a nyelv forráskódjából generált virtuális gép-nyelvre fordítják a cuccot, ilyen pl a Java, de ilyen pl. a Python is, a kettő közt az a különbség, hogy a Python on-the-fly állítja elő a pyc fájlokat, míg a Java futtatás előtt.
Van interpreter, ilyen pl a Basic.
Van azon kívül a byte kódot alkalmazó nyelvek esetén a JIT, azaz Just In-Time compiler, ami úgy működik, hogy amikor egy osztályra szükség van, akkor az abból generált byte-kódból a célprocesszoron futó natív kódot fordít a VM, és valójában natív kód fut, nem a byte-kódot értelmezi folyamatosan.
A Dalvik a 2.2-es Android óta az utóbbi módon működik, ezért ténylegesen natív kód fut (ami kétségtelenül olykor kevésbé optimalizált, mint egy közvetlenül optimalizáltan fordított pl c++ kód, de a különbség elenyésző).
Tekintettel arra, hogy - mint írtam - a Java ún. menedzselt nyelv, ami azt jelenti, hogy a változók menedzselését nem a programozó, hanem a futtató környezet végzi, és tekintettel arra, hogy a változók menedzselése az idő igen jelentős részét viszi el, az optimalizáció csak a maradék feladatokra korlátozódik, így annak jelentősége erősen csökken.
Pont a változókezelést végző rész (GC, Garbage Collector) a legkritikusabb a Java alapú környezetekben. Nagyrészt emiatt van az Androidos telefonok esetén (főleg az egymagos készülékekben) az a bizonyos "lagging".
A kétmagos készülékek esetén már a 2.3-as Androidnál is a GC-t a második processzor végzi, ezért a lag egészen elenyésző, sőt, ez az az eset, amikor egy egyszálas Java alkalmazás gyorsabb lehet egy egyszálas C++-nál is, hiszen a feladatok egy részét az egyszálasság ellenére átveszi a második processzor.