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()));}