﻿<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/index.xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>A Java bájtkód titkai</title>
<link href="/_sweb4/main.css" rel="stylesheet" type="text/css" />
</head>
<body>
  <div style="margin: 0px auto; width: 985px;" id="menudiv">
  <!-- Menü -->
  <ul class="menu" id="menu">
    <li>
      <a href="#" class="menulink">Informatika</a>
      <ul>
        <li>
          <a href="#" class="sub">Nyílt forrás</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/informatika/nyilt/lnw.htm">A Linux nem Windows</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/a-katedralis-es-a-bazar/">A katedrális és a bazár</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Zárt forrás</a>
          <ul>
            <li class="topline">
              <a href="http://new.egalizer.hu/what-is-the-matrix/">What is the Matrix?</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Történelem</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/informatika/tortenelem/commodore.htm">Commodore</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/tortenelem/szszgep.htm">Személyi számítógépek</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/tortenelem/x86cpu.htm">PC processzorok</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/tortenelem/archi.htm">Számítógép-architektúrák</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/tortenelem/geos.htm">GEOS</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Esszék</a>
          <ul>
            <li class="topline">
              <a href="#" class="sub">Joel on Software</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/informatika/joel/gui.htm">Felhasználói felületek</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/essze/mkernel.htm">Mikrokernel</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/essze/hasznalat.htm">A gép használata</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/linux-vagy-windows/">Linux vagy Windows?</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/essze/javabytecode.htm">Java bájtkód</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/essze/javagc.htm">Java szemétgyűjtő</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/essze/java/java8.htm">A Java 8 újdonságai</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/essze/mbrgpt.htm">Az MBR-től a GPT-ig</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Tesztek</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/informatika/tesztek/winteszt.htm">Melyik a gyorsabb?</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/informatika/tesztek/kindle.htm">Amazon Kindle</a>
            </li>
          </ul>
        </li>
      </ul>
    </li>
    <li>
      <a href="#" class="menulink">Tudomány</a>
      <ul>
        <li>
          <a href="#" class="sub">Atomerőművek</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/tudomany/atom/baleset.htm">Atomerőmű balesetek</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/tudomany/atom/19ev.htm">Csernobil 19 évvel később</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/tudomany/atom/csernobil.htm">Csernobil</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Űrkutatás</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/tudomany/urkutatas/voyager.htm">A Voyager szondák</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/tudomany/urkutatas/voyagercomp.htm">A Voyager-ek számítógépe</a>
            </li>
          </ul>
        </li>
      </ul>
    </li>
    <li>
      <a href="#" class="menulink">Szárazföld</a>
      <ul>
        <li>
          <a href="#" class="sub">Lamborghini</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/szarazfold/egyeb/lambo/gt.htm">350 GT/400 GT</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/szarazfold/egyeb/lambo/miura.htm">Miura</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/szarazfold/egyeb/lambo/countach.htm">Countach</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Munkagépek</a>
          <ul>
            <li class="topline">
              <a href="#" class="sub">Dömperek</a>
              <ul>
                <li class="topline">
                  <a href="http://new.egalizer.hu/terex-titan/">Terex Titan</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/munkagepek/domper/cat797/cat797.htm">Caterpillar 797</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#" class="sub">Kotrógépek</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/szarazfold/munkagepek/kotrogep/muskie.htm">Big Muskie</a>
                </li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Építmények</a>
          <ul>
            <li class="topline">
              <a href="#" class="sub">Épületek</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/szarazfold/epitmeny/epulet/rekord/rekord.htm">Magassági rekordok</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/epitmeny/epulet/taipei101/taipei101.htm">Taipei 101</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/epitmeny/epulet/petronas/petronas.htm">Petronas tornyok</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/epitmeny/epulet/swfc/swfc.htm">SWFC</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/epitmeny/epulet/hins/hins.htm">Home Insurance</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#" class="sub">Tornyok</a>
              <ul>
                <li class="topline">
                  <a href="https://new.egalizer.hu/osztyankino-tv-torony/">Osztyankino TV-torony</a>
                </li>
                <li>
                  <a href="https://new.egalizer.hu/eiffel-torony/">Eiffel torony</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#" class="sub">Egyéb</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/szarazfold/epitmeny/egyeb/tenna.htm">Antennák</a>
                </li>
                <li>
                  <a href="https://new.egalizer.hu/akashi-kaikyo-hid/">Akashi Kaikyo</a>
                </li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Vasút</a>
          <ul>
            <li class="topline">
              <a href="http://new.egalizer.hu/sinkanzen/">Sinkanzen</a>
            </li>
            <li class="topline">
              <a href="http://www.egalizer.hu/szarazfold/vasut/nagyseb.htm">Nagy sebességű vonatok</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Egyéb</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/szarazfold/egyeb/wind.htm">Big Wind</a>
            </li>
          </ul>
        </li>
      </ul>
    </li>
    <li>
      <a href="#" class="menulink">Zene</a>
      <ul>
        <li>
          <a href="#" class="sub">Esszék</a>
          <ul>
            <li class="topline">
              <a href="http://new.egalizer.hu/paul-hindemith-zene-es-erzelem/">Zene és érzelem</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/arthur-honegger-a-jelen-es-a-jovo-kilatasai/">A jövőről</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/benjamin-britten-palyamrol/">Pályámról</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Zeneszerzők</a>
          <ul>
            <li class="topline">
              <a href="#" class="sub">Wolfgang Amadeus Mozart</a>
              <ul>
                <li class="topline">
                  <a href="http://new.egalizer.hu/mozart-porosz-vonosnegyesei/">Porosz vonósnégyesek</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/zene/zeneszerzok/mozart/zvers.htm">Fortepiano versenyek</a>
                </li>
                <li>
                  <a href="http://new.egalizer.hu/utazas-a-jupiterre/">Utazás a Jupiterre</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#" class="sub">Joseph Haydn</a>
              <ul>
                <li class="topline">
                  <a href="http://new.egalizer.hu/a-szimfonia-szuletese/">A szimfónia születése</a>
                </li>
              </ul>
            </li>			
            <li>
              <a href="#" class="sub">Bartók Béla</a>
              <ul>
                <li class="topline">
                  <a href="http://new.egalizer.hu/bartok-bela-oneletrajz/">Önéletrajz</a>
                </li>
                <li>
                  <a href="http://new.egalizer.hu/szamomra-minden-nap-bartok-evfordulo/">Évforduló</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#" class="sub">Gustav Mahler</a>
              <ul>
                <li class="topline">
                  <a href="http://new.egalizer.hu/ket-es-fel-perc-csond/">Két és fél perc csönd</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#" class="sub">Ludwig van Beethoven</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/zene/zeneszerzok/beethoven/kilenc.htm">Kilencedik szimfónia</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="http://www.egalizer.hu/zene/zeneszerzok/webern.htm">Anton Webern</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Karmesterek</a>
          <ul>
            <li class="topline">
              <a href="#" class="sub">Wilhelm Furtwängler</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/zene/karmesterek/furtw.htm">Bevezetés</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/zene/karmesterek/furtw2.htm">Furtwängler élete</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/zene/karmesterek/furtw3.htm">Furtwängler lemezen</a>
                </li>
                <li>
                  <a href="http://new.egalizer.hu/friedrich-schnapp/">Friedrich Schnapp</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#" class="sub">Willem Mengelberg</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/zene/karmesterek/mengel.htm">Columbia felvételek</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/zene/karmesterek/mengel_opk.htm">Opus Kura lemezek</a>
                </li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          <a href="http://new.egalizer.hu/cd-velemenyek/">CD vélemény</a>
        </li>
        <li>
          <a href="#" class="sub">Sorozatok, kiadók</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/zene/kiado/greatcon.htm">Great Conductors</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="http://www.egalizer.hu/zene/librettok/librettok.htm">Szövegkönyvek</a>
        </li>
      </ul>
    </li>
    <li>
      <a href="#" class="menulink">High Fidelity</a>
      <ul>
        <li>
          <a href="#" class="sub">Esszék</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/hifi/esszek/zenehifi.htm">A zene és a hifi</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/esszek/termtorz.htm">A HiFiről</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/a-high-end-rol/">A High End</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/esszek/modszer.htm">Módszerek és csapdák</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/a-digitalis-kihivas/">A digitális kihívás</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/loudness-unit-cd-adatbazis/">Hangosság adatbázis</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="http://new.egalizer.hu/sajat-rendszerem/">Saját rendszer</a>
        </li>
        <li>
          <a href="#" class="sub">Salvatore</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/hifi/highend/bev.htm">Bevezetés</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/highend/tortenet.htm">Történetem</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/highend/kereskedelem.htm">Kereskedelem</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/highend/lemezek.htm">Hanglemezek</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/highend/filo.htm">Filozófiám</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/highend/magazin.htm">Magazinok</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/highend/lp12.htm">Linn Sondek</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Hangtechnika</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/hifi/hangtechnika/tda1541/tda1541.htm">TDA1541</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/hangtechnika/resta/resta.htm">Restaurálás</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/cd-sacd-dvd-audio/">Formátumok</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/hangtechnika/zfelv.htm">A zenei felvételekről</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/hangtechnika/nagyfel/nagyfel.htm">A nagy felbontásról</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/hangtechnika/futomuvek.htm">CD futóművek tesztje</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Történelem</a>
          <ul>
            <li class="topline">
              <a href="http://www.egalizer.hu/hifi/tortenelem/cd.htm">A Compact Disc</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/pcm-felvetelek/">Az első PCM felvételek</a>
            </li>
            <li>
              <a href="http://www.egalizer.hu/hifi/tortenelem/gramo.htm">Gramofónia</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/solti-ringje-es-a-bitrata/">Solti Ringje és a bitráta</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="sub">Készülékek</a>
          <ul>
            <li class="topline">
              <a href="http://new.egalizer.hu/magyar-hi-fi-keszulekgyartok-listaja/">Magyar gyártók</a>
            </li>
          </ul>
        </li>
      </ul>
    </li>
    <li>
      <a href="#" class="menulink">Irodalom</a>
      <ul>
        <li class="topline">
          <a href="#" class="sub">Írók</a>
          <ul>
            <li class="topline">
              <a href="http://new.egalizer.hu/rejto-jeno-szomoru-elete/">Rejtő Jenő</a>
            </li>
            <li>
              <a href="http://new.egalizer.hu/olaf-stapledon-elete/">Olaf Stapledon</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="http://new.egalizer.hu/a-kepes-kronika/">Képes Krónika</a>
        </li>		
      </ul>
    </li>
    <li>
      <a href="#" class="menulink">Tárgyak</a>
        <ul>
            <li class="topline">
              <a href="#" class="sub">Kockák a négyzeten</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/szarazfold/egyeb/kockak1.htm">Az őskor</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/egyeb/kockak2.htm">A hőskor 1.</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/egyeb/kockak3.htm">A hőskor 2.</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/egyeb/ajandek.htm">Ajándék- készletek</a>
                </li>
              </ul>                  
            </li>			
            <li>
              <a href="#" class="sub">Karórák</a>
              <ul>
                <li class="topline">
                  <a href="http://www.egalizer.hu/szarazfold/egyeb/eichi2.htm">Eichi 2</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/szarazfold/egyeb/orakar.htm">Rejtett költségek</a>
                </li>
                <li>
                  <a href="https://new.egalizer.hu/udvozlet-japanbol/">Üdvözlet Japánból</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/targyak/orak/kings.htm">A King Seiko története</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/targyak/orak/king1.htm">Az első King Seiko</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/targyak/orak/57gs.htm">Az második Grand Seiko</a>
                </li>
                <li>
                  <a href="http://www.egalizer.hu/targyak/orak/cosc.htm">A COSC röviden</a>
                </li>
                <li>
                  <a href="http://new.egalizer.hu/regi-seiko-arlistak/">Régi Seiko árlisták</a>
                </li>
              </ul>                  
            </li>			
        </ul>
    </li>
    <li>
      <a href="#" class="menulink">Névjegy</a>
      <ul>
        <li>
          <a href="http://www.egalizer.hu/nevjegy.htm">Bemutatkozás</a>
        </li>
        <li>
          <a href="http://www.egalizer.hu/szakdoga.htm">Krónikás</a>
        </li>
        <li>
          <a href="http://www.egalizer.hu/letolt.htm">Letöltés</a>
        </li>
        <li>
          <a href="http://www.egalizer.hu/linkek.htm">Linkek</a>
        </li>
      </ul>
    </li>
    <li>
      <a href="https://new.egalizer.hu" class="menulink" style="border-right: 1px solid #909090;">Kezdőlap</a>
    </li>
  </ul>
  <!-- Menü vége -->
