Obsah
2. Programová smyčka typu „for-each“ v programovacím jazyku Java
3. Demonstrační příklad Test23.java: pole a smyčka typu „for-each“ v JVM
4. Okomentovaný bajtkód demonstračního příkladu Test23.java
5. Demonstrační příklad Test24.java: seznamy a programová smyčka typu „for-each“ v JVM
6. Okomentovaný bajtkód demonstračního příkladu Test24.java
7. Demonstrační příklad Test25.java: množiny a programová smyčka typu „for-each“ v JVM
8. Okomentovaný bajtkód demonstračního příkladu Test25.java
9. Demonstrační příklad Test26.java: mapy a programová smyčka typu „for-each“ v JVM
10. Okomentovaný bajtkód demonstračního příkladu Test26.java
11. Repositář se zdrojovými kódy všech čtyř dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – složené datové typy a programová smyčka typu „for-each“ v JVM, Lua VM a Python VM
V předchozích dvou částech seriálu o programovacím jazyce Java i o JVM jsme si řekli, jakým způsobem se do bajtkódů virtuálních strojů Javy, Pythonu i jazyka Lua překládají základní operace se složenými datovými typy. Jedná se především o operace pro čtení a popř. i zápis prvků složených datových typů (polí, tabulek, seznamů, n-tic) a taktéž o operaci získání celkového počtu prvků daného složeného datového typu. V některých demonstračních příkladech jsme si taktéž ukázali způsob použití počítané programové smyčky typu for při přístupu k prvkům složených datových typů. Ve skutečnosti se ovšem velké množství operací (pravděpodobně většina operací) se složenými datovými typy neprovádí s využitím počítané smyčky typu for, ale spíše s použitím smyčky typu for-each, která je v určité podobě implementována ve všech třech virtuálních strojích (JVM, Lua VM i Python VM).
Dnes si na čtveřici demonstračních příkladů ukážeme, jakým způsobem se programová smyčka typu for-each používá a překládá v Javě. V navazující části tohoto seriálu na dnešní díl navážeme, protože si ukážeme ekvivalentní příklady, ovšem naprogramované v Pythonu, programovacím jazyce Lua a nově taktéž v Perlu 6.
2. Programová smyčka typu „for-each“ v programovacím jazyku Java
Programová smyčka typu for-each se v programovacím jazyku Java objevila ve verzi/specifikaci 5.0. Jednalo se o jedno z několika rozšíření tohoto jazyka, které bylo vyžadováno jak komunitou vývojářů, tak i de facto vynuceno situací na trhu, na němž se začaly ve větší míře prosazovat konkurenční programovací jazyky, především C# a taktéž dosti velká skupina vysokoúrovňových skriptovacích jazyků (Python, Ruby, …). Smyčku typu for-each lze v Javě využít pro postupné procházení všech prvků polí. Syntaxe v tomto případě vypadá následovně:
for (type variable : array) { tělo smyčky }
Výše uvedený zápis smyčky je do značné míry ekvivalentní počítané smyčce typu for, ovšem s tím rozdílem, že programátor nemá v předchozí verzi smyčky přístup k počitadlu i (hodnotu počitadla lze využít například při tvorbě tabulek atd.):
for (int i = 0; i < array.length; i++) { type variable = array[i]; tělo smyčky }
Kromě polí je možné programovou smyčku typu for-each použít i pro procházení všemi prvky kolekcí. Zápis je v tomto případě prakticky shodný se zápisem smyčky pro průchod všemi prvky pole:
for (type variable : collection) { tělo smyčky }
Tento zápis je ekvivalentní následujícímu zápisu; ovšem opět s tím rozdílem, že ve zkrácené for-each variantě nemá programátor přímý přístup k iterátoru, což může v některých případech komplikovat zápis algoritmu:
for (Iterator<type> iterator = collection.iterator(); iterator.hasNext(); ) { type variable = iterator.next(); tělo smyčky }
Ve skutečnosti se však použití smyčky for-each neomezuje pouze na pole a kolekce, ale lze ji využít pro instance všech tříd implementujících rozhraní Iterable<T>, tj. pro ty třídy, v nichž je implementována metoda Iterator<T> iterator(). Díky tomuto rozšíření sémantiky smyčky for-each lze implementovat například různé typy průchodů binárními stromy atd.
3. Demonstrační příklad Test23.java: pole a smyčka typu „for-each“ v JVM
Způsob překladu programové smyčky typu for-each do bajtkódu JVM si nejlépe ukážeme na několika demonstračních příkladech. V prvním demonstračním příkladu, který nese název Test23.java, je implementována přetížená metoda sum(), v jejímž těle se vypočítá suma/součet všech prvků pole, které je do této metody předáno (jako reference). Metoda je přetížená pro všech šest primitivních numerických datových typů – byte, short, int, long, float i double. Navíc je v tomto příkladu implementována i metoda hashsum(), v níž se vypočte součet hešovacích kódů všech objektů uložených v poli předaném do této metody. Ve všech zmíněných metodách je využita smyčka typu for-each pro průchod všemi prvky pole, nezávisle na typu prvků:
/** * Demonstracni priklad cislo 23. * * Pole a programova smycka typu for-each. */ public class Test23 { /** * Vypocet souctu vsech prvku pole typu byte[]. */ static int sum(byte[] array) { int sum = 0; for (byte item : array) { sum += item; } return sum; } /** * Vypocet souctu vsech prvku pole typu short[]. */ static int sum(short[] array) { int sum = 0; for (short item : array) { sum += item; } return sum; } /** * Vypocet souctu vsech prvku pole typu int[]. */ static int sum(int[] array) { int sum = 0; for (int item : array) { sum += item; } return sum; } /** * Vypocet souctu vsech prvku pole typu long[]. */ static long sum(long[] array) { long sum = 0; for (long item : array) { sum += item; } return sum; } /** * Vypocet souctu vsech prvku pole typu float[]. */ static float sum(float[] array) { float sum = 0; for (float item : array) { sum += item; } return sum; } /** * Vypocet souctu vsech prvku pole typu double[]. */ static double sum(double[] array) { double sum = 0; for (double item : array) { sum += item; } return sum; } /** * Vypocet souctu hesovacich kodu vsech prvku pole typu Object[]. */ static int hashsum(Object[] array) { int sum = 0; for (Object item : array) { sum += item.hashCode(); } return sum; } /** * Test demonstracnich metod. */ public static void main(String[] args) { byte[] byteArray = {1, 2, 3, 4}; short[] shortArray = {1, 2, 3, 4}; int[] intArray = {1, 2, 3, 4}; long[] longArray = {1L,2L,3L,4L}; float[] floatArray = {1f,2f,3f,4f}; double[] doubleArray = {1.,2.,3.,4.}; String[] stringArray = {"1","2","3","4"}; System.out.println(sum(byteArray)); System.out.println(sum(shortArray)); System.out.println(sum(intArray)); System.out.println(sum(longArray)); System.out.println(sum(floatArray)); System.out.println(sum(doubleArray)); System.out.println(hashsum(stringArray)); } }
4. Okomentovaný bajtkód demonstračního příkladu Test23.java
Podívejme se nyní na způsob překladu jednotlivých metod z demonstračního příkladu Test23.java do bajtkódu JVM. První metoda sum(byte[]) využívá pět pozic (slotů) na zásobníkovém rámci, které jsou vyhrazeny pro lokální proměnné, ať již proměnné explicitně zapsané programátorem, nebo pomocné proměnné využívané interpretrem bajtkódu:
Pozice | Lokální proměnná |
---|---|
1 | lokální proměnná sum |
2 | reference na zpracovávané pole |
3 | délka zpracovávaného pole |
4 | hodnota počitadla smyčky for, nazvěme počitadlo i |
5 | hodnota právě zpracovávaného prvku pole (i-tý prvek) |
Z výpisu bajtkódu je patrné, že i když byla použita programová smyčka typu for-each, provedl se překlad takovým způsobem, jakoby programátor ve skutečnosti použil počítanou programovou smyčku typu for:
static int sum(byte[]); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník 3: astore_2 // reference na zpracovávané pole je umístěna do druhé lokální proměnné 4: aload_2 5: arraylength // vypočítat délku pole a uložit na TOS 6: istore_3 // uložit délku pole do třetí lokální proměnné 7: iconst_0 // počáteční hodnota počitadla 8: istore 4 // uložit do čtvrté lokální proměnné 10: iload 4 // začátek programové smyčky "for" 12: iload_3 // porovnat hodnotu počitadla s délkou pole 13: if_icmpge 33 // test na ukončení programové smyčky 16: aload_2 // načíst referenci na pole 17: iload 4 // hodnota počitadla je použita jako index 19: baload // získat i-tý prvek z pole typu byte[] (i=hodnota počitadla) 20: istore 5 // uložit hodnotu prvku do páté lokální proměnné 22: iload_1 // lokální proměnná "sum" na TOS 23: iload 5 25: iadd // přičíst k proměnné "sum" hodnotu i-tého prvku pole 26: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 27: iinc 4, 1 // zvýšit hodnotu počitadla o jedničku 30: goto 10 // skok na začátek programové smyčky 33: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 34: ireturn // a vrátit ji jako výsledek metody
Prakticky stejný překlad byl proveden pro metodu sum(short[]), pouze s tím rozdílem, že se namísto instrukce baload použila pro čtení prvku pole instrukce saload:
static int sum(short[]); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník 3: astore_2 // reference na zpracovávané pole je umístěna do druhé lokální proměnné 4: aload_2 5: arraylength // vypočítat délku pole a uložit na TOS 6: istore_3 // uložit délku pole do třetí lokální proměnné 7: iconst_0 // počáteční hodnota počitadla 8: istore 4 // uložit do čtvrté lokální proměnné 10: iload 4 // začátek programové smyčky "for" 12: iload_3 // porovnat hodnotu počitadla s délkou pole 13: if_icmpge 33 // test na ukončení programové smyčky 16: aload_2 // načíst referenci na pole 17: iload 4 // hodnota počitadla je použita jako index 19: saload // získat i-tý prvek z pole typu short[] (i=hodnota počitadla) 20: istore 5 // uložit hodnotu prvku do páté lokální proměnné 22: iload_1 // lokální proměnná "sum" na TOS 23: iload 5 25: iadd // přičíst k proměnné "sum" hodnotu i-tého prvku pole 26: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 27: iinc 4, 1 // zvýšit hodnotu počitadla o jedničku 30: goto 10 // skok na začátek programové smyčky 33: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 34: ireturn // a vrátit ji jako výsledek metody
Totéž platí i pro překlad metody sum(int[]), jen se namísto baload/saload využívá – podle očekávání – instrukce iaload:
static int sum(int[]); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník 3: astore_2 // reference na zpracovávané pole je umístěna do druhé lokální proměnné 4: aload_2 5: arraylength // vypočítat délku pole a uložit na TOS 6: istore_3 // uložit délku pole do třetí lokální proměnné 7: iconst_0 // počáteční hodnota počitadla 8: istore 4 // uložit do čtvrté lokální proměnné 10: iload 4 // začátek programové smyčky "for" 12: iload_3 // porovnat hodnotu počitadla s délkou pole 13: if_icmpge 33 // test na ukončení programové smyčky 16: aload_2 // načíst referenci na pole 17: iload 4 // hodnota počitadla je použita jako index 19: iaload // získat i-tý prvek z pole typu int[] (i=hodnota počitadla) 20: istore 5 // uložit hodnotu prvku do páté lokální proměnné 22: iload_1 // lokální proměnná "sum" na TOS 23: iload 5 25: iadd // přičíst k proměnné "sum" hodnotu i-tého prvku pole 26: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 27: iinc 4, 1 // zvýšit hodnotu počitadla o jedničku 30: goto 10 // skok na začátek programové smyčky 33: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 34: ireturn // a vrátit ji jako výsledek metody
Překlad metody sum(long[]) je poněkud odlišný, a to zejména proto, že lokální proměnné typu long jsou uloženy ve dvou pozicích/slotech. Celkový počet obsazených slotů na zásobníkovém rámci je tedy o dvě vyšší než u předchozích tří variant metody sum():
Pozice | Lokální proměnná |
---|---|
1+2 | lokální proměnná sum |
3 | reference na zpracovávané pole |
4 | délka zpracovávaného pole |
5 | hodnota počitadla smyčky for, nazvěme počitadlo i |
6 | hodnota právě zpracovávaného prvku pole (i-tý prvek) |
Bajtkód přeložené metody sum(long[]):
static long sum(long[]); Code: 0: lconst_0 // počáteční hodnota lokální proměnné "sum" 1: lstore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník 3: astore_3 // reference na zpracovávané pole je umístěna do třetí lokální proměnné 4: aload_3 5: arraylength // vypočítat délku pole a uložit na TOS 6: istore 4 // uložit délku pole do čtvrté lokální proměnné 8: iconst_0 // počáteční hodnota počitadla 9: istore 5 // uložit do páté lokální proměnné 11: iload 5 // začátek programové smyčky "for" 13: iload 4 // porovnat hodnotu počitadla s délkou pole 15: if_icmpge 35 // test na ukončení programové smyčky 18: aload_3 // načíst referenci na pole 19: iload 5 // hodnota počitadla je použita jako index 21: laload // získat i-tý prvek z pole typu long[] (i=hodnota počitadla) 22: lstore 6 // uložit hodnotu prvku do šesté lokální proměnné 24: lload_1 // lokální proměnná "sum" na TOS 25: lload 6 27: ladd // přičíst k proměnné "sum" hodnotu i-tého prvku pole 28: lstore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 29: iinc 5, 1 // zvýšit hodnotu počitadla o jedničku 32: goto 11 // skok na začátek programové smyčky 35: lload_1 // načíst aktuální hodnotu lokální proměnné "sum" 36: lreturn // a vrátit ji jako výsledek metody
Metoda sum(float[]) je přeložena podobně, jako tomu bylo u metody sum(int[]), samozřejmě až na rozdíly v některých instrukcích (iconst0/fconst0, iload1/fload1, iadd/fadd atd.):
static float sum(float[]); Code: 0: fconst_0 // počáteční hodnota lokální proměnné "sum" 1: fstore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník 3: astore_2 // reference na zpracovávané pole je umístěna do druhé lokální proměnné 4: aload_2 5: arraylength // vypočítat délku pole a uložit na TOS 6: istore_3 // uložit délku pole do třetí lokální proměnné 7: iconst_0 // počáteční hodnota počitadla 8: istore 4 // uložit do čtvrté lokální proměnné 10: iload 4 // začátek programové smyčky "for" 12: iload_3 // porovnat hodnotu počitadla s délkou pole 13: if_icmpge 33 // test na ukončení programové smyčky 16: aload_2 // načíst referenci na pole 17: iload 4 // hodnota počitadla je použita jako index 19: faload // získat i-tý prvek z pole typu float[] (i=hodnota počitadla) 20: fstore 5 // uložit hodnotu prvku do páté lokální proměnné 22: fload_1 // lokální proměnná "sum" na TOS 23: fload 5 25: fadd // přičíst k proměnné "sum" hodnotu i-tého prvku pole 26: fstore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 27: iinc 4, 1 // zvýšit hodnotu počitadla o jedničku 30: goto 10 // skok na začátek programové smyčky 33: fload_1 // načíst aktuální hodnotu lokální proměnné "sum" 34: freturn // a vrátit ji jako výsledek metody
U metody sum(double[]) platí stejná poznámka, jaká byla uvedena v případě sum(long[]), tj. proměnné typu long i double obsazují vždy dvě pozice/sloty na zásobníkovém rámci:
static double sum(double[]); Code: 0: dconst_0 // počáteční hodnota lokální proměnné "sum" 1: dstore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník 3: astore_3 // reference na zpracovávané pole je umístěna do třetí lokální proměnné 4: aload_3 5: arraylength // vypočítat délku pole a uložit na TOS 6: istore 4 // uložit délku pole do čtvrté lokální proměnné 8: iconst_0 // počáteční hodnota počitadla 9: istore 5 // uložit do páté lokální proměnné 11: iload 5 // začátek programové smyčky "for" 13: iload 4 // porovnat hodnotu počitadla s délkou pole 15: if_icmpge 35 // test na ukončení programové smyčky 18: aload_3 // načíst referenci na pole 19: iload 5 // hodnota počitadla je použita jako index 21: daload // získat i-tý prvek z pole typu double[] (i=hodnota počitadla) 22: dstore 6 // uložit hodnotu prvku do šesté lokální proměnné 24: dload_1 // lokální proměnná "sum" na TOS 25: dload 6 27: dadd // přičíst k proměnné "sum" hodnotu i-tého prvku pole 28: dstore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 29: iinc 5, 1 // zvýšit hodnotu počitadla o jedničku 32: goto 11 // skok na začátek programové smyčky 35: dload_1 // načíst aktuální hodnotu lokální proměnné "sum" 36: dreturn // a vrátit ji jako výsledek metody
static int hashsum(java.lang.Object[]); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník 3: astore_2 // reference na zpracovávané pole je umístěna do druhé lokální proměnné 4: aload_2 5: arraylength // vypočítat délku pole a uložit na TOS 6: istore_3 // uložit délku pole do třetí lokální proměnné 7: iconst_0 // počáteční hodnota počitadla 8: istore 4 // uložit do čtvrté lokální proměnné 10: iload 4 // začátek programové smyčky "for" 12: iload_3 // porovnat hodnotu počitadla s délkou pole 13: if_icmpge 33 // test na ukončení programové smyčky 16: aload_2 // načíst referenci na pole 17: iload 4 // hodnota počitadla je použita jako index 19: aaload // získat i-tý prvek (=referenci) z pole typu Object[] (i=hodnota počitadla) 20: astore 5 // uložit hodnotu prvku (=referenci) do páté lokální proměnné 22: iload_1 // lokální proměnná "sum" na TOS 23: aload 5 // výpočet hešovacího kódu 25: invokevirtual #2; // Method java/lang/Object.hashCode:()I 28: iadd // přičíst k proměnné "sum" hodnotu hešovacího kódu i-tého prvku pole 29: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 30: iinc 4, 1 // zvýšit hodnotu počitadla o jedničku 33: goto 10 // skok na začátek programové smyčky 36: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 37: ireturn // a vrátit ji jako výsledek metody
5. Demonstrační příklad Test24.java: seznamy a programová smyčka typu „for-each“ v JVM
V dnešním druhém demonstračním příkladu s názvem Test24.java je na dvojici metod pojmenovaných sum() a hashsum() ukázáno použití programové smyčky typu for-each při průchodu všemi prvky uloženými do seznamu, tj. do kolekce implementující rozhraní List. V metodě sum() se předpokládá, že všechny prvky seznamu budou typu Integer, což je kontrolováno jak při překladu, tak i při běhu aplikace (protože překladač nedokáže kvůli dynamickému linkování zaručit, jak bude metoda sum() přesně volána):
/** * Demonstracni priklad cislo 24. * * Seznamy a programova smycka typu for-each. */ import java.util.List; public class Test24 { /** * Vypocet souctu vsech prvku seznamu typu List<Integer>. */ static int sum(List<Integer> list) { int sum = 0; for (int item : list) { sum += item; } return sum; } /** * Vypocet souctu hesovacich kodu vsech prvku seznamu typu List<? extends Object>. */ static int hashsum(List<? extends Object> list) { int sum = 0; for (Object item : list) { sum += item.hashCode(); } return sum; } /** * Test demonstracnich metod. */ public static void main(String[] args) { List<Integer> integerList = java.util.Arrays.asList(1,2,3,4); List<? extends Object> objectList = java.util.Arrays.asList("1","2","3","4"); System.out.println(sum(integerList)); System.out.println(hashsum(objectList)); } }
6. Okomentovaný bajtkód demonstračního příkladu Test24.java
Metoda sum(java.util.List) (povšimněte si, že se při překladu „vytratila“ informace o typu prvků seznamů, což však přesně odpovídá specifikaci Javy) využívá na zásobníkovém rámci kupodivu pouze tři pozice/sloty, což je značný rozdíl oproti předchozímu příkladu, v němž se používalo většinou pět slotů:
Pozice | Lokální proměnná |
---|---|
1 | lokální proměnná sum |
2 | reference na iterátor získaný pro seznam |
3 | hodnota právě zpracovávaného prvku seznamu |
Překlad metody sum(java.util.List) je přímočarý a odpovídá očekávání. Nejprve se získá iterátor pro seznam a posléze se volají metody Iterator.hasNext() pro test ukončení smyčky a Iterator.next() pro přečtení dalšího prvku. Zajímavá je však instrukce checkcast pro otestování typu každého prvku v seznamu, což je důležité, neboť již víme, že se tato informace „vytratila“ z hlavičky metody (je jen součástí metadat):
static int sum(java.util.List); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník // získat iterátor pro kolekci (zde konkrétně seznam) 3: invokeinterface #2, 1; // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 8: astore_2 // uložit iterátor do druhé lokální proměnné 9: aload_2 // začátek programové smyčky // test na ukončení programové smyčky 10: invokeinterface #3, 1; // InterfaceMethod java/util/Iterator.hasNext:()Z 15: ifeq 38 // po dosažení konce kolekce se programová smyčka ukončí 18: aload_2 // načíst iterátor na TOS // čtení prvku z kolekce 19: invokeinterface #4, 1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; // test, zda je prvek skutečně typu Integer 24: checkcast #5; // class java/lang/Integer // převod z Integer na int 27: invokevirtual #6; // Method java/lang/Integer.intValue:()I 30: istore_3 // hodnotu prvku uložit do třetí lokální proměnné 31: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 32: iload_3 // načíst hodnotu prvku z kolekce 33: iadd // přičíst k proměnné "sum" hodnotu prvku kolekce 34: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 35: goto 9 // skok na začátek programové smyčky 38: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 39: ireturn // a vrátit ji jako výsledek metody
Podobným způsobem je zkonstruován i bajtkód metody hashsum(), v níž se však namísto čtení a zpracování objektů typu Integer volá pro všechny objekty nalezené v seznamu metoda Object.hashCode(). I z tohoto důvodu zde již nenalezneme použití instrukce checkcast:
static int hashsum(java.util.List); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník // získat iterátor pro kolekc (zde konkrétně pro seznam) 3: invokeinterface #2, 1; // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 8: astore_2 // uložit iterátor do druhé lokální proměnné 9: aload_2 // začátek programové smyčky // test na ukončení programové smyčky 10: invokeinterface #3, 1; // InterfaceMethod java/util/Iterator.hasNext:()Z 15: ifeq 35 // po dosažení konce kolekce se programová smyčka ukončí 18: aload_2 // načíst iterátor na TOS // čtení prvku z kolekce 19: invokeinterface #4, 1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 24: astore_3 // hodnotu prvku uložit do třetí lokální proměnné 25: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 26: aload_3 // načíst hodnotu prvku (=referenci) z kolekce // výpočet hešovacího kódu objektu 27: invokevirtual #7; // Method java/lang/Object.hashCode:()I 30: iadd // přičíst k proměnné "sum" hodnotu prvku kolekce 31: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 32: goto 9 // skok na začátek programové smyčky 35: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 36: ireturn // a vrátit ji jako výsledek metody
7. Demonstrační příklad Test25.java: množiny a programová smyčka typu „for-each“ v JVM
Další, dnes již třetí demonstrační příklad se jmenuje Test25.java. Jeho zdrojový kód se do značné míry podobá zdrojovému kódu předchozího demonstračního příkladu Test24.java, až na ten rozdíl, že se namísto prvků uložených do seznamů prochází všemi prvky množiny, tj. jakékoli kolekce implementující rozhraní Set. Povšimněte si, že těla metod jsou shodná s předchozím demonstračním příkladem, což vlastně není příliš překvapivé, když si uvědomíme, že jak seznamy, tak i množiny implementují rozhraní Iterable a programová smyčka typu for-each je určena mj. právě pro využití iterátorů:
/** * Demonstracni priklad cislo 25. * * Mnoziny a programova smycka typu for-each. */ import java.util.Arrays; import java.util.Set; import java.util.TreeSet; public class Test25 { /** * Vypocet souctu vsech prvku mnoziny typu Set<Integer>. */ static int sum(Set<Integer> set) { int sum = 0; for (int item : set) { sum += item; } return sum; } /** * Vypocet souctu hesovacich kodu vsech prvku mnoziny typu Set<Object>. */ static int hashsum(Set<? extends Object> set) { int sum = 0; for (Object item : set) { sum += item.hashCode(); } return sum; } /** * Test demonstracnich metod. */ public static void main(String[] args) { Set<Integer> integerSet = new TreeSet(Arrays.asList(1,2,3,4)); Set<? extends Object> objectSet = new TreeSet(Arrays.asList("1","2","3","4")); System.out.println(sum(integerSet)); System.out.println(hashsum(objectSet)); } }
8. Okomentovaný bajtkód demonstračního příkladu Test25.java
Bajtkód vzniklý překladem demonstračního příkladu Test25.java je až na několik malých rozdílů prakticky stejný jako bajtkód předchozího příkladu Test24.java. Nejprve si ukažme, jakým způsobem jsou využity pozice/sloty alokované v zásobníkovém rámci (stack frame):
Pozice | Lokální proměnná |
---|---|
1 | lokální proměnná sum |
2 | reference na iterátor získaný pro množinu |
3 | hodnota právě zpracovávaného prvku množiny |
Nyní již následuje okomentovaný výpis bajtkódu příkladu Test25.java:
static int sum(java.util.Set); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník // získat iterátor pro kolekci (zde konkrétně množinu) 3: invokeinterface #2, 1; // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator; 8: astore_2 // uložit iterátor do druhé lokální proměnné 9: aload_2 // začátek programové smyčky // test na ukončení programové smyčky 10: invokeinterface #3, 1; // InterfaceMethod java/util/Iterator.hasNext:()Z 15: ifeq 38 // po dosažení konce kolekce se programová smyčka ukončí 18: aload_2 // načíst iterátor na TOS // čtení prvku z kolekce 19: invokeinterface #4, 1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; // test, zda je prvek skutečně typu Integer 24: checkcast #5; // class java/lang/Integer // převod z Integer na int 27: invokevirtual #6; // Method java/lang/Integer.intValue:()I 30: istore_3 // hodnotu prvku uložit do třetí lokální proměnné 31: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 32: iload_3 // načíst hodnotu prvku z kolekce 33: iadd // přičíst k proměnné "sum" hodnotu prvku kolekce 34: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 35: goto 9 // skok na začátek programové smyčky 38: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 39: ireturn // a vrátit ji jako výsledek metody
static int hashsum(java.util.Set); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník // získat iterátor pro kolekc (zde konkrétně pro množinu) 3: invokeinterface #2, 1; // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator; 8: astore_2 // uložit iterátor do druhé lokální proměnné 9: aload_2 // začátek programové smyčky // test na ukončení programové smyčky 10: invokeinterface #3, 1; // InterfaceMethod java/util/Iterator.hasNext:()Z 15: ifeq 35 // po dosažení konce kolekce se programová smyčka ukončí 18: aload_2 // načíst iterátor na TOS // čtení prvku z kolekce 19: invokeinterface #4, 1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 24: astore_3 // hodnotu prvku uložit do třetí lokální proměnné 25: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 26: aload_3 // načíst hodnotu prvku (=referenci) z kolekce // výpočet hešovacího kódu objektu 27: invokevirtual #7; // Method java/lang/Object.hashCode:()I 30: iadd // přičíst k proměnné "sum" hodnotu prvku kolekce 31: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 32: goto 9 // skok na začátek programové smyčky 35: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 36: ireturn // a vrátit ji jako výsledek metody
9. Demonstrační příklad Test26.java: mapy a programová smyčka typu „for-each“ v JVM
V dnešním posledním demonstračním příkladu, který nese název Test26.java, se ve dvojici metod sum1() a sum2() prochází mapou, tj. takovou datovou strukturou, v níž jsou uloženy dvojice klíč:hodnota, přičemž klíče musí být v rámci jedné mapy jednoznačné a unikátní. V metodě sum1() se sčítají celočíselné klíče, zatímco v metodě sum2() dochází k součtu (taktéž celočíselných) hodnot. V obou zmíněných metodách je samozřejmě využita programová smyčka typu for-each pro procházení prvky množiny typu Map.Entry:
/** * Demonstracni priklad cislo 26. * * Mapy a programova smycka typu for-each. */ import java.util.Map; import java.util.TreeMap; public class Test26 { /** * Vypocet souctu klicu vsech prvku mapy typu Map<Integer,Integer>. */ static int sum1(Map<Integer,Integer> map) { int sum = 0; for (Map.Entry<Integer,Integer> item : map.entrySet()) { sum += item.getKey(); } return sum; } /** * Vypocet souctu hodnot vsech prvku mapy typu Map<Integer,Integer>. */ static int sum2(Map<Integer,Integer> map) { int sum = 0; for (Map.Entry<Integer,Integer> item : map.entrySet()) { sum += item.getValue(); } return sum; } /** * Test demonstracnich metod. */ public static void main(String[] args) { Map<Integer, Integer> map = new TreeMap<Integer,Integer>(); for (int i=0; i<=4; i++) { map.put(i,i); } System.out.println(sum1(map)); System.out.println(sum2(map)); } }
10. Okomentovaný bajtkód demonstračního příkladu Test26.java
Před popisem bajtkódu demonstračního příkladu Test26.java se podívejme, podobně jako tomu bylo u všech tří předchozích demonstračních příkladů, na obsazení zásobníkového rámce:
Pozice | Lokální proměnná |
---|---|
1 | lokální proměnná sum |
2 | reference na iterátor získaný pro mapu s prvky typu Map.Entry |
3 | hodnota právě zpracovávaného prvku mapy (typ Map.Entry) |
Bajtkód metody sum1() je poměrně dlouhý, a to především z toho důvodu, že se pro průchod mapou musí nejdříve získat množina s prvky Map.Entry, a to konkrétně s využitím metody Map.entrySet(). Následně se získá iterátor pro tuto množinu a při průchodu všemi prvky vracenými iterátorem se (zbytečně) provádí test na jejich typ s využitím instrukce checkcast. Stejná instrukce je použita pro testování typu klíče – opět se zde ukazuje, jaké problémy způsobuje fakt, že typ prvků/klíčů/hodnot není jednoznačnou součástí popisu datového typu kolekce:
static int sum1(java.util.Map); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník // získat objekt typu Map.Entry 3: invokeinterface #2, 1; // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set; // získat iterátor pro kolekci (zde konkrétně množinu) 8: invokeinterface #3, 1; // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator; 13: astore_2 // uložit iterátor do druhé lokální proměnné 14: aload_2 // začátek programové smyčky // test na ukončení programové smyčky 15: invokeinterface #4, 1; // InterfaceMethod java/util/Iterator.hasNext:()Z 20: ifeq 51 // po dosažení konce kolekce se programová smyčka ukončí 23: aload_2 // načíst iterátor na TOS // čtení prvku z kolekce 24: invokeinterface #5, 1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; // test, zda je prvek skutečně typu Map.Entry (to musí být celkem zbytečná konstrukce) 29: checkcast #6; // class java/util/Map$Entry 32: astore_3 // uložit objekt vrácený iterátorem z TOS do třetí lokální proměnné 33: iload_1 // načíst hodnotu lokální proměnné "sum" 34: aload_3 // uložit objekt vrácený iterátorem na TOS // získat klíč z dvojice Map.Entry 35: invokeinterface #7, 1; // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object; // test, zda je klíč typu Integer 40: checkcast #8; // class java/lang/Integer // převod z Integer na int 43: invokevirtual #9; // Method java/lang/Integer.intValue:()I 46: iadd // přičíst k proměnné "sum" hodnotu prvku kolekce 47: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 48: goto 14 // skok na začátek programové smyčky 51: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 52: ireturn // a vrátit ji jako výsledek metody
Bajtkód metody sum2() se od bajtkódu metody sum1() liší pouze v jednom ohledu – získávají a zpracovávají se zde hodnoty, nikoli klíče, tj. pro objekty typu Map.Entry se volá metoda getValue() a nikoli metoda getKey():
static int sum2(java.util.Map); Code: 0: iconst_0 // počáteční hodnota lokální proměnné "sum" 1: istore_1 // inicializace lokální proměnné "sum" 2: aload_0 // uložit první (jediný) parametr metody na zásobník // získat objekt typu Map.Entry 3: invokeinterface #2, 1; // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set; // získat iterátor pro kolekci (zde konkrétně množinu) 8: invokeinterface #3, 1; // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator; 13: astore_2 // uložit iterátor do druhé lokální proměnné 14: aload_2 // začátek programové smyčky // test na ukončení programové smyčky 15: invokeinterface #4, 1; // InterfaceMethod java/util/Iterator.hasNext:()Z 20: ifeq 51 // po dosažení konce kolekce se programová smyčka ukončí 23: aload_2 // načíst iterátor na TOS // čtení prvku z kolekce 24: invokeinterface #5, 1; // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; // test, zda je prvek skutečně typu Map.Entry (to musí být celkem zbytečná konstrukce) 29: checkcast #6; // class java/util/Map$Entry 32: astore_3 // uložit objekt vrácený iterátorem z TOS do třetí lokální proměnné 33: iload_1 // načíst hodnotu lokální proměnné "sum" 34: aload_3 // uložit objekt vrácený iterátorem na TOS // získat hodnotu (value) z dvojice Map.Entry 35: invokeinterface #10, 1;// InterfaceMethod java/util/Map$Entry.getValue:()Ljava/lang/Object; // test, zda je hodnota typu Integer 40: checkcast #8; // class java/lang/Integer // převod z Integer na int 43: invokevirtual #9; // Method java/lang/Integer.intValue:()I 46: iadd // přičíst k proměnné "sum" hodnotu prvku kolekce 47: istore_1 // přenos hodnoty z TOS do lokální proměnné "sum" 48: goto 14 // skok na začátek programové smyčky 51: iload_1 // načíst aktuální hodnotu lokální proměnné "sum" 52: ireturn // a vrátit ji jako výsledek metody
11. Repositář se zdrojovými kódy všech čtyř dnešních demonstračních příkladů
Všechny čtyři dnes popsané a využité demonstrační příklady (naprogramované v Javě, protože příklady pro jazyky Python a Lua budou popsány příště) byly uloženy do Mercurial repositáře umístěného na adrese http://icedtea.classpath.org/people/ptisnovs/jvm-tools/. Odkazy na prozatím poslední verze těchto příkladů naleznete v tabulce pod tímto odstavcem:
12. Odkazy na Internetu
- For-each Loop in Java
http://www.leepoint.net/notes-java/flow/loops/foreach.html - Programming in Lua (first edition)
http://www.lua.org/pil/contents.html - Programming in Lua: Numeric for
http://www.lua.org/pil/4.3.4.html - Programming in Lua: break and return
http://www.lua.org/pil/4.4.html - Programming in Lua: Tables
http://www.lua.org/pil/2.5.html - Programming in Lua: Table Constructors
http://www.lua.org/pil/3.6.html - Programovací jazyk Lua
http://palmknihy.cz/web/kniha/programovaci-jazyk-lua-12651.htm - Lua: Tables Tutorial
http://lua-users.org/wiki/TablesTutorial - Lua: Control Structure Tutorial
http://lua-users.org/wiki/ControlStructureTutorial - Lua Types Tutorial
http://lua-users.org/wiki/LuaTypesTutorial - Goto Statement in Lua
http://lua-users.org/wiki/GotoStatement - Python break, continue and pass Statements
http://www.tutorialspoint.com/python/python_loop_control.htm - For Loop (Wikipedia)
http://en.wikipedia.org/wiki/For_loop - Heinz Rutishauser
http://en.wikipedia.org/wiki/Heinz_Rutishauser - Parrot
http://www.parrot.org/ - Parrot languages
http://www.parrot.org/languages - Parrot Primer
http://docs.parrot.org/parrot/latest/html/docs/intro.pod.html - Parrot Opcodes
http://docs.parrot.org/parrot/latest/html/ops.html - Parrot VM
http://en.wikibooks.org/wiki/Parrot_Virtual_Machine - Parrot Assembly Language
http://www.perl6.org/archive/pdd/pdd06_pasm.html - Parrot Reference: Chapter 11 – Perl 6 and Parrot Essentials
http://oreilly.com/perl/excerpts/perl-6-and-parrot-essentials/parrot-reference.html - Python Bytecode: Fun With Dis
http://akaptur.github.io/blog/2013/08/14/python-bytecode-fun-with-dis/ - Python's Innards: Hello, ceval.c!
http://tech.blog.aknin.name/category/my-projects/pythons-innards/ - Byterun
https://github.com/nedbat/byterun - Python Byte Code Instructions
http://document.ihg.uni-duisburg.de/Documentation/Python/lib/node56.html - Python Byte Code Instructions
https://docs.python.org/3.2/library/dis.html#python-bytecode-instructions - Lua 5.2 sources
http://www.lua.org/source/5.2/ - Lua 5.2 sources – lopcodes.h
http://www.lua.org/source/5.2/lopcodes.h.html - Lua 5.2 sources – lopcodes.c
http://www.lua.org/source/5.2/lopcodes.c.html - dis – Python module
https://docs.python.org/2/library/dis.html - Comparison of Python virtual machines
http://polishlinux.org/apps/cli/comparison-of-python-virtual-machines/ - O-code
http://en.wikipedia.org/wiki/O-code_machine - BCPL
http://en.wikipedia.org/wiki/BCPL - The BCPL Cintcode System and Cintpos User Guide by Martin Richards
http://www.cl.cam.ac.uk/users/mr/bcplman.pdf - Bootstrapping the BCPL Compiler using INTCODE
http://www.gtoal.com/languages/bcpl/amiga/bcpl/booting.txt - p-code machine
http://en.wikipedia.org/wiki/P-code_machine - ucsd-psystem-vm 0.11 (a portable virtual machine for the UCSD p-System)
http://ucsd-psystem-vm.sourceforge.net/ - Introduction to Smalltalk bytecodes
http://marianopeck.wordpress.com/2011/05/21/introduction-to-smalltalk-bytecodes/ - Audio File Formats.
http://sox.sourceforge.net/AudioFormats-11.html - TestSounds.com: pure digital sounds to test your audio
http://www.testsounds.com/ - Test Tones (20hz – 20khz)
http://mdf1.tripod.com/test-tones.html - WAV (Wikipedia)
http://en.wikipedia.org/wiki/WAV - WAVE PCM soundfile format
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ - Audio Interchange File Format
http://en.wikipedia.org/wiki/Aiff - Musical Instrument Digital Interface,
http://en.wikipedia.org/wiki/Musical_Instrument_Digital_Interface - A MIDI Pedalboard Encode,
http://www.pykett.org.uk/a_midi_pedalboard_encoder.htm - MIDI Note Number, Frequency Table,
http://tonalsoft.com/pub/news/pitch-bend.aspx - Note names, MIDI numbers and frequencies,
http://www.phys.unsw.edu.au/jw/notes.html - The MIDI Specification,
http://www.gweep.net/~prefect/eng/reference/protocol/midispec.html - Essentials of the MIDI protocol,
http://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html - General MIDI,
http://en.wikipedia.org/wiki/General_MIDI - Obecné MIDI (General MIDI),
http://www-kiv.zcu.cz/~herout/html_sbo/midi/5.html - Custom Chips: Paula
http://www.amiga-hardware.com/showhardware.cgi?HARDID=1460 - Big Book of Amiga Hardware
http://www.amiga-resistance.info/bboahfaq/ - Amiga Hardware Database
http://amiga.resource.cx/ - ExoticA
http://www.exotica.org.uk/wiki/Main_Page - The absolute basics of Amiga audio
http://www.sufo.estates.co.uk/amiga/amimus.html - Wikipedia: Tracker
http://en.wikipedia.org/wiki/Tracker - Wikipedia: Trackers
http://en.wikipedia.org/wiki/Trackers - Ultimate Soundtracker
http://en.wikipedia.org/wiki/Ultimate_Soundtracker - Protracker
http://en.wikipedia.org/wiki/ProTracker - Impulse Tracker
http://en.wikipedia.org/wiki/Impulse_Tracker - Scream Tracker
http://en.wikipedia.org/wiki/ScreamTracker - MikMod for Java
http://jmikmod.berlios.de/ - List of audio trackers
http://en.wikipedia.org/wiki/List_of_audio_trackers - Wikipedia: Module File
http://en.wikipedia.org/wiki/Module_file - Wikipedia: Chiptune
http://en.wikipedia.org/wiki/Chiptune - SDL_mixer 2.0
http://www.libsdl.org/projects/SDL_mixer/ - SDLJava: package sdljava.ttf
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/package-summary.html#package_description - SDLJava: class sdljava.ttf.SDLTTF
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTTF.html - SDLJava: class sdljava.ttf.SDLTrueTypeFont
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTrueTypeFont.html - SDL_ttf Documentation
http://www.libsdl.org/projects/SDL_ttf/docs/ - SDL_ttf 2.0 (není prozatím součástí SDLJava)
http://www.libsdl.org/projects/SDL_ttf/ - SDL_ttf doc
http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf_frame.html - SDL 1.2 Documentation: SDL_Surface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html - SDL 1.2 Documentation: SDL_PixelFormat
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html - SDL 1.2 Documentation: SDL_LockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html - SDL 1.2 Documentation: SDL_UnlockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html - SDL 1.2 Documentation: SDL_LoadBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html - SDL 1.2 Documentation: SDL_SaveBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html - SDL 1.2 Documentation: SDL_BlitSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html - SDL 1.2 Documentation: SDL_VideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html - SDL 1.2 Documentation: SDL_GetVideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html - glDrawArrays
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArrays.xml - glDrawElements
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElements.xml - glDrawArraysInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArraysInstanced.xml - glDrawElementsInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElementsInstanced.xml - Root.cz: Seriál Grafická knihovna OpenGL
http://www.root.cz/serialy/graficka-knihovna-opengl/ - Root.cz: Seriál Tvorba přenositelných grafických aplikací využívajících knihovnu GLUT
http://www.root.cz/serialy/tvorba-prenositelnych-grafickych-aplikaci-vyuzivajicich-knihovnu-glut/ - Best Practices for Working with Vertex Data
https://developer.apple.com/library/ios/documentation/3ddrawing/conceptual/opengles_programmingguide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html - Class BufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferStrategy.html - Class Graphics
http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Graphics.html - Double Buffering and Page Flipping
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html - BufferStrategy and BufferCapabilities
http://docs.oracle.com/javase/tutorial/extra/fullscreen/bufferstrategy.html - Java:Tutorials:Double Buffering
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering - Double buffer in standard Java AWT
http://www.codeproject.com/Articles/2136/Double-buffer-in-standard-Java-AWT - Java 2D: Hardware Accelerating – Part 1 – Volatile Images
http://www.javalobby.org/forums/thread.jspa?threadID=16840&tstart=0 - Java 2D: Hardware Accelerating – Part 2 – Buffer Strategies
http://www.javalobby.org/java/forums/t16867.html - How does paintComponent work?
http://stackoverflow.com/questions/15544549/how-does-paintcomponent-work - A Swing Architecture Overview
http://www.oracle.com/technetwork/java/architecture-142923.html - Class javax.swing.JComponent
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html - Class java.awt.Component
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html - Class java.awt.Component.BltBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.BltBufferStrategy.html - Class java.awt.Component.FlipBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.FlipBufferStrategy.html - Metoda java.awt.Component.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html#isDoubleBuffered() - Metoda javax.swing.JComponent.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#isDoubleBuffered() - Metoda javax.swing.JComponent.setDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#setDoubleBuffered(boolean) - Javadoc – třída GraphicsDevice
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsDevice.html - Javadoc – třída GraphicsEnvironment
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsEnvironment.html - Javadoc – třída GraphicsConfiguration
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsConfiguration.html - Javadoc – třída DisplayMode
http://docs.oracle.com/javase/7/docs/api/java/awt/DisplayMode.html - Lesson: Full-Screen Exclusive Mode API
http://docs.oracle.com/javase/tutorial/extra/fullscreen/ - Full-Screen Exclusive Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html - Display Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/displaymode.html - Using the Full-Screen Exclusive Mode API in Java
http://www.developer.com/java/other/article.php/3609776/Using-the-Full-Screen-Exclusive-Mode-API-in-Java.htm - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - MultiMedia eXtensions
http://softpixel.com/~cwright/programming/simd/mmx.phpi - SSE (Streaming SIMD Extentions)
http://www.songho.ca/misc/sse/sse.html - Timothy A. Chagnon: SSE and SSE2
http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf - Intel corporation: Extending the Worldr's Most Popular Processor Architecture
http://download.intel.com/technology/architecture/new-instructions-paper.pdf - SIMD architectures:
http://arstechnica.com/old/content/2000/03/simd.ars/ - GC safe-point (or safepoint) and safe-region
http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html - Safepoints in HotSpot JVM
http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html - Java theory and practice: Synchronization optimizations in Mustang
http://www.ibm.com/developerworks/java/library/j-jtp10185/ - How to build hsdis
http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/tools/hsdis/README - Java SE 6 Performance White Paper
http://www.oracle.com/technetwork/java/6-performance-137236.html - Lukas Stadler's Blog
http://classparser.blogspot.cz/2010/03/hsdis-i386dll.html - How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
http://dropzone.nfshost.com/hsdis.htm - PrintAssembly
https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly - The Java Virtual Machine Specification: 3.14. Synchronization
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.14 - The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4 - The Java Virtual Machine Specification: 17.4. Memory Model
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4 - The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7 - Open Source ByteCode Libraries in Java
http://java-source.net/open-source/bytecode-libraries - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - BCEL Home page
http://commons.apache.org/bcel/ - Byte Code Engineering Library (před verzí 5.0)
http://bcel.sourceforge.net/ - Byte Code Engineering Library (verze >= 5.0)
http://commons.apache.org/proper/commons-bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - Javassist
http://www.jboss.org/javassist/ - Byteman
http://www.jboss.org/byteman - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - jclasslib bytecode viewer
http://www.ej-technologies.com/products/jclasslib/overview.html