解释Java反射性能:为什么它的速度非常快?

jbu*_*jbu 7 java reflection performance interface

我已经看到其他线程说java反射性能比使用非反射调用慢10-100倍.

我在1.6中的测试表明情况并非如此,但我发现了一些其他有趣的东西,我需要有人向我解释.

我有实现我的界面的对象.我做了三件事1)使用对象的引用我将该对象转换为接口并通过接口调用方法2)使用对实际对象的引用直接调用方法,3)通过反射调用方法.我看到#1接口调用最快,紧接着是#3反射,但我注意到直接方法调用是最慢的一个很好的边缘.

我不明白,我会期望直接调用最快,然后接口,然后反射会慢得多.

Blah和ComplexClass与主类位于不同的包中,并且都有一个doSomething(int x)方法,它实现了接口并只打印整数x.

下面是我的结果(以毫秒时间,导致非常相似的W /多次试验):直接调用的方法:107194直接从对象铸造调用方法到接口:89594通过反射调用一个方法:90453

这是我的代码:

public class Main
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        Blah x = new Blah();
        ComplexClass cc = new ComplexClass();
        test((Object) x, cc);
    }

    public static void test(Object x, ComplexClass cc)
    {
        long start, end;
        long time1, time2, time3 = 0;
        int numToDo = 1000000;
        MyInterface interfaceClass = (MyInterface) x;

        //warming up the cache
        for (int i = 0; i < numToDo; i++)
        {
            cc.doSomething(i); //calls a method directly
        }

        start = System.currentTimeMillis();
        for (int i = 0; i < numToDo; i++)
        {
            cc.doSomething(i); //calls a method directly
        }
        end = System.currentTimeMillis();
        time1 = end - start;

        start = System.currentTimeMillis();
        for (int i = 0; i < numToDo; i++)
        {
            interfaceClass.doSomething(i); //casts an object to an interface then calls the method
        }
        end = System.currentTimeMillis();
        time2 = end - start;


        try
        {
            Class xClass = x.getClass();
            Class[] argTypes =
            {
                int.class
            };
            Method m = xClass.getMethod("doSomething", argTypes);
            Object[] paramList = new Object[1];
            start = System.currentTimeMillis();
            for (int i = 0; i < numToDo; i++)
            {
                paramList[0] = i;
                m.invoke(x, paramList); //calls via reflection
            }
            end = System.currentTimeMillis();
            time3 = end - start;

        } catch (Exception ex)
        {
        }

        System.out.println("calling a method directly: " + time1);
        System.out.println("calling a method directly from an object cast to an interface: " + time2);
        System.out.println("calling a method through reflection: " + time3);
    }
Run Code Online (Sandbox Code Playgroud)

Tom*_*ine 8

将所有测试放在同一个程序中是一个微基准测试错误 - 与Java性能相关的某些热身.这是最重要的失败.

将测试放在单独的程序中.然后多次运行测试,这样你就可以感受到热身完成和统计意义.

你还有一个包含内循环的巨大方法.Hotspot似乎比以前更好地处理这个问题,但它仍然不是很好.

您应该发现通过-server调用虚拟方法(即使由不同的类加载器加载)在紧密循环中完全优化.因此,说直接呼叫比反射呼叫快多少没有多大意义.