LV2: modul zesilovače, dle oficiálního příkladu, ale bez závislosti na Pythonu – stačí gcc a make
1 package cz.frantovo.příklady.reflexe;
3 import java.lang.reflect.Field;
4 import java.math.BigDecimal;
5 import java.math.RoundingMode;
7 import java.util.Objects;
8 import java.util.concurrent.ConcurrentHashMap;
9 import java.util.function.Consumer;
13 * @author Ing. František Kučera (frantovo.cz)
15 public class Reflexe {
17 private static final String NÁZEV_PROMĚNNÉ = "proměnná";
18 private static final int POČET_OPAKOVÁNÍ = 1000000;
19 private static final RoundingMode ZAOKROUHLOVÁNÍ = RoundingMode.UP;
20 private static final int PŘESNOST_PROCENT = 2;
22 private static final Map<KlíčTřídaPole, Field> známáPole = new ConcurrentHashMap<>();
23 private static final Map<Class, Map<String, Field>> známáPole2 = new ConcurrentHashMap<>();
25 private static void nastav(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
26 Field f = objekt.getClass().getDeclaredField(proměnná);
27 f.setAccessible(true);
28 f.set(objekt, hodnota);
29 // TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou
32 private static void nastavOptimalizovaně(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
34 KlíčTřídaPole klíč = new KlíčTřídaPole(objekt.getClass(), proměnná);
35 Field f = známáPole.get(klíč);
38 f = objekt.getClass().getDeclaredField(proměnná);
39 f.setAccessible(true);
40 známáPole.put(klíč, f);
43 f.set(objekt, hodnota);
44 // TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou
47 private static class KlíčTřídaPole {
49 private final Class třída;
50 private final String pole;
52 public KlíčTřídaPole(Class třída, String pole) {
58 public boolean equals(Object obj) {
59 if (obj instanceof KlíčTřídaPole) {
60 KlíčTřídaPole druhýKlíč = (KlíčTřídaPole) obj;
61 return Objects.equals(třída, druhýKlíč.třída) && Objects.equals(pole, druhýKlíč.pole);
68 public int hashCode() {
69 return Objects.hash(třída, pole);
74 private static void nastavOptimalizovaně2(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
76 Map<String, Field> mapaPolí = známáPole2.get(objekt.getClass());
77 if (mapaPolí == null) {
78 mapaPolí = new ConcurrentHashMap<>();
79 známáPole2.put(objekt.getClass(), mapaPolí);
82 Field f = mapaPolí.get(proměnná);
84 f = objekt.getClass().getDeclaredField(proměnná);
85 f.setAccessible(true);
86 mapaPolí.put(proměnná, f);
89 f.set(objekt, hodnota);
90 // TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou
93 private static void testSetter(int početOpakování) {
94 NějakáTřída t = new NějakáTřída();
95 for (int i = 0; i < početOpakování; i++) {
100 private static void testPřímýPřístup(int početOpakování) {
101 NějakáTřída t = new NějakáTřída();
102 for (int i = 0; i < početOpakování; i++) {
103 t.veřejnáProměnná = i;
107 private static void testReflexe(int početOpakování) {
108 NějakáTřída t = new NějakáTřída();
110 for (int i = 0; i < početOpakování; i++) {
111 nastav(t, NÁZEV_PROMĚNNÉ, i);
113 } catch (Exception e) {
114 throw new RuntimeException("test se nezdařil", e);
118 private static void testReflexeOptimalizovaná(int početOpakování) {
119 NějakáTřída t = new NějakáTřída();
121 for (int i = 0; i < početOpakování; i++) {
122 nastavOptimalizovaně(t, NÁZEV_PROMĚNNÉ, i);
124 } catch (Exception e) {
125 throw new RuntimeException("test se nezdařil", e);
129 private static void testReflexeOptimalizovaná2(int početOpakování) {
130 NějakáTřída t = new NějakáTřída();
132 for (int i = 0; i < početOpakování; i++) {
133 nastavOptimalizovaně2(t, NÁZEV_PROMĚNNÉ, i);
135 } catch (Exception e) {
136 throw new RuntimeException("test se nezdařil", e);
140 private static void testReflexePřipravená(int početOpakování) {
141 NějakáTřída t = new NějakáTřída();
143 Field f = t.getClass().getDeclaredField(NÁZEV_PROMĚNNÉ);
144 f.setAccessible(true);
145 for (int i = 0; i < početOpakování; i++) {
148 } catch (Exception e) {
149 throw new RuntimeException("test se nezdařil", e);
153 private static String lpad(int početZnaků, Object text) {
154 return String.format("%1$" + početZnaků + "s", String.valueOf(text));
157 private static BigDecimal spočítejProcenta(long hodnota, long základ) {
158 BigDecimal h = BigDecimal.valueOf(hodnota);
159 BigDecimal z = BigDecimal.valueOf(základ);
160 return h.multiply(BigDecimal.valueOf(100)).divide(z, PŘESNOST_PROCENT, ZAOKROUHLOVÁNÍ);
163 private static Long testuj(String názevTestu, int početOpakování, Long časProPorovnání, Consumer<Integer> test) {
164 System.out.print("TEST: " + lpad(24, názevTestu) + ": ");
166 long začátek = System.currentTimeMillis();
167 test.accept(početOpakování);
168 long konec = System.currentTimeMillis();
169 long celkovýČas = konec - začátek;
170 BigDecimal relativníČas = časProPorovnání == null ? BigDecimal.valueOf(100).setScale(PŘESNOST_PROCENT) : spočítejProcenta(celkovýČas, časProPorovnání);
171 System.out.println("početOpakování = " + lpad(12, početOpakování) + " celkovýČas = " + lpad(8, celkovýČas) + " ms relativníČas = " + lpad(8, relativníČas) + " %");
173 } catch (Exception e) {
174 System.out.println("došlo k chybě");
180 public static void main(String[] args) {
181 long základníČas = testuj("přímý přístup", POČET_OPAKOVÁNÍ, null, Reflexe::testPřímýPřístup);
182 testuj("setter", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testSetter);
183 testuj("reflexe", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexe);
184 testuj("reflexe optimalizovaná 1", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexeOptimalizovaná);
185 testuj("reflexe optimalizovaná 2", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexeOptimalizovaná2);
186 testuj("reflexe připravená", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexePřipravená);