On a faster java.lang.reflect.Method using Javassist
adrian.brock Feb 19, 2006 8:11 AMI've been playing with generating our own reflection objects
rather than using the JDK classes.
My Javassist reflection methods are significantly faster
int iterations = 10000000; public void testStressJavassist() throws Throwable { ClassInfo typeInfo = getClassInfo(String.class); MethodInfo methodInfo = typeInfo.getDeclaredMethod("toString", null); String hello = "Hello"; long start = System.currentTimeMillis(); for (int i = 0; i < iterations; ++i) methodInfo.invoke(hello, null); long end = System.currentTimeMillis(); System.out.println("testStressJavassist " + (end - start) + "ms"); } public void testStressReflect() throws Throwable { Method method = String.class.getDeclaredMethod("toString", null); String hello = "Hello"; long start = System.currentTimeMillis(); for (int i = 0; i < iterations; ++i) method.invoke(hello, null); long end = System.currentTimeMillis(); System.out.println("testStressReflect " + (end - start) + "ms"); } public void testStressJavassist2() throws Throwable { ClassInfo typeInfo = getClassInfo(String.class); TypeInfo intInfo = getTypeInfo(Integer.TYPE); MethodInfo methodInfo = typeInfo.getDeclaredMethod("charAt", new TypeInfo[] { intInfo }); String hello = "Hello"; Object[] params = { new Integer(4) }; long start = System.currentTimeMillis(); for (int i = 0; i < iterations; ++i) methodInfo.invoke(hello, params); long end = System.currentTimeMillis(); System.out.println("testStressJavassist2 " + (end - start) + "ms"); } public void testStressReflect2() throws Throwable { Method method = String.class.getDeclaredMethod("charAt", new Class[] { Integer.TYPE }); String hello = "Hello"; Object[] params = { new Integer(4) }; long start = System.currentTimeMillis(); for (int i = 0; i < iterations; ++i) method.invoke(hello, params); long end = System.currentTimeMillis(); System.out.println("testStressReflect2 " + (end - start) + "ms"); }
Output - you can also see the cost of Autoboxing the int ;-)
testStressJavassist 479ms testStressReflect 2937ms testStressJavassist2 1153ms testStressReflect2 3344ms
Rather than showing the code used to generate the class
here is the generated code:
java.lang.String.toString(); public Object invoke(Object target, Object[] args) throws Throwable {if (target == null) throw new IllegalArgumentException("Null target for toString()Ljava/lang/String;");if (target instanceof java.lang.String == false) throw new IllegalArgumentException("Target " + target + " i s not an instance of java.lang.String for toString()Ljava/lang/String;");if (args != null && args.length != 0)throw new IllegalArgumentExcep tion("Expected no parameters for toString()Ljava/lang/String;");return ((java.lang.String)target).toString();} java.lang.String.charAt(int); public Object invoke(Object target, Object[] args) throws Throwable {if (target == null) throw new IllegalArgumentException("Null target for charAt(I)C");if (target instanceof java.lang.String == false) throw new IllegalArgumentException("Target " + target + " is not an instance of java.lang.String for charAt(I)C");if (args == null || args.length != 1) throw new IllegalArgumentException("Expected 1 parameter(s) for c harAt(I)C");if (args[0] == null) throw new IllegalArgumentException("Parameter 0 cannot be null for int for charAt(I)C");if (args[0] != null && args[0] instanceof java.lang.Integer == false) throw new IllegalArgumentException("Parameter 0 is not an instance of java.lang.Integer f or charAt(I)C");return new java.lang.Character(((java.lang.String)target).charAt(((java.lang.Integer)args[0]).intValue()));}
I also have an option for turning off parameter checking,
but this doen't seem to make any measurable difference to the numbers
although the generated code is easier to understand :-)
String.toString(); public Object invoke(Object target, Object[] args) throws Throwable {return ((java.lang.String)target).toString();} String.charAt(int); public Object invoke(Object target, Object[] args) throws Throwable {return new java.lang.Character(((java.lang.String)target).charAt(((java .lang.Integer)args[0]).intValue()));}