Home >Java >javaTutorial >How to improve the efficiency of using Java reflection
In our daily work or interviews, we often encounter the knowledge point of "reflection". Through "reflection" we can dynamically obtain object information and flexibly call object methods, etc., but at the same time we use it Along with the emergence of another sound, that is, "reflection" is very slow and should be used sparingly. Is reflection really slow? How much slower is it than when we usually create objects and call methods? I guess many people have never tested it, they just "heard" it. Let's directly experience "reflection" directly through some test cases.
Text
Prepare the test object
The following defines a test class TestUser, which only has the id and name attributes, as well as their getter/setter methods, and a self- Define the sayHi method.
public class TestUser { private Integer id; private String name; public String sayHi(){ return "hi"; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Test to create 1 million objects
// 通过普通方式创建TestUser对象@Testpublic void testCommon(){ long start = System.currentTimeMillis(); TestUser user = null; int i = 0; while(i<1000000){ ++i; user = new TestUser(); } long end = System.currentTimeMillis(); System.out.println("普通对象创建耗时:"+(end - start ) + "ms"); }//普通对象创建耗时:10ms
// 通过反射方式创建TestUser对象@Testpublic void testReflexNoCache() 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("无缓存反射创建对象耗时:"+(end - start ) + "ms"); }//无缓存反射创建对象耗时:926ms
In the above two test methods, the author tested each 5 times, took an average of the time they consumed, and output You can see from the results that one is 10ms and the other is 926ms. When 1 million objects are created, reflection is actually about 90 times slower. wtf? Is the gap so big? Is reflection really that slow? Next, the author changes the reflection posture and continues to test it to see what the result is?
// 通过缓存反射方式创建TestUser对象@Testpublic void testReflexWithCache() 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("通过缓存反射创建对象耗时:"+(end - start ) + "ms"); }//通过缓存反射创建对象耗时:41ms
In fact, we can find through the code that the Class.forName method is more time-consuming. It actually calls a local method, through which the JVM is asked to find and load the specified class. Therefore, when we use it in the project, we can cache the Class object returned by Class.forName, and obtain it directly from the cache the next time it is used, which greatly improves the efficiency of obtaining Class. In the same way, when we obtain Constructor, Method and other objects, we can also cache them for use to avoid time-consuming creation every time they are used.
Testing the reflection calling method
@Testpublic void testReflexMethod() 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("反射调用方法耗时:"+(end - start ) + "ms"); }//反射调用方法耗时:330ms
@Testpublic void testReflexMethod() 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 反射调用方法耗时:"+(end - start ) + "ms"); }//setAccessible=true 反射调用方法耗时:188ms
Here we reflect and call the sayHi method 100 million times. After calling method.setAccessible(true), found that it is nearly half faster. Looking at the API, we can learn that jdk will perform security access checks when setting the acquisition field and calling methods, and such operations will be time-consuming, so you can turn off security checks through setAccessible(true), thereby improving reflection efficiency.
The Ultimate Reflection
In addition to the above methods, is there any way to use reflection to the extreme? Here we introduce ReflectASM, a high-performance reflection toolkit. It is a reflection mechanism implemented through bytecode generation. The following is a performance comparison with Java reflection.
Conclusion
Finally, to summarize, In order to better use reflection, we should load the relevant configuration and data required for reflection into the memory when the project starts, and then run Each stage fetches these metadata from the cache for reflection operations. You don’t have to be afraid of reflection. The virtual machine is constantly being optimized. As long as we use the right method, it is not as slow as “rumored”. When we have the ultimate pursuit of performance, we can consider using third-party packages to directly Code operation.
Related tutorials: Java video tutorial
The above is the detailed content of How to improve the efficiency of using Java reflection. For more information, please follow other related articles on the PHP Chinese website!