franta-hg@27: package cz.frantovo.příklady.reflexe; franta-hg@27: franta-hg@27: import java.lang.reflect.Field; franta-hg@27: import java.math.BigDecimal; franta-hg@27: import java.math.RoundingMode; franta-hg@36: import java.util.Map; franta-hg@36: import java.util.Objects; franta-hg@36: import java.util.concurrent.ConcurrentHashMap; franta-hg@27: import java.util.function.Consumer; franta-hg@27: franta-hg@27: /** franta-hg@27: * franta-hg@27: * @author Ing. František Kučera (frantovo.cz) franta-hg@27: */ franta-hg@27: public class Reflexe { franta-hg@27: franta-hg@27: private static final String NÁZEV_PROMĚNNÉ = "proměnná"; franta-hg@27: private static final int POČET_OPAKOVÁNÍ = 1000000; franta-hg@27: private static final RoundingMode ZAOKROUHLOVÁNÍ = RoundingMode.UP; franta-hg@27: private static final int PŘESNOST_PROCENT = 2; franta-hg@27: franta-hg@36: private static final Map známáPole = new ConcurrentHashMap<>(); franta-hg@36: private static final Map> známáPole2 = new ConcurrentHashMap<>(); franta-hg@36: franta-hg@27: private static void nastav(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { franta-hg@27: Field f = objekt.getClass().getDeclaredField(proměnná); franta-hg@27: f.setAccessible(true); franta-hg@27: f.set(objekt, hodnota); franta-hg@27: // TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou franta-hg@27: } franta-hg@27: franta-hg@36: private static void nastavOptimalizovaně(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { franta-hg@36: franta-hg@36: KlíčTřídaPole klíč = new KlíčTřídaPole(objekt.getClass(), proměnná); franta-hg@36: Field f = známáPole.get(klíč); franta-hg@36: franta-hg@36: if (f == null) { franta-hg@36: f = objekt.getClass().getDeclaredField(proměnná); franta-hg@36: f.setAccessible(true); franta-hg@36: známáPole.put(klíč, f); franta-hg@36: } franta-hg@36: franta-hg@36: f.set(objekt, hodnota); franta-hg@36: // TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou franta-hg@36: } franta-hg@36: franta-hg@36: private static class KlíčTřídaPole { franta-hg@36: franta-hg@36: private final Class třída; franta-hg@36: private final String pole; franta-hg@36: franta-hg@36: public KlíčTřídaPole(Class třída, String pole) { franta-hg@36: this.třída = třída; franta-hg@36: this.pole = pole; franta-hg@36: } franta-hg@36: franta-hg@36: @Override franta-hg@36: public boolean equals(Object obj) { franta-hg@36: if (obj instanceof KlíčTřídaPole) { franta-hg@36: KlíčTřídaPole druhýKlíč = (KlíčTřídaPole) obj; franta-hg@36: return Objects.equals(třída, druhýKlíč.třída) && Objects.equals(pole, druhýKlíč.pole); franta-hg@36: } else { franta-hg@36: return false; franta-hg@36: } franta-hg@36: } franta-hg@36: franta-hg@36: @Override franta-hg@36: public int hashCode() { franta-hg@36: return Objects.hash(třída, pole); franta-hg@36: } franta-hg@36: franta-hg@36: } franta-hg@36: franta-hg@36: private static void nastavOptimalizovaně2(Object objekt, String proměnná, Object hodnota) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { franta-hg@36: franta-hg@36: Map mapaPolí = známáPole2.get(objekt.getClass()); franta-hg@36: if (mapaPolí == null) { franta-hg@36: mapaPolí = new ConcurrentHashMap<>(); franta-hg@36: známáPole2.put(objekt.getClass(), mapaPolí); franta-hg@36: } franta-hg@36: franta-hg@36: Field f = mapaPolí.get(proměnná); franta-hg@36: if (f == null) { franta-hg@36: f = objekt.getClass().getDeclaredField(proměnná); franta-hg@36: f.setAccessible(true); franta-hg@36: mapaPolí.put(proměnná, f); franta-hg@36: } franta-hg@36: franta-hg@36: f.set(objekt, hodnota); franta-hg@36: // TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou franta-hg@36: } franta-hg@36: franta-hg@27: private static void testSetter(int početOpakování) { franta-hg@27: NějakáTřída t = new NějakáTřída(); franta-hg@27: for (int i = 0; i < početOpakování; i++) { franta-hg@27: t.setProměnná(i); franta-hg@27: } franta-hg@27: } franta-hg@27: franta-hg@27: private static void testPřímýPřístup(int početOpakování) { franta-hg@27: NějakáTřída t = new NějakáTřída(); franta-hg@27: for (int i = 0; i < početOpakování; i++) { franta-hg@27: t.veřejnáProměnná = i; franta-hg@27: } franta-hg@27: } franta-hg@27: franta-hg@27: private static void testReflexe(int početOpakování) { franta-hg@27: NějakáTřída t = new NějakáTřída(); franta-hg@27: try { franta-hg@27: for (int i = 0; i < početOpakování; i++) { franta-hg@27: nastav(t, NÁZEV_PROMĚNNÉ, i); franta-hg@27: } franta-hg@27: } catch (Exception e) { franta-hg@27: throw new RuntimeException("test se nezdařil", e); franta-hg@27: } franta-hg@27: } franta-hg@27: franta-hg@36: private static void testReflexeOptimalizovaná(int početOpakování) { franta-hg@36: NějakáTřída t = new NějakáTřída(); franta-hg@36: try { franta-hg@36: for (int i = 0; i < početOpakování; i++) { franta-hg@36: nastavOptimalizovaně(t, NÁZEV_PROMĚNNÉ, i); franta-hg@36: } franta-hg@36: } catch (Exception e) { franta-hg@36: throw new RuntimeException("test se nezdařil", e); franta-hg@36: } franta-hg@36: } franta-hg@36: franta-hg@36: private static void testReflexeOptimalizovaná2(int početOpakování) { franta-hg@36: NějakáTřída t = new NějakáTřída(); franta-hg@36: try { franta-hg@36: for (int i = 0; i < početOpakování; i++) { franta-hg@36: nastavOptimalizovaně2(t, NÁZEV_PROMĚNNÉ, i); franta-hg@36: } franta-hg@36: } catch (Exception e) { franta-hg@36: throw new RuntimeException("test se nezdařil", e); franta-hg@36: } franta-hg@36: } franta-hg@36: franta-hg@27: private static void testReflexePřipravená(int početOpakování) { franta-hg@27: NějakáTřída t = new NějakáTřída(); franta-hg@27: try { franta-hg@27: Field f = t.getClass().getDeclaredField(NÁZEV_PROMĚNNÉ); franta-hg@27: f.setAccessible(true); franta-hg@27: for (int i = 0; i < početOpakování; i++) { franta-hg@27: f.set(t, i); franta-hg@27: } franta-hg@27: } catch (Exception e) { franta-hg@27: throw new RuntimeException("test se nezdařil", e); franta-hg@27: } franta-hg@27: } franta-hg@27: franta-hg@27: private static String lpad(int početZnaků, Object text) { franta-hg@27: return String.format("%1$" + početZnaků + "s", String.valueOf(text)); franta-hg@27: } franta-hg@27: franta-hg@27: private static BigDecimal spočítejProcenta(long hodnota, long základ) { franta-hg@27: BigDecimal h = BigDecimal.valueOf(hodnota); franta-hg@27: BigDecimal z = BigDecimal.valueOf(základ); franta-hg@27: return h.multiply(BigDecimal.valueOf(100)).divide(z, PŘESNOST_PROCENT, ZAOKROUHLOVÁNÍ); franta-hg@27: } franta-hg@27: franta-hg@27: private static Long testuj(String názevTestu, int početOpakování, Long časProPorovnání, Consumer test) { franta-hg@36: System.out.print("TEST: " + lpad(24, názevTestu) + ": "); franta-hg@27: try { franta-hg@27: long začátek = System.currentTimeMillis(); franta-hg@27: test.accept(početOpakování); franta-hg@27: long konec = System.currentTimeMillis(); franta-hg@27: long celkovýČas = konec - začátek; franta-hg@27: BigDecimal relativníČas = časProPorovnání == null ? BigDecimal.valueOf(100).setScale(PŘESNOST_PROCENT) : spočítejProcenta(celkovýČas, časProPorovnání); franta-hg@27: 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: return celkovýČas; franta-hg@27: } catch (Exception e) { franta-hg@27: System.out.println("došlo k chybě"); franta-hg@27: e.printStackTrace(); franta-hg@27: return null; franta-hg@27: } franta-hg@27: } franta-hg@27: franta-hg@27: public static void main(String[] args) { franta-hg@27: long základníČas = testuj("přímý přístup", POČET_OPAKOVÁNÍ, null, Reflexe::testPřímýPřístup); franta-hg@27: testuj("setter", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testSetter); franta-hg@27: testuj("reflexe", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexe); franta-hg@36: testuj("reflexe optimalizovaná 1", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexeOptimalizovaná); franta-hg@36: testuj("reflexe optimalizovaná 2", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexeOptimalizovaná2); franta-hg@27: testuj("reflexe připravená", POČET_OPAKOVÁNÍ, základníČas, Reflexe::testReflexePřipravená); franta-hg@27: } franta-hg@27: franta-hg@36: }