</div>

  <p id="sweb_elements">
    <object id="footer">
      Sipos Róbert (2014)<br /> Az összeállításhoz használt oldalak:<br /> <a onclick="window.open(this.href);return false;"
        href="http://docs.oracle.com/javase/specs/jvms/se7/html/index.html">Java SE 7 specifikáció</a><br /> <a onclick="window.open(this.href);return false;"
        href="http://arhipov.blogspot.hu/2011/01/java-bytecode-fundamentals.html">Java bytecode fundamentals</a><br /> <a onclick="window.open(this.href);return false;"
        href="http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/">Bytecode</a><br /> <a onclick="window.open(this.href);return false;"
        href="http://www.javaworld.com/article/2077233/core-java/bytecode-basics.html">Bytecode basics</a><br /> <a onclick="window.open(this.href);return false;"
        href="http://www.pointsoftware.ch/de/under-the-hood-runtime-data-areas-javas-memory-model/">Java memory model</a><br /> <a onclick="window.open(this.href);return false;"
        href="http://java-espresso.blogspot.hu/2011/05/heap-structure-in-jvm.html">Heap structure in JVM</a><br /> <a onclick="window.open(this.href);return false;"
        href="https://blog.codecentric.de/en/2010/01/the-java-memory-architecture-1-act/">The Java memory architectrue</a><br /> <a onclick="window.open(this.href);return false;"
        href="http://www.artima.com/insidejvm/ed2/jvm8.html">JVM</a><br /> <a onclick="window.open(this.href);return false;"
        href="http://chrononsystems.com/blog/java-7-design-flaw-leads-to-huge-backward-step-for-the-jvm">Java 7 design flaw</a><br /> <a onclick="window.open(this.href);return false;"
        href="http://www.javaworld.com/article/2077647/build-ci-sdlc/make-java-fast--optimize-.html">Make Java fast</a>
    </object>
    <object id="buttons">
      <button title="tartalombutton" />
    </object>
  </p>
  <h2>Bevezetés</h2>
  <p class="essze_bevezetes">A Java a cikk írásának idején a statisztikák szerint a második legelterjedtebb és legnépszerűbb programozási nyelv (első a C). Elterjedtségének okai
    számosak, ezek egyike a nyelv és a futtatókörnyezet felépítése: a Java nyelven írt programok fordításának eredménye egy platformfüggetlen bináris adattömb, amit bájtkódnak nevezünk. A
    bájtkód maga a program egyfajta köztes állapotban. Hasonlóan, ahogy a C programokból a C fordító assembly kódot generál, a Java programokból a Java fordító bájtkódot állít elő. Minden
    Java osztályt ezután egy .class fájl reprezentál, ami a bájtkód utasításokat és az osztállyal kapcsolatos adatokat tartalmazza. Ezek a fájlok aztán dinamikusan töltődnek be a
    futtatókörnyezetbe (ezt a műveletet az ún. osztálybetöltő - class loader - végzi) és ott végrehajtódnak függetlenül attól, milyen operációs rendszer is van a környezet alatt.</p>
  <p class="bekezd">Ez a cikk azzal foglalkozik, hogyan is néz ki a bájtkód és rövid leírást ad arról is, hogyan történik a Java programok futtatása. A megértéshez szükség van a Java
    nyelv valamint az alapvető, programozással kapcsolatos fogalmak ismeretére. Habár vannak eszközök a Java programok közvetlen assembly formába való fordítására is, ezek jelentősége
    pillanatnyilag elhanyagolható, ezért ez a cikk sem foglalkozik vele. A nyelvhez nagyon sok nyílt forrású vagy kereskedelmi eszköz és futtatókörnyezet elérhető, de a cikk csak az Oracle
    (korábban Sun) megoldásait tárgyalja, mert jelenleg messze ezek a legelterjedtebbek. Minden, az összeállításhoz használt cikkből átvett példakód esetén változatlanul hagytam az eredeti
    angol elnevezéseket.</p>
  <p class="bekezd">
    Az itt közölt információk a <b>Java 7</b>-es verziójára vonatkoznak, habár a témával kapcsolatos szerteágazó irodalom összehangolása következtében előfordulhatnak pontatlanságok.
  </p>
  <h2>A Java Virtuális Gép</h2>
  <p class="bekezd">
    Az ábra bemutatja egy Java osztály fordítását és futtatását: a forrásfájl (<span class="programkod">HelloWorld.java</span>) .class fájllá fordítódik (<span class="programkod">HelloWorld.class</span>),
    ami aztán betöltődik a virtuális gépbe, ahol végrehajtódik.
  </p>
  <p class="kozep">
    <img alt="kep1" src="/informatika/essze/bytecode/kep1.png" />
  </p>
  <h2>Java osztályok fordítása és végrehajtása</h2>
  <p class="bekezd">
    A Java eleinte interpreteres programnyelv volt, ahol a <b>JVM (Java Virtuális Gép)</b> a bájtkódot közvetlenül, utasításonként hajtotta végre. A virtuális gép elnevezés találó, hiszen
    ahogy egy valódi hardver a gépi kódot, a virtuális gép a bájtkódot hajtja végre szekvenciálisan. A fordítók fejlődésével azonban már 1997 elején elérhető lett egy <b>JIT (Just In
      Time)</b> futtatókörnyezet a nyelvhez a Symantec jóvoltából, akkor még csak Windows platformra. A bájtkódot a JIT környezet lefordítja gépi kódra, de csak akkor, amikor az adott
    programrészt ténylegesen futtatni kell. A Sun az 1998 végén megjelenő 1.2-es verzióba ezt már licencelte és alapértelmezetten beépítette. A 2000 májusában megjelenő 1.3-as Java már egy
    új, <b>HotSpot</b> nevű futtatókörnyezetet tartalmazott, ami megpróbálta egyesíteni az interpretált megközelítés és a JIT előnyeit. A Sun (és ma már az Oracle) által kiadott minden
    további Java verzió a HotSpot továbbfejlesztett változatait használja. Mivel a kód logikailag továbbra is virtuális gépen fut, minden leírás ezt a kifejezést használja.
  </p>
  <p class="bekezd">Megjegyzendő, hogy a Java szónak valójában kétféle jelentése van: egyrészről a programozási nyelvet jelenti, másrészről a Java virtuális gépet, amire viszont nem
    feltétlenül csak Javában lehet programozni, hanem egyéb nyelvekben is, amelyekhez létezik bájtkód fordító. Amikor pedig Java virtuális gépről beszélünk, valójában három dolgot is
    érthetünk alatta:</p>
  <ul>
    <li>az absztrakt specifikációt</li>
    <li>egy adott implementációt vagy</li>
    <li>annak egy futó példányát</li>
  </ul>
  <p class="bekezd">A cikkben a szövegkörnyezetből mindig kiderül, hogy melyikről is van szó.</p>
  <p class="bekezd">Az egyik ok, amiért a JVM ilyen népszerű lett és ami miatt annyi különböző nyelv, fejlesztőkörnyezet, profiler, debugger és egyéb nagyszerű eszköz létrejött az, hogy
    a Java alapvetően interpretált nyelvnek készült és a JVM bájtkód eléggé egyszerű. Bárkit meg lehet tanítani a teljes tananyagra egy óra alatt, ezután pedig bárki képes használni egy ASM
    keretrendszert és módosítgatni a bájtkódot, mert az összes fordítóprogramokkal kapcsolatos fekete mágia a JVM HotSpot fordítójába került a javac helyett, ez pedig a futtatás során már
    pontos információkkal rendelkezik a használt hardver architektúráról, elérhető erőforrásokról és egyéb futtatási információkról, így sokkal hatékonyabb optimalizálást képes végezni,
    mint egy általános fordítóprogram).</p>
  <p class="bekezd">Sok kutatás foglalkozik a nyelv vagy a fordított programok futásidejű viselkedésének fejlesztésével. Bárki írhat plugint a rendszer osztálybetöltőjéhez, ami azért
    felelős, hogy a .class fájlokat futásidőben betöltse és átadja a bájtkódot a virtuális gépnek. A módosított osztálybetöltők használhatók arra, hogy elfogják a betöltési folyamatot és
    módosítsanak az osztályokon (viszonylag könnyen, hiszen a bájtkód egyszerű), mielőtt azok átadódnak végrehajtásra a JVM-nek. Mivel az eredeti class fájl mindig változatlan marad, az
    osztálybetöltő viselkedése akár minden végrehajtás előtt újrakonfigurálható vagy pedig dinamikusan változtatható.</p>
  <h2>A Java Virtuális Gép architektúrája</h2>
  <p class="bekezd">A bájtkód tárgyalásához előbb tisztázni kell a JVM absztrakt felépítését; a környezetet, ahol a kód futni fog.</p>
  <p class="bekezd">Amikor egy Java alkalmazás elindul (a java HelloWorld-től egészen egy asadmin start-domain --verbose-ig - ami egy Glassfish alkalmazásszervert indít el), egyetlen
    futásidejű virtuális gép jön létre. Amikor az alkalmazás futása befejeződik, a futó JVM életének is vége szakad. Ha három Java alkalmazást is elindítunk ugyanazon a gépen ugyanabban az
    időben ugyanazt a konkrét implementációt használva, akkor három JVM példányt kapunk, vagyis minden Java alkalmazás saját külön JVM-ben fut.</p>
  <p class="bekezd">Amint már említettem, minden JVM-nek van egy ún. osztálybetöltő alrendszere (class loader), ami futásidőben betölti a .class fájlokban tárolt típusokat (osztályok és
    interfészek). A JVM-en belül különböző memóriaterületek vannak:</p>
  <ul>
    <li><b>metódus terület</b>: amikor a JVM betölt egy .class fájlt, az abból kiolvasott, a típussal kapcsolatos bináris információk kerülnek erre a területre, így a bájtkód
      utasítások is. A szemétgyűjtő kezeli ezt a területet, hogy a szükségtelenné vált osztálydefiníciók törlésével helyet szabadítson fel. Az angol terminológiában permanent generation
      (PermGen) területként is hivatkoznak rá.</li>
    <li><b>heap</b>: a program futása során minden objektumpéldány erre a területre kerül, vagyis egy tulajdonképpeni referencia ezen a területen mutat valahová. A szemétgyűjtő
      (garbage collector) ezt a területet is kezeli. Mivel a tömbök is Java objektumok, ezek is itt tárolódnak.</li>
    <li><b>java vermek</b>: miden programszálban minden Java metódushívás állapota egy-egy verembe kerül. Az állapot tartalmazza a lokális változókat, a metódus paramétereit, esetleges
      visszatérési értékét és a belső számítások átmeneti adatait.</li>
    <li><b>regiszterek</b>: minden szálnak egy külön PC (utasításszámláló, program counter) regisztere van, ami megmutatja, hogy a bájtkódban (vagyis a metódus területen) épp melyik
      utasítást kell következőként végrehajtani. Külön regiszter mutatja a verem aktuális tetejét is.</li>
    <li><b>natív metódus vermek</b>: a natív (vagyis nem Java bájtkód, hanem például DLL) metódushívások adatai itt tárolódnak. Szerkezete nagyrészt implementációfüggő, ez a cikk nem
      tárgyalja.</li>
  </ul>
  <p class="bekezd">A metódus terület és a heap megosztott használatban van minden, a JVM-ben futó programszál között.</p>
  <h3>A metódus terület</h3>
  <p class="bekezd">A JVM-en belül a betöltött típusokhoz tartozó inforomáció az ún. metódus területen tárolódik. Amikor az osztálybetöltő betölt egy .class fájt, a tartalmát átadja a
    virtuális gépnek, amely feldolgozza és eltárolja azt a metódus területen. Az osztályban deklarált statikus változók is ide kerülnek. Mivel minden szál megosztva használja ezt a
    területet, ezért az itt lévő adatszerkezetek kezelését a programozónak kell szálbiztosra tervezni.</p>
  <h3>A konstanskészlet</h3>
  <p class="bekezd">A konstanskészlet a metódus területen foglal helyet, de fontossága miatt külön is érdemes tárgyalni. Osztálybetöltéskor a JVM minden betöltött típushoz lefoglal egy
    konstankészlet memóriaterületet a metódus területen. Ez valójában egy tömb adatszerkezet és a típushoz tartozó sztring, egész vagy lebegőpontos konstansokat, szimbolikus linkeket
    tárolja. A konstanskészlet elemeit azok indexével lehet elérni.</p>
  <h3>Vermek, veremkeret</h3>
  <p class="bekezd">A JVM veremalapú gép, nincsenek regiszterei átmeneti adatok tárolására, a bájtkód utasítások adattárolásra a vermet használják. (Ezt még a Java tervezői döntötték el
    és az volt az oka, hogy egyszerű maradjon a virtuális gép utasításkészlete és könnyű legyen implementálni olyan architektúrákon is, ahol kevés általános célú regiszter van vagy azok
    kezelése eltér a megszokottól. Ezen kívül lehetővé teszi a JIT fordító számára a futásidejű optimalizálást is.) A java vermek ún. veremkeretekből (stack frame) állnak. Minden
    alkalommal, amikor egy metódus meghívódik, egy új veremkeret jön létre, ami a metódus-futtatás állapotát tárolja. Amikor a metódus véget ér (normál befejeződéssel vagy kivétel dobása
    miatt), a hozzá tartozó veremkeret is megszűnik, az aktuális veremkeret pedig a hívó metódus veremkerete lesz, ahová visszakerül a vezérlés.</p>
  <p class="bekezd">A Java vermek kezelése látható a következő ábrán három programszál esetén (az első kettő Java programot futtat, a harmadik natív metódust):</p>
  <p class="kozep">
    <img alt="stacks" src="/informatika/essze/bytecode/stacks.gif" />
  </p>
  <p class="bekezd">Egy szálhoz tartozó metódus csak a saját utasításszámlálóját és veremkeretét érheti el, ez pedig biztosítja, hogy ha több szál futtatja ugyanazt a metódust (a
    metódusok lokális változói külön veremkeretbe kerülnek), nincs szükség külön szinkronizálásra. Az ábrán a vermek lefelé nőnek, minden verem &quot;teteje&quot; az ábra alján van. A
    jelenleg futó metódusok veremkeretei világosabb szürke háttérrel vannak ábrázolva. Azon metódusok esetén, amelyek Java kódot futtatnak, a programszámláló a következő utasításra mutat.
    Mivel a harmadik szál natív metódust futtat, programszámlálója (sötétszürkével jelölve) nem definiált.</p>
  <p class="bekezd">Egy veremkeretnek három része van:</p>
  <ul>
    <li>lokális változók tömbje</li>
    <li>operandus verem</li>
    <li>keret adatok</li>
  </ul>
  <p>
    <b>Lokális változók</b>
  </p>
  <p class="bekezd">A lokális változók tömbben tárolódnak, melynek mérete fordítási időben dől el. Minden utasítás, ami lokális változót akar használni, egy indexet tartalmaz, ami
    kijelöli a változót ebben a tömbben (az indexek 0-val kezdődnek). Egy int, float, referencia és returnAddress típusú elem egy, long és double típusú elem pedig két bejegyzést foglal el
    ebben a tömbben. (A returnAddress belsőleg használt primitív típus, amit a JVM a finally blokk megvalósításához használ. A programozó számára nem elérhető. Két bejegyzést elfoglaló
    érték eléréséhez az első bejegyzés indexét használja az adott opkód.) A byte, short és char típusú értékek int típussá konvertálódnak veremkeretre tárolás előtt. Amikor ezeket az
    értékeket a JVM visszaírja a heap-re, akkor visszakonvertálódnak eredeti típusúvá. A boolean típusú értékeket a JVM minden belső tárolásnál int típusként kezeli.</p>
  <p class="bekezd">
    A lokális változók tömbje 0-tól 65535-ig indexelődik, tehát elméletileg 65536 lokális változónk lehet metódusonként (példányszintű metódusoknál egyel kevesebb, lásd lejjebb). A hívó
    metódus veremkerete átlapolódik, vagyis a hívó az argumentumokat az operandus veremre teszi és a meghívott metódus ezeket helyi változóként éri el, a lokális változótömb tartalmazza
    ugyanis a metódus helyi változóin kívül a paramétereket is. A fordító a paramétereket teszi először a tömbbe abban a sorrendben, ahogyan a metódus leírásában definiáltak. Így például: <img
      alt="method" src="/informatika/essze/bytecode/method.png" class="jobb" />
  </p>
  <pre class="programkod">
