franta-hg@27
|
1 |
package cz.frantovo.příklady.reflexe;
|
franta-hg@27
|
2 |
|
franta-hg@27
|
3 |
import java.lang.reflect.Field;
|
franta-hg@27
|
4 |
import java.math.BigDecimal;
|
franta-hg@27
|
5 |
import java.math.RoundingMode;
|
franta-hg@36
|
6 |
import java.util.Map;
|
franta-hg@36
|
7 |
import java.util.Objects;
|
franta-hg@36
|
8 |
import java.util.concurrent.ConcurrentHashMap;
|
franta-hg@27
|
9 |
import java.util.function.Consumer;
|
franta-hg@27
|
10 |
|
franta-hg@27
|
11 |
/**
|
franta-hg@27
|
12 |
*
|
franta-hg@27
|
13 |
* @author Ing. František Kučera (frantovo.cz)
|
franta-hg@27
|
14 |
*/
|
franta-hg@27
|
15 |
public class Reflexe {
|
franta-hg@27
|
16 |
|
franta-hg@27
|
17 |
private static final String NÁZEV_PROMĚNNÉ = "proměnná";
|
franta-hg@27
|
18 |
private static final int POČET_OPAKOVÁNÍ = 1000000;
|
franta-hg@27
|
19 |
private static final RoundingMode ZAOKROUHLOVÁNÍ = RoundingMode.UP;
|
franta-hg@27
|
20 |
private static final int PŘESNOST_PROCENT = 2;
|
franta-hg@27
|
21 |
|
franta-hg@36
|
22 |
private static final Map<KlíčTřídaPole, Field> známáPole = new ConcurrentHashMap<>();
|
franta-hg@36
|
23 |
private static final Map<Class, Map<String, Field>> známáPole2 = new ConcurrentHashMap<>();
|
franta-hg@36
|
24 |
|
franta-hg@27
|
25 |
private static void nastav(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
|
franta-hg@27
|
26 |
Field f = objekt.getClass().getDeclaredField(proměnná);
|
franta-hg@27
|
27 |
f.setAccessible(true);
|
franta-hg@27
|
28 |
f.set(objekt, hodnota);
|
franta-hg@27
|
29 |
// TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou
|
franta-hg@27
|
30 |
}
|
franta-hg@27
|
31 |
|
franta-hg@36
|
32 |
private static void nastavOptimalizovaně(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
|
franta-hg@36
|
33 |
|
franta-hg@36
|
34 |
KlíčTřídaPole klíč = new KlíčTřídaPole(objekt.getClass(), proměnná);
|
franta-hg@36
|
35 |
Field f = známáPole.get(klíč);
|
franta-hg@36
|
36 |
|
franta-hg@36
|
37 |
if (f == null) {
|
franta-hg@36
|
38 |
f = objekt.getClass().getDeclaredField(proměnná);
|
franta-hg@36
|
39 |
f.setAccessible(true);
|
franta-hg@36
|
40 |
známáPole.put(klíč, f);
|
franta-hg@36
|
41 |
}
|
franta-hg@36
|
42 |
|
franta-hg@36
|
43 |
f.set(objekt, hodnota);
|
franta-hg@36
|
44 |
// TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou
|
franta-hg@36
|
45 |
}
|
franta-hg@36
|
46 |
|
franta-hg@36
|
47 |
private static class KlíčTřídaPole {
|
franta-hg@36
|
48 |
|
franta-hg@36
|
49 |
private final Class třída;
|
franta-hg@36
|
50 |
private final String pole;
|
franta-hg@36
|
51 |
|
franta-hg@36
|
52 |
public KlíčTřídaPole(Class třída, String pole) {
|
franta-hg@36
|
53 |
this.třída = třída;
|
franta-hg@36
|
54 |
this.pole = pole;
|
franta-hg@36
|
55 |
}
|
franta-hg@36
|
56 |
|
franta-hg@36
|
57 |
@Override
|
franta-hg@36
|
58 |
public boolean equals(Object obj) {
|
franta-hg@36
|
59 |
if (obj instanceof KlíčTřídaPole) {
|
franta-hg@36
|
60 |
KlíčTřídaPole druhýKlíč = (KlíčTřídaPole) obj;
|
franta-hg@36
|
61 |
return Objects.equals(třída, druhýKlíč.třída) && Objects.equals(pole, druhýKlíč.pole);
|
franta-hg@36
|
62 |
} else {
|
franta-hg@36
|
63 |
return false;
|
franta-hg@36
|
64 |
}
|
franta-hg@36
|
65 |
}
|
franta-hg@36
|
66 |
|
franta-hg@36
|
67 |
@Override
|
franta-hg@36
|
68 |
public int hashCode() {
|
franta-hg@36
|
69 |
return Objects.hash(třída, pole);
|
franta-hg@36
|
70 |
}
|
franta-hg@36
|
71 |
|
franta-hg@36
|
72 |
}
|
franta-hg@36
|
73 |
|
franta-hg@36
|
74 |
private static void nastavOptimalizovaně2(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
|
franta-hg@36
|
75 |
|
franta-hg@36
|
76 |
Map<String, Field> mapaPolí = známáPole2.get(objekt.getClass());
|
franta-hg@36
|
77 |
if (mapaPolí == null) {
|
franta-hg@36
|
78 |
mapaPolí = new ConcurrentHashMap<>();
|
franta-hg@36
|
79 |
známáPole2.put(objekt.getClass(), mapaPolí);
|
franta-hg@36
|
80 |
}
|
franta-hg@36
|
81 |
|
franta-hg@36
|
82 |
Field f = mapaPolí.get(proměnná);
|
franta-hg@36
|
83 |
if (f == null) {
|
franta-hg@36
|
84 |
f = objekt.getClass().getDeclaredField(proměnná);
|
franta-hg@36
|
85 |
f.setAccessible(true);
|
franta-hg@36
|
86 |
mapaPolí.put(proměnná, f);
|
franta-hg@36
|
87 |
}
|
franta-hg@36
|
88 |
|
franta-hg@36
|
89 |
f.set(objekt, hodnota);
|
franta-hg@36
|
90 |
// TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou
|
franta-hg@36
|
91 |
}
|
franta-hg@36
|
92 |
|
franta-hg@27
|
93 |
private static void testSetter(int početOpakování) {
|
franta-hg@27
|
94 |
NějakáTřída t = new NějakáTřída();
|
franta-hg@27
|
95 |
for (int i = 0; i < početOpakování; i++) {
|
franta-hg@27
|
96 |
t.setProměnná(i);
|
franta-hg@27
|
97 |
}
|
franta-hg@27
|
98 |
}
|
franta-hg@27
|
99 |
|
franta-hg@27
|
100 |
private static void testPřímýPřístup(int početOpakování) {
|
franta-hg@27
|
101 |
NějakáTřída t = new NějakáTřída();
|
franta-hg@27
|
102 |
for (int i = 0; i < početOpakování; i++) {
|
franta-hg@27
|
103 |
t.veřejnáProměnná = i;
|
franta-hg@27
|
104 |
}
|
franta-hg@27
|
105 |
}
|
franta-hg@27
|
106 |
|
franta-hg@27
|
107 |
private static void testReflexe(int početOpakování) {
|
franta-hg@27
|
108 |
NějakáTřída t = new NějakáTřída();
|
franta-hg@27
|
109 |
try {
|
franta-hg@27
|
110 |
for (int i = 0; i < početOpakování; i++) {
|
franta-hg@27
|
111 |
nastav(t, NÁZEV_PROMĚNNÉ, i);
|
franta-hg@27
|
112 |
}
|
franta-hg@27
|
113 |
} catch (Exception e) {
|
franta-hg@27
|
114 |
throw new RuntimeException("test se nezdařil", e);
|
franta-hg@27
|
115 |
}
|
franta-hg@27
|
116 |
}
|
franta-hg@27
|
117 |
|
franta-hg@36
|
118 |
private static void testReflexeOptimalizovaná(int početOpakování) {
|
franta-hg@36
|
119 |
NějakáTřída t = new NějakáTřída();
|
franta-hg@36
|
120 |
try {
|
franta-hg@36
|
121 |
for (int i = 0; i < početOpakování; i++) {
|
franta-hg@36
|
122 |
nastavOptimalizovaně(t, NÁZEV_PROMĚNNÉ, i);
|
franta-hg@36
|
123 |
}
|
franta-hg@36
|
124 |
} catch (Exception e) {
|
franta-hg@36
|
125 |
throw new RuntimeException("test se nezdařil", e);
|
franta-hg@36
|
126 |
}
|
franta-hg@36
|
127 |
}
|
franta-hg@36
|
128 |
|
franta-hg@36
|
129 |
private static void testReflexeOptimalizovaná2(int početOpakování) {
|
franta-hg@36
|
130 |
NějakáTřída t = new NějakáTřída();
|
franta-hg@36
|
131 |
try {
|
franta-hg@36
|
132 |
for (int i = 0; i < početOpakování; i++) {
|
franta-hg@36
|
133 |
nastavOptimalizovaně2(t, NÁZEV_PROMĚNNÉ, i);
|
franta-hg@36
|
134 |
}
|
franta-hg@36
|
135 |
} catch (Exception e) {
|
franta-hg@36
|
136 |
throw new RuntimeException("test se nezdařil", e);
|
franta-hg@36
|
137 |
}
|
franta-hg@36
|
138 |
}
|
franta-hg@36
|
139 |
|
franta-hg@27
|
140 |
private static void testReflexePřipravená(int početOpakování) {
|
franta-hg@27
|
141 |
NějakáTřída t = new NějakáTřída();
|
franta-hg@27
|
142 |
try {
|
franta-hg@27
|
143 |
Field f = t.getClass().getDeclaredField(NÁZEV_PROMĚNNÉ);
|
franta-hg@27
|
144 |
f.setAccessible(true);
|
franta-hg@27
|
145 |
for (int i = 0; i < početOpakování; i++) {
|
franta-hg@27
|
146 |
f.set(t, i);
|
franta-hg@27
|
147 |
}
|
franta-hg@27
|
148 |
} catch (Exception e) {
|
franta-hg@27
|
149 |
throw new RuntimeException("test se nezdařil", e);
|
franta-hg@27
|
150 |
}
|
franta-hg@27
|
151 |
}
|
franta-hg@27
|
152 |
|
franta-hg@27
|
153 |
private static String lpad(int početZnaků, Object text) {
|
franta-hg@27
|
154 |
return String.format("%1$" + početZnaků + "s", String.valueOf(text));
|
franta-hg@27
|
155 |
}
|
franta-hg@27
|
156 |
|
franta-hg@27
|
157 |
private static BigDecimal spočítejProcenta(long hodnota, long základ) {
|
franta-hg@27
|
158 |
BigDecimal h = BigDecimal.valueOf(hodnota);
|
franta-hg@27
|
159 |
BigDecimal z = BigDecimal.valueOf(základ);
|
franta-hg@27
|
160 |
return h.multiply(BigDecimal.valueOf(100)).divide(z, PŘESNOST_PROCENT, ZAOKROUHLOVÁNÍ);
|
franta-hg@27
|
161 |
}
|
franta-hg@27
|
162 |
|
franta-hg@27
|
163 |
private static Long testuj(String názevTestu, int početOpakování, Long časProPorovnání, Consumer<Integer> test) {
|
franta-hg@36
|
164 |
System.out.print("TEST: " + lpad(24, názevTestu) + ": ");
|
franta-hg@27
|
165 |
try {
|
franta-hg@27
|
166 |
long začátek = System.currentTimeMillis();
|
franta-hg@27
|
167 |
test.accept(početOpakování);
|
franta-hg@27
|
168 |
long konec = System.currentTimeMillis();
|
franta-hg@27
|
169 |
long celkovýČas = konec - začátek;
|
franta-hg@27
|
170 |
BigDecimal relativníČas = časProPorovnání == null ? BigDecimal.valueOf(100).setScale(PŘESNOST_PROCENT) : spočítejProcenta(celkovýČas, časProPorovnání);
|
franta-hg@27
|
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) + " %");
|
franta-hg@27
|
172 |
return celkovýČas;
|
franta-hg@27
|
173 |
} catch (Exception e) {
|
franta-hg@27
|
174 |
System.out.println("došlo k chybě");
|
franta-hg@27
|
175 |
e.printStackTrace();
|
franta-hg@27
|
176 |
return null;
|
franta-hg@27
|
177 |
}
|
franta-hg@27
|
178 |
}
|
franta-hg@27
|
179 |
|
franta-hg@27
|
180 |
public static void main(String[] args) {
|
franta-hg@27
|
181 |
long základníČas = testuj("přímý přístup", POČET_OPAKOVÁNÍ, null, Reflexe::testPřímýPřístup);
|
franta-hg@27
|
182 |
testuj("setter", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testSetter);
|
franta-hg@27
|
183 |
testuj("reflexe", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexe);
|
franta-hg@36
|
184 |
testuj("reflexe optimalizovaná 1", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexeOptimalizovaná);
|
franta-hg@36
|
185 |
testuj("reflexe optimalizovaná 2", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexeOptimalizovaná2);
|
franta-hg@27
|
186 |
testuj("reflexe připravená", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexePřipravená);
|
franta-hg@27
|
187 |
}
|
franta-hg@27
|
188 |
|
franta-hg@36
|
189 |
}
|