前言

都说Java反射效率慢,个人也只是听说而已,到底慢在哪里? 又有多么慢?
今天就来分析下,此片博客与诸君共享,也当记录下自己的成果。

反射demo 设计

  1. 代码 new 和 class.newInstance() 方法的区别, Class.forName 方法 实验。
  2. 代码方法调用 和 method.invoker() 方法分析,class.getMethod 方法分析。
  3. Field 去赋值 和getField() 效率实验。

实验demo

package com.lc.reflect;

import com.lc.demo.User;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTest {

    public static void testNew() {
        long starTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            User user = new User();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("newTime: " + (endTime - starTime));
    }

    public static void testForNameNew() throws Exception {
        long starTime = System.currentTimeMillis();
        Class<?> userClass = Class.forName("com.lc.demo.User");
        for (int i = 0; i < 100000; i++) {
            User user = (User) userClass.newInstance();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("classNewTime: " + (endTime - starTime));
    }

    public static void testConstructor() throws Exception {
        long starTime = System.currentTimeMillis();
        Class<?> userClass = Class.forName("com.lc.demo.User");
        Constructor<?> constructor = userClass.getConstructor();
        System.out.println("constructor: " + constructor);
        for (int i = 0; i < 100000; i++) {
            User user = (User) constructor.newInstance();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("classNewTime: " + (endTime - starTime));
    }

    public static void testSet() {
        long starTime = System.currentTimeMillis();
        User user = new User();
        for (int i = 0; i < 100000; i++) {
            user.setId(1);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("newTime: " + (endTime - starTime));
    }


    public static void testMethodSet() throws Exception {
        User user = new User();
        long starTime = System.currentTimeMillis();

        for (int i = 0; i < 100000; i++) {
            Method setName = User.class.getMethod("setName", String.class);
            setName.invoke(user, "ss");
        }
        long endTime = System.currentTimeMillis();
        System.out.println("newTime: " + (endTime - starTime));
    }

    public static void testField() throws Exception {
        User user = new User();
        long starTime = System.currentTimeMillis();

        for (int i = 0; i < 100000; i++) {
            Field name = User.class.getDeclaredField("name");
            name.setAccessible(true);
            name.set(user, "ss");
        }
        long endTime = System.currentTimeMillis();
        System.out.println("newTime: " + (endTime - starTime));
    }

    public static void main(String[] args) throws Exception {
        // testNew(); // 8  100000次new 对象,5次实验取中位数
        /**
         * 150(forName 放入for循环的情况下)  100000次forName 对象,5次实验取中间值,forName
         * 放出来的话 时间在15-28 徘徊
         */
        //testForNameNew();
        //testConstructor(); //28-38  100000次constructor.newInstance 对象 5次实验取中位数

        //testSet(); //0-2

        testMethodSet(); //20-41, 在getMethod 方法不及时的情况下,  getMethod 方法计时的情况下,任然为20-43,基本无区别。 在getmethod 方法在循环内的情况下为140-170 之间

        //testField(); //17-28(在获取field 后在做循环的情况下) 中间。 在field 在循环内部的时候 时间在79-100 中间
    }
}

结论

以上demo 我们已100000 为总体样本,每个都做5次实验,从其中的数据上我们大概的可以分析出以下结论

  1. newclass.newInstance() 方法在效率上大概的有 3 倍到4 倍的性能差距。而在Class.forName 也放入循环后,效率上达到几十倍的性能差距,可见主要耗时还是在Class.forName 上, 而使用constructor 和 class.newInstance(),在效率上基本无差别。
  2. method方法调用 性能执行上大概有个20 倍的性能差距,而在将 class.getMethod 放入循环后,差距达到了上百倍,所以可以看出,单纯的使用method.invoke() 方法调用 问题还是不大,(这个经过请教一位公司大佬,发现在 jdk1.8 里边 method.invoke 在调用30 次后,会变成方法执行,也就是生成代码类似于asm 或者javasisit 直接代码生成)。所以效率主要耗在寻找method 里边。
  3. Field 在执行field.set() 性能上大概在10 多倍的差距,比method.invoke() 甚至还要快一点,但在将Feild 获取也加入到循环里边去的时候,和直接的代码调用效率差距大概在50-70 倍之间,由此可以看出,所有的field,method在执行的时候效率还可以,差距大概和直接的代码调用在20多倍的差距间但获取这个field 和method (getField, getMethod) 这些后效率上升数个数量级