class Methods {
    public static int classMethod(int i, long l, float f,
      double d, Object o, byte b) {
        return 0;
    }
    public int instanceMethod(char c, double d, short s,
      boolean b) {
        return 0;
    }
}
</pre>
  <p class="bekezd">Amint az ábrából is látható, az instanceMethod() első paramétere referencia típusú, habár ilyen paraméter nem látható a kódban. Ez a rejtett this referencia a
    példánymetódusoknál jelenik meg, amelyek ezt a referenciát használják arra, hogy annak az objektumnak a példányadatait érjék el, amelyiken meghívódtak. Ahogyan az ábrán látható,
    statikus metódusoknál nincs ilyen paraméter, ezek csak az osztály statikus mezőit érik el. Az objektumok referenciaként adódnak át, tehát a heap-en tárolt objektumokról sosem található
    másolat a helyi változók között vagy a vermen, csak annak referenciájáról.</p>
  <p class="bekezd">A metódus paramétereitől eltérően a lokális változók sorrendje nem kötött, a tömbben a paraméterek után bármilyen sorrendben elhelyezkedhetnek, egy pozíciót pedig
    akár két különböző változó is használhat, ha hatáskörük nem fedi egymást. A pontos pozíciókat ebben az esetben is a fordító határozza meg.</p>
  <div class="keretes">
    <p>Akárcsak a többi memóriaterület esetén, a JVM specifikációja nem mondja meg, hogy a Java típusokhoz egy adott architektúrán milyen típusok feleljenek meg, ez mindig az adott JVM
      implementáció tervezőire van bízva. Ha tehát egy implementáció 64 bites szóhosszt használó processzoron fut, akkor a long vagy double típusokat a lokális változók tömbjében akár
      egyetlen bejegyzésben is lehet tárolni, ilyenkor a második bejegyzés üres marad (mert a JVM specifikáció csak azt mondja meg, hogy két bejegyzés szükséges a tároláshoz).</p>
  </div>
  <p>
    <b>Operandus verem</b>
  </p>
  <p class="bekezd">
    Akárcsak a lokális változók, az operandus verem is tömbként van szervezve és LIFO elven működik, mérete fordítási időben dől el. A bájtkódban - ahogy a neve is mutatja - minden egyes
    utasítást egy bájt reprezentál, ezt a bájtot opkódnak hívják. Az <span class="programkod">aload_0</span> utasítás opkódja például 0x2A. Egyes utasítások esetén az operandus az utasítást
    követi a bájtkódban vagy pedig a konstanskészletből olvasódik ki, de az operandusok helye legtöbb esetben az operandus verem. Sok utasítás leemel operandus(oka)t a veremről, műveletet
    végez vele (velük) és az eredményt visszateszi a veremre. Egy összeadás például a következőképp néz ki:
  </p>
  <pre class="programkod">  iload_0  //a 0. indexen lévő helyi változót a veremre helyezi
  iload_1  //az 1. indexen lévő helyi változót a veremre helyezi.
  iadd     //levesz a veremről két egész értéket, összeadja ezeket majd visszateszi az eredményt
  istore_2 // levesz a veremről egy egész értéket és a 2-es indexen lévő helyre teszi
</pre>
  <p class="kozep">
    <img alt="verem1" src="/informatika/essze/bytecode/verem1.png" />
  </p>
  <p class="bekezd">Az operandus verembe kerülnek a metódusok visszatérési értékei is.</p>
  <p>
    <b>Keret adatok</b>
  </p>
  <p class="bekezd">A lokális változók és az operandus verem mellett a veremkeret speciális adatokat is tárol, amelyek kellenek a metódus végrehajtásához és a kivételkezeléshez. Ezeket
    nevezzük keret adatoknak.</p>
  <p class="bekezd">A JVM sok utasítása hivatkozik a konstanskészlet bejegyzéseire, néhány utasítás közvetlenül ebből az adatszerkezetből helyez adatokat a veremre vagy ebből nyeri ki
    azokat az adatokat, amelyeket példányosításhoz, mező eléréshez vagy metódushíváshoz használ. Ezért a keret adatok tartalmaznak egy mutatót a konstanskészletre.</p>
  <p class="bekezd">Az adatok tartalmaznak egyfajta referenciát a metódus kivételtáblájára is, amit a JVM arra használ, hogy feldolgozza a futás során dobott kivételeket (bővebben
    lejjebb) valamint tartalmazhatnak egyéb adatokat is, amelyek a metódushívást vagy a nyomkövetést segítik. Pontos szerkezete implementációfüggő.</p>
  <table class="imgtable" frame="below" cellpadding="3px" cellspacing="0" style="clear: both; margin: auto;">
    <tr>
      <td style="width: 100%"><img alt="kep2" src="/informatika/essze/bytecode/kep2.png" /></td>
    </tr>
    <tr>
      <td style="width: 100%">A veremkeret elvi ábrázolása</td>
    </tr>
  </table>
  <h2>Memóriaszerkezet áttekintés</h2>
  <p class="bekezd">Az eddig leírtak érthetőbbé teszik az alábbi JVM memóriaszerkezeti ábrát. Az ábrán főként az eredeti angol elnevezéseket használom, azonban a részletezésben ezeknek
    megadom a magyar megfelelőit is.</p>
  <p class="kozep">
    <img alt="memory" src="/informatika/essze/bytecode/memory.png" />
  </p>
  <p class="bekezd">Amint látható, minden fentebb tárgyalt terület több kisebb részre oszlik. Az alkalmazás memóriahasználata szempontjából a legfontosabb a heap terület és a metódus
    terület. A több részre való osztás oka főként a szemétgyűjtő működése, az alábbi részletezés erre is kitér.</p>
  <ul>
    <li><b>Új terület (young generation)</b>: ide kerülnek az újonnan létrehozott objektumok, mérete a JVM-nek adott paraméterekkel állítható (NewSize és MaxNewSize)</li>
    <li><b>Éden terület</b>: minden objektum, ami metódusokban vagy osztályok mezőihez létrejön, itt kezdi életciklusát. A metódusokon belül használt objektumok általában megszűnnek a
      metódus véget érésével, néhány objektum viszton tovább létezik, ha mutat rá referencia objektumok mezőjeként. Ha az éden terület elkezd betelni, akkor egy kisebb szemétgyűjtő művelet
      indul, ami az élő objektumokat átmozgatja a túlélő területekre, hogy hely szabaduljon fel az újonnan létrehozott objektumoknak.</li>
    <li><b>Túlélő (survivor) területek</b>: mielőtt a szemétgyűjtő a még élő objektumokat átmozgatná a megtartott területre, a túlélő területeken gyűjti össze. Miután az itt lévő
      objektumok &quot;túléltek&quot; megadott számú szemétgyűjtési ciklust, átkerülnek a megtartott területre.</li>
    <li><b>Régi (old generation) és megtartott (tenured) terület</b>: olyan objektumok tárolódnak itt, amelyek túlélték a kisebb szemétgyűjtési ciklusokat (minor garbage collection) és
      eléggé régóta mutat rájuk használt referencia. Ezen a területen nagyobb szemétgyűjtési ciklus (major garbage collection) fut. A ciklusok magjában illetve metódusok törzsében létrejött
      lokális hatókörű objektumok sosem kerülnek át erre a területre.</li>
    <li><b>Virtuális területek</b>: a JVM memóriahasználatát konfigurálni lehet, minden fő területre be lehet állítani kezdeti értéket (ennyi memóriát foglal le induláskor a JVM) és
      maximális értéket (ennyi memóriát foglal le legfeljebb a JVM). A kettő közötti különbség a virtuális, vagyis a használatlan terület.</li>
    <li><b>Állandó (permanent generation) terület</b>: a korábban már tárgyalt metódus terület, ahol az osztályok definícióinak betöltése és megszüntetése zajlik. Futásidejű
      konstanskészlet (constant pool), a mezők és metódusok adatai (field and method data) és a bájtkód. (Amint Henrik Stahl, a Java Platform Group <a
      onclick="window.open(this.href);return false;" href="https://blogs.oracle.com/java/entry/java_7_questions_answers">termékmanagere is írta,</a> a Java 8-ban a memóriakezelés
      átszervezése miatt ez a terület megszűnt.)</li>
    <li><b>Natív terület</b>: a JVM belső műveleteihez használt. Külső könyvtárak betöltésére szánt terület, valamint a kódfordításhoz használt memória. Itt van a verem is, tehát ide
      kerülnek a szálak veremkeretei. A mérete (egy-két kivételtől eltekintve - mint például a verem) JVM kapcsolóval közvetlenül nem módosítható.</li>
  </ul>
  <p class="bekezd">Egy konkrét osztályt használva a memóriaszervezés a következőképpen néz ki:</p>
  <pre class="programkod">import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Logger;

