直接呼出しとリフレクション。

ふと思い立って、コードを書いてみたり。


結局どれだけ差があるのさ?

  • 結果。
CGLib      TOTAL :     172,212,794
CGLib      AVG   :             172
Reflection TOTAL :     404,496,857
Reflection AVG   :             404
Direct     TOTAL :      97,788,141
Direct     AVG   :              97
==================
CGLib      TOTAL :     149,866,977
CGLib      AVG   :             149
Reflection TOTAL :     396,531,053
Reflection AVG   :             396
Direct     TOTAL :      95,978,462
Direct     AVG   :              95
==================
CGLib      TOTAL :     142,808,269
CGLib      AVG   :             142
Reflection TOTAL :     399,944,598
Reflection AVG   :             399
Direct     TOTAL :      95,536,951
Direct     AVG   :              95
==================
CGLib      TOTAL :     146,544,536
CGLib      AVG   :             146
Reflection TOTAL :     402,051,285
Reflection AVG   :             402
Direct     TOTAL :      97,291,030
Direct     AVG   :              97
==================
CGLib      TOTAL :     147,852,179
CGLib      AVG   :             147
Reflection TOTAL :     396,690,007
Reflection AVG   :             396
Direct     TOTAL :      95,101,145
Direct     AVG   :              95
==================

つまり、直接呼出しが、4倍程度速い感じ。
単に比較の問題なので、別に速いからどうと言う事も無いけれど。
CGLibのFastClassも意外と速いけど、直接呼出しに比べると遅いらしい。

  • 思い立ったテストコード。
public class Main {

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            test();
            System.out.println("==================");
        }
    }

    public static void test() {
        try {
            String instance = "aabbccddeeddffgghhjjkkllmmnn";
            Test[] tests = new Test[] { new CGLib(), new Reflection(),
                    new Direct() };
            int count = 1000000;
            for (int i = 0; i < tests.length; i++) {
                Test test = tests[i];
                test.init();
                long start = System.nanoTime();
                for (int j = 0; j < count; j++) {
                    test.invoke(instance);
                }
                long total = System.nanoTime() - start;
                System.out.printf("%1$-10s TOTAL : %2$,15d%n", test.name(),
                        total);
                if (0 < total) {
                    System.out.printf("%1$-10s AVG   : %2$,15d%n", test.name(),
                            total / count);
                } else {
                    System.out.println(test.name() + " AVG   : (too fast)");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    interface Test {
        String name();

        void init() throws Exception;

        void invoke(String instance) throws Exception;
    }

    static class Reflection implements Test {
        Method m = null;

        public String name() {
            return "Reflection";
        }

        public void init() throws Exception {
            m = String.class.getMethod("indexOf", new Class[] { String.class });
        }

        public void invoke(String instance) throws Exception {
            m.invoke(instance, new Object[] { "ll" });
        }
    }

    static class Direct implements Test {

        public String name() {
            return "Direct";
        }

        public void init() throws Exception {
        }

        public void invoke(String instance) throws Exception {
            instance.indexOf("ll");
        }
    }

    static class CGLib implements Test {
        FastClass clazz;

        int index;

        public String name() {
            return "CGLib";
        }

        public void init() throws Exception {
            clazz = FastClass.create(String.class);
            index = clazz.getIndex("indexOf", new Class[] { String.class });
        }

        public void invoke(String instance) throws Exception {
            clazz.invoke(index, instance, new Object[] { "ll" });
        }
    }
}

虎が使えてねぇぞ。ゴルァと突っ込まれましたので、綺麗に見える様にしてみるました。
コードのインデントを変えてみるました。