preface

In our usual work or interview, will often encounter “reflection” this knowledge point, through “reflection” we can dynamically obtain the information of the object and flexible call object method, but in use at the same time accompanied by another sound, that is, “reflection” is very slow, to use less. Is the reflection really slow? How much slower is that than when we normally create objects and call methods? A lot of people probably haven’t been tested, just “hearsay.” Let’s get a feel for reflection directly through some test cases.

The body of the

Preparing test objects

Let’s define a test class TestUser with only id and name attributes and their getters/setters, and a custom sayHi method.

public class TestUser {
    private Integer id;
    private String name;
    
    public String sayHi(a){
        return "hi";
    }

    public Integer getId(a) {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name; }}Copy the code
The test creates 1 million objects
// Create the TestUser object in the normal way
@Test
public void testCommon(a){
    long start = System.currentTimeMillis();
    TestUser user = null;
    int i = 0;
    while(i<1000000){
        ++i;
        user = new TestUser();
    }
    long end = System.currentTimeMillis();
    System.out.println("Common object creation time:"+(end - start ) + "ms");
}

// common object creation takes 10ms
Copy the code
// Create the TestUser object by reflection
@Test
public void testReflexNoCache(a) throws Exception {
    long start = System.currentTimeMillis();
    TestUser user = null;
    int i = 0;
    while(i<1000000){
        ++i;
        user = (TestUser) Class.forName("ReflexDemo.TestUser").newInstance();
    }
    long end = System.currentTimeMillis();
    System.out.println("No cache reflection object creation time:"+(end - start ) + "ms");
}

// no cache reflection object creation time: 926ms
Copy the code

In the above two test methods, the author tested themselves for 5 times and averaged their consumption time. In the output result, we can see that one is 10ms and the other is 926ms. In the case of creating 100W objects, the reflection is about 90 times slower. WTF? How big a difference is that? Is the reflection really so slow? The following author for a reflection of the posture, continue to test, see how the result?

// Create the TestUser object using cache reflection
@Test
public void testReflexWithCache(a) throws Exception {
    long start = System.currentTimeMillis();
    TestUser user = null;
    Class rUserClass = Class.forName("RefleDemo.TestUser");
    int i = 0;
    while(i<1000000){
        ++i;
        user = (TestUser) rUserClass.newInstance();
    }
    long end = System.currentTimeMillis();
    System.out.println("Time to create objects by cache reflection:"+(end - start ) + "ms");
}

// it takes 41ms to create objects by cache reflection
Copy the code

Yi? This operation only takes 41ms, greatly improving the efficiency of reflection to create objects. Why so much faster?

The class.forname method, which is time-consuming, actually calls a local method that asks the JVM to find and load the specified Class. Therefore, we can cache the Class object returned by class.forname when we use it in the project, and retrieve it directly from the cache when we use it next time. This greatly improves the efficiency of obtaining the Class. Similarly, we can cache objects such as Constructor and Method to avoid time-consuming creation each time we use them.

Test the reflection call method
@Test
public void testReflexMethod(a) throws Exception {
    long start = System.currentTimeMillis();
    Class testUserClass = Class.forName("RefleDemo.TestUser");
    TestUser testUser = (TestUser) testUserClass.newInstance();
    Method method = testUserClass.getMethod("sayHi");
    int i = 0;
    while(i<100000000){
        ++i;
        method.invoke(testUser);
    }
    long end = System.currentTimeMillis();
    System.out.println("Reflection call method time:"+(end - start ) + "ms");
}

// Reflection call method time: 330ms
Copy the code
@Test
public void testReflexMethod(a) throws Exception {
    long start = System.currentTimeMillis();
    Class testUserClass = Class.forName("RefleDemo.TestUser");
    TestUser testUser = (TestUser) testUserClass.newInstance();
    Method method = testUserClass.getMethod("sayHi");
    int i = 0;
    while(i<100000000){
        ++i;
        method.setAccessible(true);
        method.invoke(testUser);
    }
    long end = System.currentTimeMillis();
    System.out.println("SetAccessible =true Reflection method call time:"+(end - start ) + "ms");
}

//setAccessible=true Reflection call method time: 188ms
Copy the code

Here we call the sayHi method 100 million times, and after calling method.setaccessible (true), it’s nearly half that fast. As you can see from the API, the JDK performs security access checks when setting fetch fields and calling methods. Such operations are time-consuming, so you can use setAccessible(true) to disable security checks and improve reflection efficiency.

Extreme reflection

In addition to the above methods, is there any way to use reflection more extreme? This section describes a high-performance reflection toolkit, ReflectASM. It is a reflection mechanism implemented in the form of bytecode generation. Here is a performance comparison with Java reflection.

Here will not introduce its use, interested friends can directly send to the past: github.com/EsotericSof…

conclusion

In conclusion, in order to make better use of reflection, we should load the configuration and data required by reflection into memory at project startup, and fetch the metadata from the cache for reflection at run time. There is no need to be afraid of reflection, the virtual machine is constantly optimized, as long as we use the right method, it is not as slow as the “rumor”, when we are in pursuit of extreme performance, we can consider using the three-party package, directly to the bytecode operation.


Public account blog sync Github warehouse, interested friends can help give a Star oh, code word is not easy, thank you for your support.

Github.com/PeppaLittle…

Recommended reading

“Proper Java Logging posture” “Thread Safety with ConcurrentHashMap?” How to Save yourself from a JVM Explosion

Follow the late Night programmer to share the driest stuff