public class HelloWorld {
 private static Logger LOGGER=Logger.getLogger(HelloWorld.class.getName());
 public void sayHello(String message){
  SimpleDateFormat formatter=new SimpleDateFormat(&quot;YYYY.MM.dd&quot;);
  String today=formatter.format(new Date());
  LOGGER.info(today+&quot;: &quot;+message);
}
</pre>
  <p class="bekezd">A memóriabeli tartalom:</p>
  <p class="kozep">
    <img alt="pelda" src="/informatika/essze/bytecode/pelda.png" />
  </p>
  <div class="keretes">
    <h3>OutOfMemoryError: de akkor melyik is?</h3>
    <p>Némi rálátással a JVM memóriakezelésére már könnyebben megérthető, mi is okozza az időnként felmerülő OutOfMemoryError kivételeket.</p>
    <ul>
      <li><span class="programkod">Exception in thread &quot;main&quot;: java.lang.OutOfMemoryError: Java heap space</span>: új objektum már nem hozható létre a heap területen</li>
      <li><span class="programkod">Exception in thread &quot;main&quot;: java.lang.OutOfMemoryError: Requested array size exceeds VM limit</span>: új tömb létrehozásának kísérlete
        olyan mérettel, ami nem fér el a heap területen.</li>
      <li><span class="programkod">Exception in thread &quot;main&quot;: java.lang.OutOfMemoryError: PermGen space</span>: újabb osztályok és metódusok már nem tölthetőek a metódus
        területre. Általában akkor fordul elő, ha túl sok külső könyvtárat használ a program vagy az osztálybetöltőben memóriaszivárgásos programhiba van.</li>
      <li><span class="programkod">Exception in thread &quot;main&quot;: java.lang.OutOfMemoryError: unable to create new native thread</span>: túl sok szál van a JVM-ben és már nincs
        elég memória új létrehozásához. Előfordulhat, hogy már túl sok fájl van megnyitva.</li>
      <li><span class="programkod">Exception in thread &quot;main&quot;: java.lang.OutOfMemoryError: &lt;reason&gt; &lt;stacktrace&gt; (Native method)</span>: nem sikerült a
        memóriafoglalás a natív JVM veremben (például JNI - vagyis külső C vagy C++ metódushívás esetén). Leginkább a natív kódban, nem pedig a JVM-ben lévő problémát jelez.</li>
      <li><span class="programkod">Exception in thread &quot;main&quot;: java.lang.OutOfMemoryError: request &lt;size&gt; bytes for &lt;reason&gt;. Out of swap space?</span>: az
        operációs rendszer szintjén fogyott el a memória. Nem feltétlenül Java problémát jelent, lehetséges, hogy más futó program használta el a teljes szabad memóriát.</li>
      <li><span class="programkod">Exception in thread &quot;main&quot;: java.lang.OutOfMemoryError: GC overhead limit exceeded</span>: ha a JVM működésének már 98%-át a szemétgyűjtő
        futtatása teszi ki, miközben a felszabadított terület mérete érdemben nem nő. Akkor fordul elő, amikor egy program rövid idő alatt olyan nagy mennyiségű objektumot hoz létre, ami
        már feszegeti a heap terület határait.</li>
    </ul>
    <p>
      És még egy érdekesség: a JVM vermén előforduló memóriafoglalási hiba (ha túl sok veremkeret van már a JVM veremben) nem <span class="programkod">OutOfMemoryError</span> kivételt dob,
      hanem <span class="programkod">java.lang.StackOverflowError</span>-t.
    </p>
  </div>
  <h2>Java .class fájlformátum</h2>
  <p class="kozep">
    <img alt="classfile" src="/informatika/essze/bytecode/classfile.png" />
  </p>
  <p class="bekezd">Az ábra bemutatja egy Java .class fájl egyszerűsített felépítését. A fájl a fejléccel kezdődik, ami az ún. mágikus számot (0xCAFEBABE) és egy verziószámot tartalmaz.
    Ezt követi a konstanskészlet, az osztály elérési jogai bitmaszkos reprezentációban, az általa implementált interfészek listája, az osztály által tartalmazott mezők és metódusok, végül
    pedig az attribútumok, mint például a SourceFile attribútum, ami a forrásfájl helyét adja meg. Az attribútumok lehetőséget adnak arra, hogy kiegészítő, felhasználó által definiált
    információt adjunk a .class fájl adatstruktúrájához. Egy saját osztálybetöltő például kiértékelhet egy ilyen attribútumot, hogy bizonyos átalakításokat végezzen a bájtkódon. A JVM
    specifikációja azt mondja, hogy minden virtuális gép implementációnak figyelmen kívül kell hagynia az ismeretlen (például a felhasználó által definiált) attribútmokat.</p>
  <p class="bekezd">Mivel az összes olyan információ, ami ahhoz szükséges, hogy futásidőben feloldjuk az osztályreferenciákat, mezőket és metódusokat sztring konstansokban van elmentve,
    a konstans pool valójában egy átlagos .class fájl nagyjából 60%-át elfoglalja. Maguk a bájtkód utasítások átlagosan csak 12%-ot foglalnak el.</p>
  <p class="bekezd">Az ábra jobb felső doboza a konstanskészlet egy változatát mutatja, az alatta lévő lekerekített doboz pedig a példaosztály egyik metódusának utasításait tartalmazza.
    Ez a metódus egy szokványos műveletet végez el:</p>
  <p class="programkod">System.out.println(&quot;Hello, world&quot;);</p>
  <p class="bekezd">
    Az első utasítás betölti a <span class="programkod">java.lang.System</span> osztály out mezőjének tartalmát az operandusverembe. Ez a <span class="programkod">java.io.PrintStream</span>
    osztály egy példánya. Az &quot;ldc&quot; (konstans betöltése) a &quot;Hello world&quot; sztring referenciáját helyezi a veremre. A következő utasítás meghívja a println példánymetódust,
    ami mindkét értéket paraméterben kapja (a példánymetódusok mindig implicit módon a példány referenciát kapják nulladik paraméterként).
  </p>
  <p class="bekezd">A class fájlban lévő utasítások, egyéb adatstruktúrák és maguk a konstansok is hivatkozhatnak más elemekre a konstanskészletben. Ilyen referenciák fix indexeket
    használnak, amik közvetlenül az utasításokba vannak kódolva. Ezek az ábrán bekeretezve láthatóak.</p>
  <p class="bekezd">
    Az invokevirtual utasítás például egy CONSTANT_MethodRef_info (röviden MethodRef) konstanskészlet-bejegyzésre hivatkozik, ami a hívott metódus nevéről tartalmaz információkat, annak az
    aláírásáról (argumentumok, visszatérési érték típusa) és hogy melyik osztályhoz tartozik. Valójában, ahogy a bekeretezett érték mutatja, a MethodRef konstans csak egyéb bejegyzésekre
    hivatkozik, amelyek már a valódi adatokat tartalmazzák. Hivatkozik például a ConstantClass bejegyzésre, ami szimbolikus linket tartalmaz a <span class="programkod">java.io.PrintStream</span>
    osztályra. Hogy a class fájl mérete kicsi maradjon, ilyen konstansok általában meg vannak osztva különböző utasítások és egyéb konstanskészletbeli bejegyzések között. Ehhez hasonlóan
    egy mezőt egy Fieldref konstans reprezentál, ami adatokat tartalmaz a nevéről, típusáról és az azt tartalmazó osztályról.
  </p>
  <p class="bekezd">A konstanskészlet alapvetően a következő típusú bejegyzéseket tartalmazza: referenciák metódusokra, mezők és osztályok, sztringek, integer-ek, float-ok, long-ok és
    double-k.</p>
  <h3>Fájlformátum</h3>
  <p class="bekezd">Az alábbi táblázat részletesen bemutatja a .class fájl felépítését. Az első oszlopban található az adott rész bájtokban adott mérete, a másodikban a Java
    specifikációjában használt kódnév, a harmadikban pedig rövid leírás.</p>
  <table class="datatable">
    <thead class="datatable">
      <tr>
        <th>Méret</th>
        <th>Kód</th>
        <th>Leírás</th>
      </tr>
    </thead>
    <tbody>
      <tr class="tr1">
        <td>4</td>
        <td>magic</td>
        <td>0xCAFEBABE</td>
      </tr>
      <tr class="tr2">
        <td>2</td>
        <td>minor_version</td>
        <td>A fájlformátum alverziója</td>
      </tr>
      <tr class="tr1">
        <td>2</td>
        <td>major_version</td>
        <td>A fájlformátum főverziója. J2SE 8 esetén 52 (0x34), J2SE 7 esetén 51 (0x33), J2SE 6 esetén 50 (0x32).</td>
      </tr>
      <tr class="tr2">
        <td>2</td>
        <td>constant_pool_count</td>
        <td>A konstanskészletbeli bejegyzések száma</td>
      </tr>
      <tr class="tr1">
        <td>cp_info</td>
        <td>constant_pool[constant_pool_count-1]</td>
        <td>Konstanskészlet bejegyzések. Indexelésük 1-től indul, mert a 0-s index speciális célokra van fenntartva.</td>
      </tr>
      <tr class="tr2">
        <td>2</td>
        <td>access_flags</td>
        <td>A fájlban tárolt osztály vagy interface elérési jogainak bitmaszkja. Azt is megmutatja, hogy a fájlban osztály, interface vagy enum tárolódik-e.</td>
      </tr>
      <tr class="tr1">
        <td>2</td>
        <td>this_class</td>
        <td>Konstanskészletbeli index, ami egy CONSTANT_Class_info szerkezetet tárol.</td>
      </tr>
      <tr class="tr2">
        <td>2</td>
        <td>super_class</td>
        <td>Értéke 0 vagy egy konstanskészletbeli index. Ha nem 0, akkor értéke egy, a közvetlen ősosztályt reprezentáló CONSTANT_Class_info szerkezetre mutat. Egyetlen ősosztálynak
          sem lehet beállítva az ACC_FINAL flag-je az access_flags mezőben. Ha értéke 0, akkor ez a .class fájl az Object osztályt tartalmazza, aminek nincs ősosztálya. Interfészek esetén
          mindig egy konstanskészletbeli index, ami az Object-et reprezentáló CONSTANT_Class_info struktúrára mutat.</td>
      </tr>
      <tr class="tr1">
        <td>2</td>
        <td>interfaces_count</td>
        <td>Az osztály vagy interfész által implementált közvetlen interfészek listája.</td>
      </tr>
      <tr class="tr2">
        <td>2*interfaces_count</td>
        <td>interfaces[interfaces_count]</td>
        <td>Minden egyes elem konstanskészletbeli index, ami egy CONSTANT_Class_info szerkezetre mutat.</td>
      </tr>
      <tr class="tr1">
        <td>2</td>
        <td>fields_count</td>
        <td>A field_info szerkezet bejegyzéseinek száma.</td>
      </tr>
      <tr class="tr2">
        <td>field_info</td>
        <td>fields[fields_count]</td>
        <td>Minden eleme leírja az osztály vagy interfész egy mezőjének tulajdonságait. Mind az osztályszintű, mind a példányszintű mezőket tartalmazza (kivéve az öröklötteket).</td>
      </tr>
      <tr class="tr1">
        <td>2</td>
        <td>methods_count</td>
        <td>A method_info szerkezet bejegyzéseinek száma.</td>
      </tr>
      <tr class="tr2">
        <td>method_info</td>
        <td>methods[methods_count]</td>
        <td>Minden bejegyzése az osztály által megvalósított egy metódusról tartalmaz információkat (az öröklött metódusokról nem). Amennyiben a metódushoz tartozó elérési
          jogosultságok között nincs bekapcsolva az ACC_NATIVE vagy az ACC_ABSTRACT flag, akkor a metódus bájtkódját is ez tartalmazza.</td>
      </tr>
      <tr class="tr1">
        <td>2</td>
        <td>attributes_count</td>
        <td>Az attributes listában szereplő bejegyzések száma.</td>
      </tr>
      <tr class="tr2">
        <td>attribute_info</td>
        <td>attributes[attributes_count]</td>
        <td>Az osztályhoz tartozó kiegészítő attribútumok, mint például a belső osztályok, a forrásfájl helye, annotációk, stb.</td>
      </tr>
    </tbody>
  </table>
  <h3>Metódus kód</h3>
  <p class="bekezd">Minden konstanskészletbeli bejegyzés egy egybájtos címkéből és az azt követő bájttömből áll. A címke határozza meg a bájttömb értelmezését. Néhány típus:</p>
  <ul>
    <li>Ha a címke értéke 1, akkor a következő bájttömb egy CONSTANT_Utf8 szerkezet, ami első két bájtjában szerkezet bájtokban számolt hosszát adja meg, ezt követi maga a tartalom:
      UTF8 karakterek.</li>
    <li>Ha a címke értéke 10, akkor a következő bájttömb egy CONSTANT_Methodref szerkezet, ami két kétbájtos indexet tartalmaz, első egy CONSTANT_Class_info szerkezetre mutat, ami a
      metódus osztályát tartalmazza, a második pedig egy CONSTANT_NameAndType_info szerkezetre, ami a metódus nevét és paraméterlistáját tartalmazza.</li>
  </ul>
  <p class="bekezd">
    A .class fájl teljes specifikációja az <a onclick="window.open(this.href);return false;" href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1">Oracle
      dokumentációjában</a> megtalálható, jelen cikk csak a method_info struktúra részletezésére tér ki. Ez látható a következő táblázatban.
  </p>
  <table class="datatable">
    <thead class="datatable">
      <tr>
        <th>Méret</th>
        <th>Kód</th>
        <th>Leírás</th>
      </tr>
    </thead>
    <tbody>
      <tr class="tr1">
        <td>2</td>
        <td>access_flags</td>
        <td>A metódushoz tartozó jogosultság bitmaszkja.</td>
      </tr>
      <tr class="tr2">
        <td>2</td>
        <td>name_index</td>
        <td>Konstanskészletbeli index, egy CONSTANT_Utf8_info struktúrára mutat, ami a metódus nevét tartalmazza. Konstruktorok esetén ez a név &lt;init&gt;, statikus konstruktorok
          esetén &lt;clinit&gt;, egyéb esetben pedig az, amit az osztály fejlesztője megadott. A konstruktorok fix elnevezése nem okoz problémát, mert ilyen nevet a Java programkódban nem
          lehet megadni.</td>
      </tr>
      <tr class="tr1">
        <td>2</td>
        <td>descriptor_index</td>
        <td>Konstanskészletbeli index, ami a metódus deszkriptorára mutat. Ez tartalmazza a metódus paramétereinek és visszatérési értékének leírását.</td>
      </tr>
      <tr class="tr2">
        <td>2</td>
        <td>attributes_count</td>
        <td>Az attributes listában szereplő bejegyzések száma.</td>
      </tr>
      <tr class="tr1">
        <td>attribute_info</td>
        <td>attributes[attributes_count]</td>
        <td>A metódushoz tartozó attribútumok.</td>
      </tr>
    </tbody>
  </table>
  <p class="bekezd">Az attributes lista szerkezete a következő:</p>
  <table class="datatable">
    <thead class="datatable">
      <tr>
        <th>Méret</th>
        <th>Kód</th>
        <th>Leírás</th>
      </tr>
    </thead>
    <tbody>
      <tr class="tr1">
        <td>2</td>
        <td>attribute_name_index</td>
        <td>Konstanskészletbeli index, ami egy CONSTANT_Utf8_info szerkezetre mutat. Az adott attribútum típusát jelöli. Nem absztrakt (és nem natív) metódusok esetén ez
          &quot;Code&quot;.</td>
      </tr>
      <tr class="tr2">
        <td>4</td>
        <td>attribute_length</td>
        <td>Az info szerkezet mérete bájtokban</td>
      </tr>
      <tr class="tr1">
        <td>1</td>
        <td>info[attribute_length]</td>
        <td>Az attribútum információja. &quot;Code&quot; attribútum esetén a metódus veremkeretének maximális mérete, a lokális változók száma és a bájtkód utasítások tömbje. A lokális
          változók neveiről valamint a forrásfájlbeli sorszámokról is tartalmazhat információt, ezeket a debuggerek használják, de ezek megléte opcionális. Ha a forrást <span
          class="programkod">-g:none</span> kapcsolóval fordítjuk, akkor ezek az információk nem kerülnek a .class fájlba.
        </td>
      </tr>
    </tbody>
  </table>
  <h3>Példakód</h3>
  <p class="bekezd">Ez az alfejezet egy .class fájl vizsgálatát tartalmazza a fenti leírás alapján. A példaosztály a lehető legegyszerűbb:</p>
  <pre class="programkod">public class HelloWorld {
  public void process() {
    System.out.println(&quot;Hello World!&quot;);
  }
}
</pre>
  <p class="bekezd">
    Miután ezt <span class="programkod">javac -g:none</span> paranccsal lefordítjuk, a következő 319 bájtos fájl jön létre (hexa editor nézetben megtekintve, a számjegyként és betűként
    értelmezhetetlen karakterek helyén _ áll):
  </p>
  <p class="kozep">
    <img alt="helloclass" src="/informatika/essze/bytecode/classsample.png" />
  </p>
  <p class="bekezd">
    A fájl tartalmának elemzése a fenti információk alapján (bővebb elemzése szöveges fájlban <a href="./elemzes.txt">letölthető innen</a>):
  </p>
  <table class="datatable">
    <thead class="datatable">
      <tr>
        <th>Pozíció</th>
        <th>Méret</th>
        <th>Leírás</th>
      </tr>
    </thead>
    <tbody>
      <tr class="tr1">
        <td>0</td>
        <td>4</td>
        <td>0xCAFEBABE - a &quot;mágikus szám&quot;</td>
      </tr>
      <tr class="tr2">
        <td>4</td>
        <td>2</td>
        <td>az alverzió értéke: 0</td>
      </tr>
      <tr class="tr1">
        <td>6</td>
        <td>2</td>
        <td>a főverzió értéke: 0x33, vagyis J2SE7 fordítóval készült class fájlról van szó</td>
      </tr>
      <tr class="tr2">
        <td>8</td>
        <td>2</td>
        <td>a konstanskészletbeli bejegyzések száma+1: 0x19 vagyis 25</td>
      </tr>
      <tr class="tr1">
        <td>10</td>
        <td>231</td>
        <td>a konstanskészletbeli bejegyzések</td>
      </tr>
      <tr class="tr2">
        <td>10</td>
        <td>5</td>
        <td>1. konstansbejegyzés. A 10. bájtpozíción 0xA vagyis 10 áll, ami megmutatja, hogy ez egy CONSTANT_Methodref_info bejegyzés</td>
      </tr>
      <tr class="tr1">
        <td>15</td>
        <td>5</td>
        <td>2. konstansbejegyzés. A 15. bájtpozíción 9 áll, ami megmutatja, hogy ez egy CONSTANT_Fieldref_info bejegyzés</td>
      </tr>
      <tr class="tr2">
        <td>20</td>
        <td>3</td>
        <td>3. konstansbejegyzés. A 20. bájtpozíción 8 áll, ami megmutatja, hogy ez egy CONSTANT_String_info bejegyzés</td>
      </tr>
      <tr class="tr1">
        <td>23</td>
        <td>5</td>
        <td>4. konstansbejegyzés: CONSTANT_Methodref_info</td>
      </tr>
      <tr class="tr2">
        <td>28</td>
        <td>3</td>
        <td>5. konstansbejegyzés. A 28. bájtpozíción 7 áll, ami megmutatja, hogy ez egy CONSTANT_Class_info bejegyzés</td>
      </tr>
      <tr class="tr1">
        <td>31</td>
        <td>3</td>
        <td>6. konstansbejegyzés: CONSTANT_Class_info</td>
      </tr>
      <tr class="tr2">
        <td>34</td>
        <td>32</td>
        <td>7.-10. konstansbejegyzések. Mindegyik CONSTANT_Utf8_info típusú. Értékeik: &quot;&lt;init&gt;&quot;, &quot;()V&quot;, &quot;Code&quot;, &quot;process&quot;</td>
      </tr>
      <tr class="tr1">
        <td>66</td>
        <td>5</td>
        <td>11. konstansbejegyzés. A 66. bájtpozíción 0xC vagyis 12 áll, ami megmutatja, hogy ez egy CONSTANT_NameAndType_info bejegyzés</td>
      </tr>
      <tr class="tr2">
        <td>71</td>
        <td>31</td>
        <td>12.-16. konstansbejegyzések.</td>
      </tr>
      <tr class="tr1">
        <td>102</td>
        <td>137</td>
        <td>17.-24. konstansbejegyzések. Mindegyik CONSTANT_Utf8_info típusú. Értékeik: &quot;HelloWorld&quot;, &quot;java/lang/Object&quot;, &quot;java/lang/System&quot;,
          &quot;out&quot;, &quot;Ljava/io/PrintStream;&quot;, &quot;java/io/PrintStream&quot;, &quot;println&quot;, &quot;(Ljava/lang/String;)V&quot;</td>
      </tr>
      <tr class="tr2">
        <td>239</td>
        <td>2</td>
        <td>Jogosultsági flagek.</td>
      </tr>
      <tr class="tr1">
        <td>241</td>
        <td>2</td>
        <td>Konstanskészlet-beli index a this osztályhoz: 5. Ezen az indexen egy CONSTANT_Class_info bejegyzés áll, aminek egyetlen értéke van: egy index az osztály nevére. Ennek
          értéke 0x11, vagyis a 17. konstansra mutat, ami pedig a &quot;HelloWorld&quot; karaktersorozat (a 105. pozíción kezdődik).</td>
      </tr>
      <tr class="tr2">
        <td>243</td>
        <td>2</td>
        <td>Konstanskészletbeli index az ősosztályhoz: 6. Ezen az indexen egy CONSTANT_Class_info bejegyzés áll, aminek egyetlen értéke van: egy index az osztály nevére. Ennek értéke
          0x12, vagyis a 18. konstansra mutat, ami pedig a &quot;java/lang/Object&quot; karaktersorozat, vagyis az osztály az Object osztályból származik.</td>
      </tr>
      <tr class="tr1">
        <td>245</td>
        <td>2</td>
        <td>Az osztály által implementált interface-ek száma. Ez esetben 0.</td>
      </tr>
      <tr class="tr2">
        <td>247</td>
        <td>2</td>
        <td>Az osztály mezőinek száma. Ez esetben 0.</td>
      </tr>
      <tr class="tr1">
        <td>249</td>
        <td>2</td>
        <td>Az osztály metódusainak száma. Ez esetben 2 (konstruktor és a process).</td>
      </tr>
      <tr class="tr2">
        <td>251</td>
        <td>66</td>
        <td>A metódusok tartalma.</td>
      </tr>
      <tr class="tr1">
        <td>251</td>
        <td>2</td>
        <td>A metódus elérési jogosultságainak bitmaszkja.</td>
      </tr>
      <tr class="tr2">
        <td>253</td>
        <td>2</td>
        <td>A metódus nevének konstans-indexe: 7. Ez pedig az &lt;init&gt;, vagyis az alapértelmezett konstruktor.</td>
      </tr>
      <tr class="tr1">
        <td>255</td>
        <td>2</td>
        <td>Metódusleíró konstanskészletbeli indexe. Itt 8, ami a következő sztringet tartalmazza: &quot;()V&quot;. Ez azt jelenti, hogy a metódusnak nincsenek paraméterei és
          &quot;V&quot;, vagyis void a visszatérési értéke.</td>
      </tr>
      <tr class="tr2">
        <td>257</td>
        <td>2</td>
        <td>Attribútumok száma: 1</td>
      </tr>
      <tr class="tr1">
        <td>259</td>
        <td>2</td>
        <td>Az első attribútum neve: index a konstanskészletben: 9, vagyis &quot;Code&quot;. Ez mutatja, hogy az attribútum a bájtkódot tartalmazza (néhány, a JVM számára szükséges
          kiegészítő információval együtt).</td>
      </tr>
      <tr class="tr2">
        <td>261</td>
        <td>4</td>
        <td>Az attribútum hossza: 0x11, vagyis 17 bájt.</td>
      </tr>
      <tr class="tr1">
        <td>265</td>
        <td>17</td>
        <td>Az attribútum tartalma: ez maga a bájtkód.</td>
      </tr>
      <tr class="tr2">
        <td>282</td>
        <td>2</td>
        <td>A második metódus elérési jogosultságai.</td>
      </tr>
      <tr class="tr1">
        <td>284</td>
        <td>33</td>
        <td>A második metódus leírója és bájtkódja, hasonlóan az elsőhöz, itt már nem részletezve.</td>
      </tr>
      <tr class="tr2">
        <td>317</td>
        <td>2</td>
        <td>A fájl attribútumai, ez esetben 0</td>
      </tr>
    </tbody>
  </table>
  <p class="bekezd">Amint látható, a .class fájlban a bájtkódot kivéve a legtöbb információ szöveges formában tárolódik, amihez egy vagy több szintű konstanskészlet-indexeken keresztül
    jutunk el. A Java erősen típusos nyelv és a mezőkhöz, lokális változókhoz és metódus paraméterekhez kapcsolódó típusokról szóló információt ún. aláírásokban tárolják. Ezek szintén a
    konstanskészletben tárolt speciális formátumú sztringek. Az általános main metódus paramétere és visszatérési érték típusa például:</p>
  <p class="programkod">public static void main(String[] argv)</p>
  <p class="bekezd">a következő aláírással van jelölve:</p>
  <p class="programkod">([java/lang/String;)V</p>
  <p class="bekezd">Az osztályokat belsőleg sztringek reprezentálják, mint például a &quot;java/lang/String&quot;, a primitív típusokat pedig, mint például a float egy egész szám.
    Aláírásokon belül ezeket egy karakter jelenti, például az I az egészet. A tömbök jelzésére [ használatos az aláírás kezdetén.</p>
  <h2>Opkódok - a bájtkód utasításkészlet</h2>
  <p class="bekezd">A bájtkód utasításkészlet jelenleg 212 utasítást tartalmaz, 44 opkód fenntartottként van jelölve jövőbeli felhasználásra vagy a virtuális gép belső
    optimalizációihoz. Az utasításkészletet nagyjából a következő csoportokra lehet osztani:</p>
  <p class="bekezd">
    <b>Veremműveletek</b>: konstansok veremre helyezése vagy azok betöltése a konstanskészletből az ldc utasítással vagy speciális rövidített utasításokkal, ahol az operandus magába az
    utasításba van kódolva, például iconst_0 vagy bipush (bájt érték veremre helyezése).
  </p>
  <p class="bekezd">
    <b>Aritmetikai operátorok</b>: a JVM utasításkészlete külön csoportokba osztja az aritmetikai utasításokat aszerint, hogy azok milyen típusú operandusokon végeznek műveleteket. Az i-vel
    kezdődő aritmetikai operátorok integer operátorokat jelölnek. Az iadd például két integert ad össze, az eredményt pedig visszahelyezi a veremre. A Java típusok boolean, byte, short és
    char a JVM-ben mind integerként kezelődnek.
  </p>
  <p class="bekezd">
    <b>Folyamatvezérlés</b>: vannak vezérlésátadó utasítások, mint a goto és az if_icmpeq, ami két egész közötti egyenlőséget vizsgál. Aztán van a jsr (szubrutinra ugrás) és a ret utasítás,
    amelyeket általában arra használnak, hogy a try-catch blokkok finally ágát implementálják. Kivételeket az athrow utasítással lehet dobni. Az ugrási pozíciókat az aktuális bájtkód
    pozíciótól számítot eltolással (offset - például egész szám) lehet megadni.
  </p>
  <p class="bekezd">
    <b>Betöltés és tárolás</b>: helyi változók esetén iload és istore. Vannak aztán tömbműveletek is, mint például az iastore, amivel egy egész értéket egy tömbbe lehet tárolni.
  </p>
  <p class="bekezd">
    <b>Mező elérés</b>: egy példánymező értékét a getfield utasítással lehet kiolvasni, a putfield utasítással írni. Statikus mezőknél ugyanez getstatic és putstatic.
  </p>
  <p class="bekezd">
    <b>Metódushívás</b>: a statikus metódusok meghívhatók az invokestatic utasítással vagy virtuális kötéssel az invokevirtual utasítással. Ősosztály és privát metódusok hívására szolgál az
    invokespecial. Interfész metódusok hívására pedig az invokeinterface utasítás szolgál. Dinamikus metódushívást az invokedynamic utasítással lehet megvalósítani, de ez csak a Java 8-ban
    lett igazán kihasználva.
  </p>
  <p class="bekezd">
    <b>Objektum foglalás</b>: példányokat lehet létrehozni a new utasítással, primitív típusokból álló tömbök, mint például int[] létrehozhatóak a newarray utasítással, referenciákat
    tartalmazó tömb, mint például String[][] az anewarray vagy a multianewarray utasítással.
  </p>
  <p class="bekezd">
    <b>Konverzió és típus ellenőrzés</b>: primitív típusú verem operandusok esetén léteznek konverziós utasítások, mint az f2i, ami lebegőpontos értéket egésszé alakít. Típuskényszerítés
    validálása történhet a checkcast utasítással, az instanceof utasítás pedig megfelel a Java instanceof utasításának.
  </p>
  <p class="bekezd">A legtöbb utasításnak adott mérete van, de létezik néhány változó hosszúság utasítás is, mint például a lookupswitch és tableswitch, amelyek a switch() kifejezések
    implementálására használatosak. Mivel a case esetek száma változhat, ezek az utasítások változó számú kifejezést tartalmaznak.</p>
  <p class="bekezd">Vezérlésátadó utasítások, mint például a goto a bájtkód tömbjén belüli relatív offszetekkel dolgozik, a kivételkezelők és lokális változók viszont abszolút címeket
    használnak a bájtkódon belül. Az előbbi referenciákat tárol a try blokk elejére és végére valamint kezelő kódjára. Az utóbbi kijelöli azt a kódszakaszt, vagyis hatókört, ahol a változó
    elérhető. Ez bonyolulttá teszi kódok beszúrását vagy törlését az absztrakciónak ezen a szintjén, mivel ezeket az offszeteket újra kell számolni minden esetben és frissíteni kell a
    hivatkozó objektumokat.</p>
  <p class="bekezd">
    Ha tanulmányozzuk a Java bájtkód utasításokat, láthatjuk, hogy néhány utasításnak prefixe van, mint például aload_0 vagy istore_2. Ez az utasítás által kezelt adat típusára vonatkozik.
    Az &quot;a&quot; prefix azt jelenti, hogy az opkód objektum referenciával dolgozik, az &quot;i&quot; pedig azt, hogy egész értékkel. Léteznek opkódok a következő prefixszel is:
    &quot;b&quot; bájt esetén, &quot;l&quot; hosszú egész, &quot;c&quot; karakter esetén, &quot;f&quot; egyszeres, &quot;d&quot; kétszeres pontosságú lebegőpontos érték esetén.<br /> Ezen
    cikknek nem témája a teljes opkód referencia tárgyalása. A teljes lista elérhető <a onclick="window.open(this.href);return false;"
      href="http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings">itt.</a>
  </p>
  <h2>Bájtkód élesben</h2>
  <p class="bekezd">
    A memóriaszerkezet és a fájlformátum után most már lássuk, hogyan is néz ki maga a bájtkód valódi programok esetén. A .class fájlok visszafejtésére a Java tartalmaz parancssori eszközt,
    ez a <span class="programkod">javap</span>. Paraméter nélkül pusztán csak az osztály vázát jeleníti meg, -c paraméterrel a bájtkódot is. Elsőként a fentebb lefordított HelloWorld
    osztályt vizsgáljuk meg:
  </p>
  <pre class="programkod">public class HelloWorld {
  public void process() {
    System.out.println(&quot;Hello World!&quot;);
  }
}
</pre>
  <pre class="programkod">javap -c HelloWorld</pre>
  <pre class="programkod">public class HelloWorld {
  public HelloWorld();
    Code:
       0: aload_0       
       1: invokespecial #1                // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
       4: return        

  public void process();
    Code:
       0: getstatic     #2                // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                // String Hello World!
       5: invokevirtual #4                // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return        
}
</pre>
  <p class="bekezd">
    Az osztály nagyon egyszerű, könnyű látni a kapcsolatot a forráskód és a legenerált bájtkód között. Vegyük észre - ahogyan a .class fájl elemzéséből is látható volt -: a fordító bizony
    legenerálta az alapértelmezett konstruktort (ahogy ez következik is a JVM specifikációjából). Az alapértelmezett konstruktor első opkódja, az aload_0 a helyi változótábla 0. indexen
    található értékét teszi az operandus verem tetejére. Korábban már említettem, hogy a helyi változótábla arra is használva van, hogy a metódusoknak paramétert adjunk át. A
    &quot;this&quot; referencia mindig a 0. helyen tárolódik. Ezt példánymetódusok esetén mindig át kell adni, mert a metódus az osztály példányváltozóit és nevét ezen keresztül éri el,
    tehát egy paraméterek nélküli példánymetódus is kap valójában egy paramétert, a this referenciát. A második opkód utasítás az 1. helyen az <span class="programkod">invokespecial</span>.
    Ez meghívja az ősosztály konstruktorát. Korábban említettem, hogy metódus hívásakor a paraméterek a verembe kerülnek, majd a hívás során verem tartalma átlapolódik és a hívott
    metódusban a helyi változótáblába kerül. Tehát az <span class="programkod">invokespecial</span> előtt a this referenciát a lokális változótábla 0. pozíciójáról a verembe tesszük (<span
      class="programkod">aload_0</span>), ahonnan a hívás során leemelődik és a meghívott metódus lokális változótáblájába kerül. A <span class="programkod">return</span> visszatér a
    metódusból. Észrevehetjük azt is, hogy néhány opkódnak fura operandusa van, mint #1 vagy #2. Ez az osztály konstanskészletére hivatkozik. Az <span class="programkod">invokespecial</span>
    esetén egy Methodref-re, vagyis metódus információra mutat. Ha ezt végigkövetjük: az első bejegyzés osztályhivatkozása a 0x6, ami egy Class szerkezet. Az ebben lévő hivatkozás pedig
    (0x12) a java/lang/Object-et mutatja. A Methodref második indexe 0xB, ami egy NameAndType szerkezetet indexel. Ennek első indexe (0x7) a névre hivatkozik: a 7. helyen a
    konstanskészletben a &lt;init&gt; található, második indexe pedig a típusokról ad információt, itt 0x8 az index, ez pedig a ()V sztringet jelöli ki. Így tehát összeáll a hívott metódus,
    amint azt az opkód utáni megjegyzés is mutatja: java/lang/Object.&quot;&lt;init&gt;&quot;:()V
  </p>
  <p class="bekezd">
    A process metódus első opkódja a System osztály statikus out mezőjét tölti be, az <span class="programkod">ldc</span> utasítás a 3-as indexű konstanst tölti be a verem tetejére, ami a
    &quot;Hello World!&quot; sztring. Ez lesz a paramétere a meghívott metódusnak, amit az invokevirtual utasítás hív meg. Ez a 4. konstansra hivatkozik, ami egy Methodref érték, megadja a
    hívott metódust.<br /> Lássunk most egy egyszerű POJO-t egy mezővel, getterrel és setterrel.
  </p>
  <pre class="programkod">public class Foo {
  private String bar;

  public String getBar(){ 
    return bar; 
  }

  public void setBar(String bar) {
    this.bar = bar;
  }
}
</pre>
  <p class="bekezd">Bájtkódja így néz ki:</p>
  <pre class="programkod">public class Foo {
  public Foo();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
       4: return        

  public java.lang.String getBar();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field bar:Ljava/lang/String;
       4: areturn       

  public void setBar(java.lang.String);
    Code:
       0: aload_0       
       1: aload_1       
       2: putfield      #2                  // Field bar:Ljava/lang/String;
       5: return        
}
</pre>
  <p class="bekezd">
    A fentebb tárgyalt részletes .class fáj kifejtést a javap összefoglalva meg tudja mutatni. Ehhez futtassuk a következő parancsot: <span class="programkod">javap -c -s -verbose</span> (a
    -s kiírja a szignatúrákat, a -verbose kiírja az összes részletet).
  </p>
  <pre class="programkod">Classfile /f:/Programok/java/sample/Foo.class
  Last modified 2014.04.06.; size 291 bytes
  MD5 checksum 1a7709f1dca471e22d2083654069ef6b
public class Foo
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:
   #1 = Methodref          #4.#14         //  java/lang/Object.&quot;&lt;init&gt;&quot;:()V
   #2 = Fieldref           #3.#15         //  Foo.bar:Ljava/lang/String;
   #3 = Class              #16            //  Foo
   #4 = Class              #17            //  java/lang/Object
   #5 = Utf8               bar
   #6 = Utf8               Ljava/lang/String;
   #7 = Utf8               &lt;init&gt;
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               getBar
  #11 = Utf8               ()Ljava/lang/String;
  #12 = Utf8               setBar
  #13 = Utf8               (Ljava/lang/String;)V
  #14 = NameAndType        #7:#8          //  &quot;&lt;init&gt;&quot;:()V
  #15 = NameAndType        #5:#6          //  bar:Ljava/lang/String;
  #16 = Utf8               Foo
  #17 = Utf8               java/lang/Object
{
  public Foo();
    Signature: ()V
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
         4: return        

  public java.lang.String getBar();
    Signature: ()Ljava/lang/String;
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: getfield      #2                  // Field bar:Ljava/lang/String;
         4: areturn       

  public void setBar(java.lang.String);
    Signature: (Ljava/lang/String;)V
    flags: ACC_PUBLIC

    Code:
      stack=2, locals=2, args_size=2
         0: aload_0       
         1: aload_1       
         2: putfield      #2                  // Field bar:Ljava/lang/String;
         5: return        
}
</pre>
  <p class="bekezd">A kifejtés első négy sora értelemszerű. A minor version a fájl alverziója, a major version a főverziója. A flags mutatja az osztály elérési jogosultságait. Az
    ACC_PUBLIC jelenléte mutatja, hogy az osztály publikus elérésű, az ACC_SUPER flag visszamenőleges kompatibilitás miatt szükséges, az összes modern fordító beállítja. Ezután a
    konstanskészlet összes bejegyzése következik. Ahogy fentebb a .class fájl közvetlen vizsgálatakor látszottak a hivatkozások, itt is látható. A #2 például:</p>
  <pre class="programkod">const #2 = Field #3.#18; // Foo.bar:Ljava/lang/String;</pre>
  <p class="bekezd">hivatkozik a következőkre:</p>
  <pre class="programkod">const #3 = class #19; // Foo
const #18 = NameAndType #5:#6;// bar:Ljava/lang/String;</pre>
  <p class="bekezd">
    és így tovább. Ezután következnek a metódusok, mindegyiknek jelezve a paraméterlistája és a jogosultságai. A stack mutatja a metódus vermének méretét, ahogy fentebb is olvasható volt,
    ez fordítási időben meghatározódik, itt pedig látható, hogy a &quot;Code&quot; attribútumon belül, a bájtkóddal együtt tárolódik. A locals mutatja a helyi változók táblájának méretét,
    az args_size pedig a paraméterlista méretét. A bájtkódon belül minden opkód egy számmal van jelölve (<u>0</u>: aload_0). Ez az utasítás keretben elfoglalt helyére vonatkozik (lásd
    lejjebb).
  </p>
  <pre class="programkod">public String getBar(){ 
    return bar; 
}

public java.lang.String getBar();
  Code:
     0: aload_0       
     1: getfield      #2                  // Field bar:Ljava/lang/String;
     4: areturn
</pre>
  <p class="bekezd">
    A felső metódus bájtkódja három opkód utasítást tartalmaz. Az <span class="programkod">aload_0</span> már ismert, ráteszi az operandus veremre a lokális változótábla 0. indexén szereplő
    referenciát (this). A következő opkód utasítás, a <span class="programkod">getfield</span> arra szolgál, hogy egy objektum egyik mezőjének értékét elérjük. Az utolsó utasítás, az <span
      class="programkod">areturn</span> visszatér egy referenciával egy metódusból. A fenti példaosztály .class fájljának bájttömbjében zöld háttér mutatja a tárgyalt opkódoknak megfelelő
    bájtkódot:
  </p>
  <p class="kozep">
    <img alt="sample2" src="/informatika/essze/bytecode/classsample2.png" />
  </p>
  <p class="bekezd">
    A getBar metódus bájtkódja 2A B4 00 02 B0. A 0x2A kód felel meg az <span class="programkod">aload_0</span> utasításnak, a 0xB0 pedig az <span class="programkod">areturn</span>
    utasításnak. Talán meglepő, hogy a metódus 3 opkódból áll, de a bájtkód tömbje 5 elemet tartalmaz. Ennek az a magyarázata, hogy a <span class="programkod">getfield</span>-nek (0xB4) 2
    bájtra van szüksége az indexeléshez (00 és 02) és ezek a paraméterek a 2-es és 3-as pozíción foglalnak helyet a tömbben, így annak mérete 5 bájt és az areturn utasítás eltolódott a 4-es
    helyre.
  </p>
  <h3>A lokális változók tömbje</h3>
  <p class="bekezd">A lokális változók tömbjének szerepéről egy korábbi fejezetben már volt szó, most megvizsgáljuk konkrét osztályon, hogyan is néz ki.</p>
  <pre class="programkod">public class Example {
   public int plus(int a){
     int b = 1;
     return a + b;
   }
}
</pre>
  <p class="bekezd">Ez a metódus 2 lokális változót kezel: egyet a metódus paramétereként kapja, a másik pedig az int típusú &quot;b&quot; lokális változó. Ahhoz, hogy a javap
    megmutassa a lokális változók tömbjét, a programot -g kapcsolóval kell fordítani, a javap-nek pedig a -l kapcsolót kell megadni. Ezután így néz ki a bájtkód:</p>
  <pre class="programkod">public int plus(int);
  Code:
     0: iconst_1      
     1: istore_2      
     2: iload_1       
     3: iload_2       
     4: iadd          
     5: ireturn       
  LineNumberTable:
    line 3: 0
    line 4: 2
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        0       6     0  this   LExample;
        0       6     1     a   I
        2       4     2     b   I
</pre>
  <p class="bekezd">
    A javac alapértelmezettként a nyomkövetéshez szükséges programsor-információkat is belegenerálja a .class fájlba, ez itt is látható. A változótábla mutatja, hogy a helyi változók hogyan
    helyezkednek el. Elsőként a metódus betölti az <b>1</b> konstanst az <span class="programkod">iconst_1</span> utasítással, majd az <span class="programkod">istore_2</span> utasítással
    eltárolja azt a helyi változótábla második helyére. A helyi változótáblában láthatjuk is, hogy a kettes hely (slot) fenn van tartva a <b>b</b> nevű változónak. Következőként az <span
      class="programkod">iload_1</span> elhelyezi az <b>a</b> értékét a verem teteján, az <span class="programkod">iload_2</span> pedig a <b>b</b> értékét. Az <span class="programkod">iadd</span>
    levesz két elemet a veremről, összeadja ezeket aztán az eredményt visszateszi a veremre, amivel a <span class="programkod">return</span> visszatér a metódusból.
  </p>
  <p class="bekezd">
    A tábla start oszlopa azt mutatja meg, hogy a bájtkódban az adott változó melyik sortól elérhető, a length pedig azt, hogy hány utasításon keresztül él. A <b>this</b> és az <b>a</b>
    változó már a metódus 0. utasításánál elérhető, a <b>b</b> pedig a másodiktól. A signature oszlop megmutatja a változó típusát.
  </p>
  <h3>Kivételkezelés</h3>
  <p class="bekezd">
    Érdemes megvizsgálni a bájtkódot kivételkezelésnél is, például hogy milyen kód generálódik a <span class="programkod">try-catch-finally</span> blokknak. Amikor a végrehajtás során egy
    kivétel dobódik, a JVM megvizsgálja a kivételek tábláját. Ez a tábla tartalmazza a kivételkezelőket: azon kódrészek hivatkozását, amelyek felelősek bizonyos, a bájtkód megadott
    területén fellépő megadott típusú kivételekért. Amikor nincs megfelelő kezelő, a kivétel továbbdobódik a metódus hívójának. A kezelő információ a sorszámokhoz és a helyi változók
    táblájához hasonlóan a Code attribútumon belül tárolódik.
  </p>
  <pre class="programkod">public class ExceptionExample {

  public void foo(){
    try {
      tryMethod();
    }
    catch (Exception e) {
      catchMethod();
    }finally{
      finallyMethod();
    }
  }

  private void tryMethod() throws Exception{}

  private void catchMethod() {}

  private void finallyMethod(){}

}</pre>
  <p class="bekezd">
    Ez fordítódik a <span class="programkod">foo()</span> metódusból:
  </p>
  <pre class="programkod">public void foo();
  Code:
     0: aload_0       
     1: invokespecial #2                  // Method tryMethod:()V
     4: aload_0       
     5: invokespecial #3                  // Method finallyMethod:()V
     8: goto          30
    11: astore_1      
    12: aload_0       
    13: invokespecial #5                  // Method catchMethod:()V
    16: aload_0       
    17: invokespecial #3                  // Method finallyMethod:()V
    20: goto          30
    23: astore_2      
    24: aload_0       
    25: invokespecial #3                  // Method finallyMethod:()V
    28: aload_2       
    29: athrow        
    30: return        
  Exception table:
     from    to  target type
         0     4    11   Class java/lang/Exception
         0     4    23   any
        11    16    23   any
        23    24    23   any
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        12       4     1     e   Ljava/lang/Exception;
         0      31     0  this   LExceptionExample;
</pre>
  <p class="bekezd">
    Amint látható, a fordító legenerálja a kódot az összes lehetséges helyzethez, ami a <span class="programkod">try-catch-finally</span> végrehajtása során történhet: a <span
      class="programkod">finallyMethod()</span> hívása 3-szor van megadva! A <span class="programkod">try</span> blokk úgy készül el, mintha a <span class="programkod">try</span> nem is
    létezne; összefűződik a <span class="programkod">finally</span>-val:
  </p>
  <pre class="programkod">public void foo();
  Code:
     0: aload_0       
     1: invokespecial #2                  // Method tryMethod:()V
     4: aload_0       
     5: invokespecial #3                  // Method finallyMethod:()V
     8: goto          30
</pre>
  <p class="bekezd">
    Ha a blokk sikeresen lefut, akkor a <span class="programkod">goto</span> utasítás a 30-as opkódra adja a vezérlést, ami egy <span class="programkod">return</span>. Ha a tryMethod() egy
    Exception példányt dob, akkor JVM megvizsgálja a kivételtáblát. Ezt a fordító generálja és a bájtkód tartalmazza. A from és to mezők megadják, hogy az adott type típusú kivétel a kód
    mely részétől meddig léphet fel, a target megadja, hogy a kivétel esetén mely pozícióra kell ugrani a vezérlésnek. A példában Exception példányú kivétel esetén a kivételtábla első
    kivételkezelője lesz kiválasztva. A kivételtáblából látható, hogy a megfelelő kivételkezelő pozíciója ez esetben 11:
  </p>
  <pre class="programkod">from   to  target type
   0    4     11   Class java/lang/Exception</pre>
  <p class="bekezd">Ennek során végrehajtódik a catchMethod() és a finallyMethod():</p>
  <pre class="programkod">    11: astore_1      
    12: aload_0       
    13: invokespecial #5                  // Method catchMethod:()V
    16: aload_0       
    17: invokespecial #3                  // Method finallyMethod:()V
    20: goto          30</pre>
  <p class="bekezd">
    Az <span class="programkod">astore_1</span> eltárolja az &quot;e&quot; nevű változóba, a helyi változók táblájának 1. helyére a verembe került kivétel referenciát, majd meghívódik a <span
      class="programkod">catchMethod()</span> és a <span class="programkod">finallyMethod</span> is. Amennyiben a végrehajtás során bármilyen más kivétel dobódna, a kivételtáblából látható,
    hogy a tetszőleges típusú kivétel kezeléséhez (amelyek a <span class="programkod">try-catch-finally</span> szerkezet bármely pontján felléphetnek) szükséges pozíció a 23:
  </p>
  <pre class="programkod">     from    to  target type
         0     4    23   any
        11    16    23   any
        23    24    23   any</pre>
  <p class="bekezd">Nézzük meg, milyen utasítások állnak a 23-as pozíciótól kezdődően:</p>
  <pre class="programkod">    23: astore_2      
    24: aload_0       
    25: invokespecial #3                  // Method finallyMethod:()V
    28: aload_2       
    29: athrow        
    30: return</pre>
  <p class="bekezd">
    Vagyis a finallyMethod() ebben az esetben is meghívódik. Az <span class="programkod">astore_2</span> a helyi változótömb 2. pozíciójára menti a kivételt, amit a metódushívás után
    visszatesz az <span class="programkod">aload_2</span> a verem tetejére és ezt dobja tovább az athrow. Érdemes még megemlíteni, hogy a Java 7 egyik újítása, a több típusú <span
      class="programkod">catch</span> lehetősége a bájtkódon semmiben sem változtatott, vagyis ha a tryMethod()-ot átírjuk mondjuk erre:
  </p>
  <pre class="programkod">private void tryMethod() throws IOException, IllegalArgumentException{}</pre>
  <p class="bekezd">a catch ágat pedig így:</p>
  <pre class="programkod">catch (IOException | IllegalArgumentException e) {</pre>
  <p class="bekezd">akkor a legenerált bájtkód érdemben nem változik, csak egy újabb sor kerül a kivételzekező táblájába, ami azt mutatja, hogy a második kivétel esetén is a 11-es
    pozícióban kezdődik a kivételkezelő:</p>
  <pre class="programkod">0     4    11   Class java/lang/IllegalArgumentException</pre>
  <h2>Optimalizálás</h2>
  <p class="bekezd">A javac fordító nem végez összetettebb optimalizálást a kódon. A legelső Java implementáció esetén még volt egy -O kapcsolója, amiről a dokumentáció azt állította,
    optimalizálni fogja a kódot a nagyobb sebesség érdekében, de a -O használatának Sun/Oracle Java 2 SDK vagy annál újabb környezet estén már nincs hatása a generált kódra. Meghagyásának
    egyetlen oka, hogy a javac kompatibilis maradjon a régebbi make fájlokkal. A Java bájtkód végrehajtásáért a HotSpot JIT felel, ami szükség esetén lefordítja azt gépi kódra és összetett
    vizsgálatokat valamint optimalizálásokat képes végezni az adott platform képességeinek figyelmbe vételével. Ezek tárgyalása külön cikket igényelne, ezért itt nem térek ki rá. Néhány
    alapvető optimalizálást a javac fordító alapértelmezetten is elvégez, mint például a konstans kifejezések kiértékelése vagy a soha nem futó kódrészek kihagyása. Nézzük a következő
    metódust:</p>
  <pre class="programkod">public void sampleMethod() {
    double i = 10l * Math.PI;
    if (true)
        System.out.println(i);
    if (false)
        System.out.println(i * 100);
}
</pre>
  <p class="bekezd">A metódusból az alábbi bájtkód készül:</p>
  <pre class="programkod">  public void sampleMethod();
    Code:
       0: ldc2_w        #11                 // double 31.41592653589793d
       3: dstore_1      
       4: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
       7: dload_1       
       8: invokevirtual #19                 // Method java/io/PrintStream.println:(D)V
      11: return        
</pre>
  <p class="bekezd">
    Mint látható, a fordító kiértékelte az i kezdőértékének konstans kifejezését és az <span class="programkod">if (true)</span> valamint <span class="programkod">if (false)</span>
    kifejezéseket is, ennek megfelelően a második <span class="programkod">println</span> már nem is került a bájtkódba. A javac emellett azt is észreveszi, ha egy sztring literál többször
    szerepel egy osztályban, ilyenkor a konstanskészletbe csak egyszer kerül be és minden előfordulás esetén ugyanarra az indexre lesz hivatkozás.
  </p>
  <h3>Szinkronizálás</h3>
  <p class="bekezd">Az JIT által végzett optimalizálás viszont még nem jelenti azt, hogy célszerűtlen lenne hatékony kódot írni, egy jó példa erre a szinkronizáció esete. A következő
    két metódus visszaadja egy tömbként implementált verem legfelső elemét. Mindkettő használ szinkronizációt és funkcionálisan azonosak:</p>
  <pre class="programkod">public synchronized int top1() {
    return intArr[0];
}

public int top2() {
    synchronized (this) {
        return intArr[0];
    }
}
</pre>
  <p class="bekezd">A funkcionális azonosság ellenére különböző méretű és sebességű kód fordítódik belőlük. Ebben az esetben a top1 gyorsabb és kisebb, mint a top2. Vizsgáljuk meg a
    generált bájtkódot, hogy lássuk miben különböznek a metódusok. A bájtkód minden sorához megjegyzések tartoznak, hogy segítsenek megérteni, mi is történik.</p>
  <pre class="programkod">public synchronized int top1();
  Code:
     0: aload_0                       // A this refeerncia veremre helyezése
     1: getfield      #29             // Field intArr:[I
                                      // A this referencia leemelése a veremről és az intArr
                                      // referenciájának elérése a konstanskészletből.
     4: iconst_0                      // A 0 veremre helyezése
     5: iaload                        // A verem tetején lévő két elem leemelése és az intArr
                                      // 0. elemének veremre helyezése
     6: ireturn                       // a verem legfelső elemének a hívó vermének tetejére
                                      // helyezése és visszatérés a metódusból

public int top2();
  Code:
     0: aload_0                       // A this refeerncia veremre helyezése
     1: dup                           // A verem tetején lévő érték még egyszer a verem
                                      // tetejére kerül 
     2: astore_1                      // A verem tetején lévő referencia a változótábla 1.
                                      // helyére kerül
     3: monitorenter                  // A verem tetején lévő referencia (this) leemelése és
                                      // a monitor belépése
     4: aload_0                       // A synchronized blokk kezdete. A this refeerncia
                                      // veremre helyezése
     5: getfield      #29             // Field intArr:[I
                                      // A this referencia leemelése a veremről és az intArr
                                      // referenciájának elérése a konstanskészletből.
     8: iconst_0                      // A 0 veremre helyezése
     9: iaload                        // A verem tetején lévő két elem leemelése és az intArr
                                      // 0. elemének veremre helyezése
    10: aload_1                       // A változótábla 1. elemének a verem tetejére helyezése
    11: monitorexit                   // A verem tetején lévő referencia (this) leemelése
                                      // és kilépés a monitorból
    12: ireturn                       // a verem legfelső elemének a hívó vermének tetejére
                                      // helyezése és visszatérés a metódusból
    13: aload_1                       // A változótábla 1. elemének a verem tetejére helyezése
    14: monitorexit                   // A verem tetején lévő referencia (this) leemelése
                                      // és kilépés a monitorból
    15: athrow                        // A verem tetején lévő referencia (this) leemelése
                                      // és a kivétel dobása
  Exception table:
     from    to  target type
         4    12    13   any
        13    15    13   any
</pre>
  <p class="bekezd">
    A top2 nagyobb és lassabb, mint a top1 a szinkronizálás és a kivételkezelés eltérő megvalósítása miatt. A top1 a <span class="programkod">synchronized</span> metódus módosítót
    használja, ami nem generál extra kódot. A top2 a <span class="programkod">synchronized</span> funkciót a metódus törzsében használja. Ez pedig a <span class="programkod">monitorenter</span>
    és <span class="programkod">monitorexit</span> opkódok, valamint kivételkezelő kód generálását eredményezi. Ha a szinkronizált blokk (egy monitor) futtatása során kivétel jön létre, a
    zárolás garantáltan megszűnik a szinkronizált blokkból való kilépés előtt. A top1 kissé hatékonyabb, mint a top2. Amikor - mint a top1 esetén - a <span class="programkod">synchronized</span>
    metódus módosítót használjuk, a zárolás és annak elengedése nem a <span class="programkod">monitorenter</span> és <span class="programkod">monitorexit</span> opkódokkal történik, hanem
    amikor a JVM meghívja a metódust, ellenőrzi a method_info struktúra access_flags bitmaszkban az ACC_SYNCHRONIZED beállítását. Ha ez meg van adva, akkor a futtató szál zárolódik,
    meghívja a metódust, aztán megszünteti a zárolást, amikor a metódus véget ér. Ha a futtatás során kivétel dobódik, akkor a zárolás automatikusan megszűnik, mielőtt a kivétel elhagyja a
    metódust. A különböző használatnak méretbeli hatásai is vannak. Szinkronizált metódusokat csak akkor érdemes használni, amikor a kódnak valóban szüksége van rá és megértettük a
    használatának költségeit. Ha egy teljes metódusnak szüksége van a szinkronizálásra, akkor célszerű előnyben részesíteni a metódus módosítót a synchronized blokkal szemben.
  </p>
  <h3>StringBuilder</h3>
  <p class="bekezd">A Java nyelvben a sztringműveletek használata sokat egyszerűsödött a C nyelvhez képest, a sztringek literálként kezelhetőek, sőt alapértelmezettként ez ajánlott.
    Ezek a bájtkódban azonban már viszonylag alacsony szintű műveletekké fordítódnak le. Lássuk, hogyan:</p>
  <pre class="programkod">public void stringMethod() {
    String o = new String(&quot;string object&quot;);
    String l = &quot;string literal&quot;;
    System.out.println(o + l);
    System.out.println(o + 100);
}
</pre>
  <p class="bekezd">A példában létrehozunk két szöveges változót, majd összefűzve kiíratjuk őket, illetve az egyik esetében egy számot is hozzáadunk. Ebből a következő bájtkód készül:</p>
  <pre class="programkod">public void stringMethod();
  Code:
     0: new           #11     // class java/lang/String
     3: dup           
     4: ldc           #30     // String string object
     6: invokespecial #15     // Method java/lang/String.&quot;&lt;init&gt;&quot;:(Ljava/lang/String;)V
     9: astore_1      
    10: ldc           #32     // String string literal
    12: astore_2      
    13: getstatic     #18     // Field java/lang/System.out:Ljava/io/PrintStream;
    16: new           #34     // class java/lang/StringBuilder
    19: dup           
    20: aload_1       
    21: invokestatic  #36     // Method java/lang/String.valueOf:(Ljava/lang/Object;)
                              // Ljava/lang/String;
    24: invokespecial #40     // Method java/lang/StringBuilder.&quot;&lt;init&gt;&quot;:(Ljava/lang/String;)V
    27: aload_2       
    28: invokevirtual #41     // Method java/lang/StringBuilder.append:
                              //(Ljava/lang/String;)Ljava/lang/StringBuilder;
    31: invokevirtual #45     // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    34: invokevirtual #24     // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    37: getstatic     #18     // Field java/lang/System.out:Ljava/io/PrintStream;
    40: new           #34     // class java/lang/StringBuilder
    43: dup           
    44: aload_1       
    45: invokestatic  #36     // Method java/lang/String.valueOf:(Ljava/lang/Object;)
                              // Ljava/lang/String;
    48: invokespecial #40     // Method java/lang/StringBuilder.&quot;&lt;init&gt;&quot;:(Ljava/lang/String;)V
    51: bipush        100
    53: invokevirtual #49     // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
    56: invokevirtual #45     // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    59: invokevirtual #24     // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    62: return        
</pre>
  <p class="bekezd">
    A <span class="programkod">new</span> opkód létrehozza a konstanskészletben megadott index által azonosított osztály új példányát és elhelyezi annak referenciáját a vermen. Látható,
    hogy a <span class="programkod">String o = new String(&quot;string object&quot;)</span> utasításhoz 5 bájtkód sor tartozik (0-9), míg a <span class="programkod">String l =
      &quot;string literal&quot;</span> sorhoz mindössze kettő (10-12), ez esetben semmilyen új objektum nem jön létre, mindössze a lokális változótábla megfelelő cellájába bekerül a
    sztringkonstans referenciája. Az első összeadáshoz tartozó bájtkód a 16-31. sorban található. Még ebben a legegyszerűbb esetben is létrejön egy új StringBuilder példány, az összeadás
    pedig <span class="programkod">StringBuilder.append</span> műveletté fordítódik. A második összeadás hasonlóan StringBuilderrel történik (40-56. sor), a 100 konstans közvetlenül a
    megfelelő append metódusnak adódik át. Mivel a 100 egy bájtban is elfér, ezért használható a bipush opkód, ami a következő bájt értéket helyezi el integerként a veremre. Amennyiben
    nagyobb számot adunk meg konstansként, sipush (2 bájt esetén) vagy konstanskészletbeli betöltés (long esetén) kerül a helyére. Ezzel a fordító helyet is spórol, a konstanshoz az
    alkalmas legkisebb tárterület lesz használva a bájtkódban.
  </p>
  <h3>Autoboxing</h3>
  <p class="bekezd">A Java 5-ben jelent meg a primitív típusokat automatikusan objektumokká és vissza alakító autoboxing technológia. Ennek segítségével már nem kell egy adott
    műveletnél arra figyelni, hogy primitív típust vagy az annak megfelelő referencia-típust használjuk-e. A következő példa megmutatja, hogyan néz ki ez a bájtkódban:</p>
  <pre class="programkod">public void boxing() {
    long res = 0l;
    res = boxingAdd(res);
}

public Long boxingAdd(Long a) {
    return a + 2l;
}
</pre>
  <p class="bekezd">Ez a kódrészlet a következő bájtkóddá fordul le:</p>
  <pre class="programkod">public void boxing();
  Code:
     0: lconst_0      
     1: lstore_1      
     2: aload_0       
     3: lload_1       
     4: invokestatic  #30                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
     7: invokevirtual #36                 // Method boxingAdd:(Ljava/lang/Long;)Ljava/lang/Long;
    10: invokevirtual #40                 // Method java/lang/Long.longValue:()J
    13: lstore_1      
    21: return        

public java.lang.Long boxingAdd(java.lang.Long);
  Code:
     0: aload_1       
     1: invokevirtual #40                 // Method java/lang/Long.longValue:()J
     4: ldc2_w        #47                 // long 2l
     7: ladd          
     8: invokestatic  #30                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
    11: areturn       
</pre>
  <p class="bekezd">
    Amint látható, amikor az átalakításra szükség van, a <span class="programkod">Long.valueOf</span> vagy <span class="programkod">Long.longValue</span> metódusok hívódnak meg.
  </p>
  <div class="keretes">
    <h3>Konstans referencia</h3>
    <p>A Java tartalmaz egy kevésbé ismert, ám egy rejtelmes hibalehetőséget magában rejtő tulajdonságot is (hibát, amennyiben a nyelvet nem megfelelően használják).</p>
    <p>
      A <span class="programkod">Long.valueOf(int i)</span> metódus forráskódja a következő módon néz ki:
    </p>
    <pre class="programkod">public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i &gt;= IntegerCache.low &amp;&amp; i &lt;= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}</pre>
    <p>Mivel az objektum létrehozás viszonylag költséges művelet, a Java fejlesztői a teljesítmény növelésére és a tárhely csökkentésére azt a megoldást találták ki, hogy bizonyos
      primitív típusok esetén előre eltárolják azok gyakran használt értékéhez tartozó előre létrehozott (ez esetben statikus inicializátorban létrejött) objektumokat és amikor erre szükség
      van (mint például a fenti autoboxing példában), akkor nem hoznak létre új objektumot, hanem csak az átmeneti tárolóból (IntegerCache) választják ki az értékhez tartozó objektum
      referenciáját. Alapértelmezetten ez a -128 és 127 közötti értékeknél működik (a felső érték paraméterezhető, de 127-nél nem lehet nagyobb).</p>
    <p>
      Primitív típusok esetén az == művelet a változók értékét hasonlítja össze, objektumok esetén viszont a referencia egyezését. (A String típus esetén literálként használva ugyanazon
      konstanskészlet-bejegyzésben tárolódnak, tehát <span class="programkod">&quot;string&quot;==&quot;string&quot;</span> true lesz, de <span class="programkod">new
        String(&quot;string&quot;)==new String(&quot;string&quot;)</span> már false)<br /> Ennek a megoldásnak van egy nagyon fontos következménye. Amennyiben mindezzel nem vagyunk tisztában, a
      következő kód meglepő eredményt ad:
    </p>
    <pre class="programkod">Integer i1 = 128;
Integer i2 = 128;
System.out.println(i1 == i2);
i1 = 127;
i2 = 127;
System.out.println(i1 == i2);</pre>
    <p>
      Az első feltételvizsgálat eredménye false lesz, a második eredménye true. Ennek oka most már világos: első esetben két új Integer objektum jön létre, a második esetben viszont mindkét
      változó ugyanannak az objektumnak a referenciáját kapja meg. (És Long típus esetén ugyanez az eredmény.) Az elvárt működéshez itt is az <span class="programkod">equals</span> metódust
      kell használni.
    </p>
    <p>Ha pedig még a reflection keretrendszert is bevetjük, akár meg is változtathatjuk az egyébként private elérésű IntegerCache értékeit, így aztán tetszőleges értéket adhatunk
      bizonyos számoknak:</p>
    <pre class="programkod">value = Integer.class.getDeclaredField(&quot;value&quot;);
value.setAccessible(true);
value.set(1, 2);
Integer i = 1;
System.out.println(i + 1);</pre>
    <p>
      A programrészlet eredménye az autoboxing miatt 3 lesz! Ha viszont az <span class="programkod">i=new Integer(1)</span> utasítással inicializálunk, akkor már 2.
    </p>
  </div>
  <h3>Vararg</h3>
  <p class="bekezd">
    Az autoboxing mellett ugyancsak a Java 5-ben jelent meg a változó hosszúságú paraméterlista, ami <i>olvashatóbbá</i> tette tetszőleges számú azonos típusú paraméter átadását
    metódusoknak, hiszen nem kellett ezeket listába vagy tömbbe szervezni. Az ezt használó metódus törzsében ezt a paraméterlistát tömbként lehet elérni (ennek mérete lehet 0 is, ha a
    metódus változó paraméterlistáját nem adjuk meg).
  </p>
  <pre class="programkod">public void methodVar(long... longparam) {
	System.out.println(longparam.length);
}

public void methodArray(long[] longparam) {
	System.out.println(longparam.length);
}

public void caller() {
	methodVar(1l, 2l, 3l);
	methodArray(new long[] { 1l, 2l, 3l });
}
</pre>
  <p class="bekezd">A két példametódus törzsében a longparam paraméter kezelése azonos, azonban a függvények szignatúrája illetve hívásuk eltérő. Amint azt a bájtkód vizsgálata
    megmutatja, ez a nyelvi tulajdonság csupán a fordítót érintette, a bájtkód semmiben nem változott. A két metódus bájtkódja teljesen azonos (lefordított szignatúrájuk is, ezért nem is
    lehet azonos néven definiálni ilyen metódusokat a Java kódban sem):</p>
  <pre class="programkod">    Code:
       0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_1       
       4: arraylength   
       5: invokevirtual #21                 // Method java/io/PrintStream.println:(I)V
       8: return        
</pre>
  <p class="bekezd">
    A két metódus hívása a fenti példában teljesen megegyezik (alább a 0.-19. sor teljesen megismétlődik a 21. sortól). Mindkét esetben egy új long tömb jön létre a paraméterekkel, sőt a
    fordító még azt is megengedi, hogy a <span class="programkod">methodVar</span> metódust is explicit tömb paraméterrel hívjuk meg: <span class="programkod">methodVar(new long[] {
      1l, 2l, 3l });</span>. Ha egy változó paraméterlistájú metódust többször hívunk azonos paraméterekkel, akkor annyit érdemes megfontolni, hogy a paraméterlistából minden esetben új tömb jön
    létre, ez pedig költségesebb, mintha ugyanannak az előre létrehozott tömbnek a referenciáját kapná meg minden esetben.
  </p>
  <pre class="programkod">  public void caller();
    Code:
       0: aload_0       
       1: iconst_3      
       2: newarray       long
       4: dup           
       5: iconst_0      
       6: lconst_1      
       7: lastore       
       8: dup           
       9: iconst_1      
      10: ldc2_w        #31                 // long 2l
      13: lastore       
      14: dup           
      15: iconst_2      
      16: ldc2_w        #33                 // long 3l
      19: lastore       
      20: invokevirtual #35                 // Method methodVar:([J)V
      23: aload_0       
      24: iconst_3      
      25: newarray       long
      27: dup           
      28: iconst_0      
      29: lconst_1      
      30: lastore       
      31: dup           
      32: iconst_1      
      33: ldc2_w        #31                 // long 2l
      36: lastore       
      37: dup           
      38: iconst_2      
      39: ldc2_w        #33                 // long 3l
      42: lastore       
      43: invokevirtual #37                 // Method methodArray:([J)V
      46: return        
</pre>
  <h3>Switch</h3>
  <p class="bekezd">
    A <span class="programkod">switch</span> kifejezés támogatásához a bájtkód két speciális utasítást használ: <span class="programkod">tableswitch</span> és <span class="programkod">lookupswitch</span>.
    Mindkettő int típusú értékekkel dolgozik (más, a <span class="programkod">switch</span> kifejezésben használható típus int típussá konvertálódik a JVM-ben). A <span class="programkod">tableswitch</span>
    általában gyorsabb, viszont több memóriát igényel, ugyanis a <span class="programkod">switch</span> kifejezésben megadott értékek minimuma és maximuma között <b>minden</b> lehetséges
    értéket felsorol. Ilyen módon a JVM azonnal a default blokkra tud ugrani, amennyiben a vizsgált változó értéke nincs a felsorolt case esetek között. A bájtkódba tehát bekerülnek azok az
    értékek is (a default blokkra hivatkozva), amelyek a Java kódban nem voltak felsorolva. Tekintsük a következő példát:
  </p>
  <pre class="programkod">public void methodSwitch(int param) {
	switch (param) {
	case 5:
		System.out.println("öt");
		break;
	case 2:
		System.out.println("kettő");
		break;
	case 1:
		System.out.println("egy");
		break;
	default:
		System.out.println("sok");
	}
}
</pre>
  <p class="bekezd">Ebből a következő bájtkód készül:</p>
  <pre class="programkod">  public void methodSwitch(int);
    Code:
       0: iload_1       
       1: tableswitch   { // 1 to 5
                     1: 58
                     2: 47
                     3: 69
                     4: 69
                     5: 36
               default: 69
          }
      36: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
      39: ldc           #21                 // String öt
      41: invokevirtual #23                 // Method java/io/PrintStream.println:
                                            // (Ljava/lang/String;)V
      44: goto          77
      47: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
      50: ldc           #29                 // String kettő
      52: invokevirtual #23                 // Method java/io/PrintStream.println:
                                            // (Ljava/lang/String;)V
      55: goto          77
      58: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
      61: ldc           #31                 // String egy
      63: invokevirtual #23                 // Method java/io/PrintStream.println:
                                            // (Ljava/lang/String;)V
      66: goto          77
      69: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
      72: ldc           #33                 // String sok
      74: invokevirtual #23                 // Method java/io/PrintStream.println:
                                            // (Ljava/lang/String;)V
      77: return                            // A switch utáni első utasítás: itt visszatérés a
                                            // metódusból
</pre>
  <p class="bekezd">
    A <span class="programkod">tableswitch</span> utasításnak 1, 2 és 5 van megadva a megfelelő case kifejezésekhez, melyek mindegyike az annak megfelelő blokk első utasítását címzi a
    kódban (58, 47, 36). Emellett bekerült a 3 és 4 is, ezek a switch kifejezésben nem szerepeltek, ezért a default blokkra mutatnak (69). Amennyiben a Java kódban nem szerepel default ág,
    a <span class="programkod">tableswitch</span> default része a switch utáni első utasításra fog mutatni. A generált .class fájlban a művelet a következő bájtokból áll:
  </p>
  <table cellpadding="0" cellspacing="0" width="55%" class="datatable">
    <thead class="datatable">
      <tr>
        <th class="normal" style="text-align: left; width: 20%;"><b>Hexa</b></th>
        <th class="normal"><b>Leírás</b></th>
      </tr>
    </thead>
    <tbody>
      <tr class="tr1">
        <td>AA 00 00</td>
        <td>Az utasítás opkódja: AA. Az opkód után ennél az utasításnál annyi 0 értékű bájt áll még, hogy az első operandus 4-el osztható bájton kezdődjön. A példában ehhez 2 bájt
          kell. Az utasítás minden operandusa int típusú, vagyis négy bájtból áll.</td>
      </tr>
      <tr class="tr2">
        <td>00 00 00 44</td>
        <td>A default ághoz tartozó kód kezdetének távolsága az opkódtól. Itt 68.</td>
      </tr>
      <tr class="tr1">
        <td>00 00 00 01</td>
        <td>Az utasítás case esetei által befogott intervallum minimuma.</td>
      </tr>
      <tr class="tr2">
        <td>00 00 00 05</td>
        <td>Az utasítás case esetei által befogott intervallum maximuma.</td>
      </tr>
      <tr class="tr1">
        <td>00 00 00 39</td>
        <td>A minimum értékhez (most 1) tartozó ág távolsága (itt 57).</td>
      </tr>
      <tr class="tr2">
        <td>00 00 00 2E</td>
        <td>A minimum+1 értékhez tartozó ág távolsága.</td>
      </tr>
      <tr class="tr1">
        <td>00 00 00 44</td>
        <td>A minimum+2 értékhez tartozó ág távolsága.</td>
      </tr>
      <tr class="tr2">
        <td>00 00 00 44</td>
        <td>A minimum+3 értékhez tartozó ág távolsága.</td>
      </tr>
      <tr class="tr1">
        <td>00 00 00 23</td>
        <td>A minimum+4 értékhez (itt a maximum) tartozó ág távolsága.</td>
      </tr>
    </tbody>
  </table>
  <p class="bekezd">
    Amint látható, a bájtkódban először következik a default ághoz tartozó kód távolsága, aztán a minimum és maximum értékek s csak aztán az egyes esetek. Amikor az utasítás végrehajtódik,
    az operandusverem tetején lévő értéket megvizsgálja a JVM, hogy a minimum és maximum közé esik-e. Ha nem, akkor a vezérlés a default ágra kerül. Ha igen, akkor az érték az utasításhoz
    tartozó célcím-táblázat indexelésére lesz felhasználva, így szinte azonnal végrehajtható az ugrás a megfelelő eset kódjára. Amennyiben hét case ágnál több eset lehetséges ezzel a
    módszerrel, a <span class="programkod">lookupswitch</span> utasítást használja a fordító. Ez történik a Java 7-ben bevezetett sztringeket kezelő switch esetén is. Mivel a <span
      class="programkod">lookupswitch</span> is csak int típussal képes dolgozni, ezért string típusú paraméter esetén a fordító előbb generál egy hashCode() metódushívást a paraméter
    sztringen, ami meghatározza a sztringnek megfelelő hash kódot és ez lesz aztán felhasználva a műveletnél. Tekintsük a következő példát:
  </p>
  <pre class="programkod">public void methodSwitch(String param) {
	switch (param) {
	case "egy":
		System.out.println(1);
		break;
	case "kettő":
		System.out.println(2);
		break;
	default:
	}
}
</pre>
  <p class="bekezd">A switch utasítás esetén tehát a generált kód esetében nincs különbség int vagy azzá konvertálható típusú paraméterekhez képest, csupán egy hashCode() metódushívás
    megelőzi a lookupswitch-et, ami aztán annak az eredményével fog dolgozni. Ez látható a bájtkódban:</p>
  <pre class="programkod">  public void methodSwitch(java.lang.String);
    Code:
       0: aload_1       
       1: dup           
       2: astore_2      
       3: invokevirtual #33                 // Method java/lang/String.hashCode:()I
       6: lookupswitch  { // 2
                100375: 32
             101941047: 44
               default: 73
          }
      32: aload_2       
      33: ldc           #28                 // String egy
      35: invokevirtual #39                 // Method java/lang/String.equals:
                                            // (Ljava/lang/Object;)Z
      38: ifne          56
      41: goto          73
      44: aload_2       
      45: ldc           #26                 // String kettő
      47: invokevirtual #39                 // Method java/lang/String.equals:
                                            // (Ljava/lang/Object;)Z
      50: ifne          66
      53: goto          73
      56: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
      59: iconst_1      
      60: invokevirtual #43                 // Method java/io/PrintStream.println:(I)V
      63: goto          73
      66: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
      69: iconst_2      
      70: invokevirtual #43                 // Method java/io/PrintStream.println:(I)V
      73: return        
</pre>
  <p class="bekezd">
    A <span class="programkod">lookupswitch</span> opkódja AB, ez is tartalmaz kiegészítő 0 bájtokat, ha szükséges. Ezt követi a default ág kódjának távolsága, a case ágak száma, majd a
    case esetek párjai, minden esetben elsőként az érték, aztán a kód távolsága. Az utasítás végrehajtásakor a JVM minden egyes esettel összehasonlítja a vermen lévő értéket és az ennek
    megfelelő ágra ugrik (a gyorsabb összehasonlítás érdekében a JVM specifikációja előírja, hogy az &quot;ágcímek&quot; sorba legyenek rendezve). Mivel string típusú paraméter esetén a
    hash kód van használva, ezért a string-switch több ág esetén gyorsabb, mintha if-else utasításokkal minden egyes változaton egy equals() függvényhívás lenne megadva.
  </p>
  <h3>Generikus osztályok</h3>
  <p class="bekezd">Végezetül viszgáljuk meg, a generikus osztályok hogyan működnek a bájtkód szintjén. A Java nyelvben a generikus programozás szigorúbb típusellenőrzést tesz lehetővé
    fordítási időben. A javac fordításkor ún. típustörlést végez, vagyis lecserél minden típusparamétert azok megadott ősére vagy ha ilyen nincs megadva, Object típusra. A generált bájtkód
    így generikus típus nélküli lesz. Ezen kívül ha szükséges, típuskényszerítést (cast) generál a kódba, hogy biztosítsa a típusbiztonságot valamint áthidaló metódusokat is létrehoz ha
    szükséges, hogy biztosítsa a polimorfizmust. Nézzük a következő osztályt:</p>
  <pre class="programkod">public class GenericsClass {
    List&lt;String&gt; array = new ArrayList&lt;&gt;();
    List array2 = new ArrayList();

    public void sampleMethod() {
        array.add(&quot;string&quot;);
        array2.add(&quot;string&quot;);
    }
}</pre>
  <p class="bekezd">
    A bájtkód vizsgálata azt mutatja, hogy mindkét lista ugyanúgy jön létre (az inicializálást a fordító a konstruktorba teszi) és az add metódus használatában sincs semmilyen különbség.
    Ami különbözik a két esetben, hogy az <span class="programkod">array</span> változónak van egy <span class="programkod">Signature</span> záradéka, amely a konstanskészletben kijelöli a
    mezőhöz tartozó pontos típust (a könnyebb áttekinthetőség érdekében a példa szempontjából lényegtelen adatokat kitöröltem).
  </p>
  <pre class="programkod">Constant pool:
   #8 = Utf8               Ljava/util/List&lt;Ljava/lang/String;&gt;;
{
  java.util.List&lt;java.lang.String&gt; array;
    Signature: #8                           // Ljava/util/List&lt;Ljava/lang/String;&gt;;

  java.util.List array2;

  public GenericsClass();
    flags: ACC_PUBLIC

    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      27     0  this   LGenericsClass;
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #13                 // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
         4: aload_0       
         5: new           #15                 // class java/util/ArrayList
         8: dup           
         9: invokespecial #17                 // Method java/util/ArrayList.&quot;&lt;init&gt;&quot;:()V
        12: putfield      #18                 // Field array:Ljava/util/List;
        15: aload_0       
        16: new           #15                 // class java/util/ArrayList
        19: dup           
        20: invokespecial #17                 // Method java/util/ArrayList.&quot;&lt;init&gt;&quot;:()V
        23: putfield      #20                 // Field array2:Ljava/util/List;
        26: return        
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      27     0  this   LGenericsClass;

  public void sampleMethod();
    flags: ACC_PUBLIC

    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      25     0  this   LGenericsClass;
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0       
         1: getfield      #18                 // Field array:Ljava/util/List;
         4: ldc           #27                 // String string
         6: invokeinterface #29,  2           // InterfaceMethod java/util/List.add:
                                              // (Ljava/lang/Object;)Z
        11: pop           
        12: aload_0       
        13: getfield      #20                 // Field array2:Ljava/util/List;
        16: ldc           #27                 // String string
        18: invokeinterface #29,  2           // InterfaceMethod java/util/List.add:
                                              // (Ljava/lang/Object;)Z
        23: pop           
        24: return        
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      25     0  this   LGenericsClass;
}
</pre>
  <p class="bekezd">Ez ez írás csak bevezetést adott a Java bájtkód világába, de minden Java programozónak érdemes megismerni legalább nagy vonalakban, mi is történik a motorház alatt.
    Az összeállításhoz nagyon sok internetes forrást felhasználtam, az alábbi listában felsorolom a legfontosabbakat.</p>
</body>
</html>