package test; import java.io.IOException; import java.lang.annotation.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Objects; public class ReflectionTest { @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface InheritedAnn { String value(); } @Retention(RetentionPolicy.RUNTIME) public @interface Ann1 { String value(); } @Retention(RetentionPolicy.RUNTIME) public @interface Ann2 { String value(); } @Retention(RetentionPolicy.RUNTIME) public @interface Ann3 { String value(); } @Retention(RetentionPolicy.RUNTIME) public @interface Ann4 { String value(); } @Retention(RetentionPolicy.RUNTIME) public @interface Ann5 { String value(); } @InheritedAnn("A") @Ann1("A") @Ann2("A") @Ann3("A") @Ann4("A") @Ann5("A") public static class ClassA { @Ann1("A.f1") @Ann2("A.f1") @Ann3("A.f1") @Ann4("A.f1") @Ann5("A.f1") public String f1; @Ann1("A.") @Ann2("A.") @Ann3("A.") @Ann4("A.") @Ann5("A.") public ClassA() { } @Ann1("A.m1") @Ann2("A.m1") @Ann3("A.m1") @Ann4("A.m1") @Ann5("A.m1") public void m1() { } @Ann1("A.m2") @Ann2("A.m2") @Ann3("A.m2") @Ann4("A.m2") @Ann5("A.m2") public void m2() { } } @Ann1("B") @Ann2("B") @Ann3("B") @Ann4("B") @Ann5("B") public static class ClassB extends ClassA { @Ann1("B.f1") @Ann2("B.f1") @Ann3("B.f1") @Ann4("B.f1") @Ann5("B.f1") public String f1; @Ann1("B.") @Ann2("B.") @Ann3("B.") @Ann4("B.") @Ann5("B.") public ClassB() { } @Ann1("B.m1") @Ann2("B.m1") @Ann3("B.m1") @Ann4("B.m1") @Ann5("B.m1") public void m1() { } @Ann1("B.m2") @Ann2("B.m2") @Ann3("B.m2") @Ann4("B.m2") @Ann5("B.m2") public void m2() { } } @Ann1("C") @Ann2("C") @Ann3("C") @Ann4("C") @Ann5("C") public static class ClassC extends ClassB { @Ann1("C.f1") @Ann2("C.f1") @Ann3("C.f1") @Ann4("C.f1") @Ann5("C.f1") public String f1; @Ann1("C.") @Ann2("C.") @Ann3("C.") @Ann4("C.") @Ann5("C.") public ClassC() { } @Ann1("C.m1") @Ann2("C.m1") @Ann3("C.m1") @Ann4("C.m1") @Ann5("C.m1") public void m1() { } @Ann1("C.m2") @Ann2("C.m2") @Ann3("C.m2") @Ann4("C.m2") @Ann5("C.m2") public void m2() { } } static void dump(Annotation[] annotations, String prefix, Appendable sb) throws Exception { for (Annotation ann : annotations) { String value = (String) ann.annotationType().getMethod("value", new Class[0]).invoke(ann, (Object[]) null); sb.append(prefix).append("@").append(ann.annotationType().getName()).append("(\"").append(value).append("\")\n"); } } static void dump(Class clazz, Field[] fields, Constructor[] constructors, Method[] methods, Appendable sb) { try { dump(clazz.getAnnotations(), "", sb); sb.append("class ").append(clazz.getName()).append(" {\n\n"); if (fields != null) { for (Field f : fields) { dump(f.getAnnotations(), " ", sb); sb.append(" ").append(f.toGenericString()).append(";\n\n"); } } if (methods != null) { for (Constructor c : constructors) { dump(c.getAnnotations(), " ", sb); sb.append(" ").append(c.toGenericString()).append(";\n\n"); } } if (methods != null) { for (Method m : methods) { dump(m.getAnnotations(), " ", sb); sb.append(" ").append(m.toGenericString()).append(";\n\n"); } } sb.append("}\n\n"); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } static final Object NOT_ANNOTATION = new Object(); static void test(Annotation ann) { if (ann == NOT_ANNOTATION) { throw new AssertionError(); } } static void test(Class clazz) { test(clazz.getAnnotation(InheritedAnn.class)); test(clazz.getAnnotation(Ann1.class)); } static void test(Class clazz, Field[] fields, Constructor[] constructors, Method[] methods) { test(clazz); for (Field f : fields) { test(f.getAnnotation(Ann1.class)); } for (Constructor c : constructors) { test(c.getAnnotation(Ann1.class)); } for (Method m : methods) { test(m.getAnnotation(Ann1.class)); } } static class Test1 extends Thread { final int loops; Test1(int loops) { this.loops = loops; } @Override public void run() { for (int i = 0; i < loops; i++) { test(ClassA.class, ClassA.class.getFields(), ClassA.class.getConstructors(), ClassA.class.getMethods()); test(ClassB.class, ClassB.class.getFields(), ClassB.class.getConstructors(), ClassB.class.getMethods()); test(ClassC.class, ClassC.class.getFields(), ClassC.class.getConstructors(), ClassC.class.getMethods()); } } } static class Test2 extends Thread { final int loops; Test2(int loops) { this.loops = loops; } @Override public void run() { Field[] classAfields = ClassA.class.getFields(); Constructor[] classAconstructors = ClassA.class.getConstructors(); Method[] classAmethods = ClassA.class.getMethods(); Field[] classBfields = ClassB.class.getFields(); Constructor[] classBconstructors = ClassB.class.getConstructors(); Method[] classBmethods = ClassB.class.getMethods(); Field[] classCfields = ClassC.class.getFields(); Constructor[] classCconstructors = ClassC.class.getConstructors(); Method[] classCmethods = ClassC.class.getMethods(); for (int i = 0; i < loops; i++) { test(ClassA.class, classAfields, classAconstructors, classAmethods); test(ClassB.class, classBfields, classBconstructors, classBmethods); test(ClassC.class, classCfields, classCconstructors, classCmethods); } } } static class Test3 extends Thread { final int loops; Test3(int loops) { this.loops = loops; } @Override public void run() { for (int i = 0; i < loops; i++) { test(ClassA.class); test(ClassB.class); test(ClassC.class); } } } static void testCorrectness() { StringBuilder sb = new StringBuilder(); dump(ClassA.class, ClassA.class.getFields(), ClassA.class.getConstructors(), ClassA.class.getMethods(), sb); dump(ClassB.class, ClassB.class.getFields(), ClassB.class.getConstructors(), ClassB.class.getMethods(), sb); dump(ClassC.class, ClassC.class.getFields(), ClassC.class.getConstructors(), ClassC.class.getMethods(), sb); System.out.println(sb); } static long test1(int threads, int loops, long prevT) { Thread[] workers = new Thread[threads]; for (int i = 0; i < workers.length; i++) { workers[i] = new Test1(loops); } return runWorkers(workers, loops, prevT); } static long test2(int threads, int loops, long prevT) { Thread[] workers = new Thread[threads]; for (int i = 0; i < workers.length; i++) { workers[i] = new Test2(loops); } return runWorkers(workers, loops, prevT); } static long test3(int threads, int loops, long prevT) { Thread[] workers = new Thread[threads]; for (int i = 0; i < workers.length; i++) { workers[i] = new Test3(loops); } return runWorkers(workers, loops, prevT); } static long runWorkers(Thread[] workers, int loops, long prevT) { try { System.gc(); Thread.sleep(500L); System.gc(); Thread.sleep(500L); System.gc(); Thread.sleep(500L); } catch (InterruptedException e) { } long t0 = System.nanoTime(); for (int i = 0; i < workers.length; i++) { workers[i].start(); } for (int i = 0; i < workers.length; i++) { try { workers[i].join(); } catch (InterruptedException e) { } } long t = System.nanoTime() - t0; System.out.println( workers[0].getClass().getSimpleName() + ": " + String.format("%3d", workers.length) + " concurrent threads * " + String.format("%9d", loops) + " loops each: " + String.format("%,15.3f", (double) t / 1000000d) + " ms" + (prevT == 0L ? "" : String.format(" (x %6.2f)", (double) t / (double) prevT))); return t; } public static void main(String[] args) throws IOException { System.out.println(); long t; System.out.println("warm-up:"); t = test1(1, 20000, 0L); test1(1, 20000, t); test1(1, 20000, t); System.out.println(); t = test2(1, 2000000, 0); test2(1, 2000000, t); test2(1, 2000000, t); System.out.println(); t = test3(1, 10000000, 0); test3(1, 10000000, t); test3(1, 10000000, t); System.out.println(); System.out.println("measure:"); t = test1(1, 20000, 0); test1(2, 20000, t); test1(4, 20000, t); test1(8, 20000, t); test1(32, 20000, t); test1(128, 20000, t); System.out.println(); t = test2(1, 2000000, 0); test2(2, 2000000, t); test2(4, 2000000, t); test2(8, 2000000, t); test2(32, 2000000, t); test2(128, 2000000, t); System.out.println(); t = test3(1, 10000000, 0); test3(2, 10000000, t); test3(4, 10000000, t); test3(8, 10000000, t); test3(32, 10000000, t); test3(128, 10000000, t); System.out.println(); } }