I\'ve always avoided Java reflection soley based on its reputation for slowness. I reached a point in the design of my current project where being able to use it would make
@Tim Bender 's code give these results on my machine(jdk_1.8_45, os_x 10.10, i7, 16G):
Reflecting instantiation took:1139ms
Normal instaniation took: 4969ms
so it seems on modern JVM, the reflection code will be optimized also well.
The JITted code for instantiating B is incredibly lightweight. Basically it needs to allocate enough memory (which is just incrementing a pointer unless a GC is required) and that's about it - there's no constructor code to call really; I don't know whether the JIT skips it or not but either way there's not a lot to do.
Compare that with everything that reflection has to do:
... and probably other things I haven't even thought of.
Typically reflection isn't used in a performance-critical context; if you need dynamic behaviour like that, you could use something like BCEL instead.
Reflection is slow for a few obvious reasons:
JIT
as wellExceptions
wrapped in InvocationTargetException
s and re-thrown etc.Just because something is 100x slower does not mean it is too slow for you assuming that reflection is the "right way" for you to design your program. For example, I imagine that IDEs make heavy use of reflection and my IDE is mostly OK from a performance perspective.
After all, the overhead of reflection is likely to pale into insignificance when compared with, say, parsing XML or accessing a database!
Another point to remember is that micro-benchmarks are a notoriously flawed mechanism for determining how fast something is in practice. As well as Tim Bender's remarks, the JVM takes time to "warm up", the JIT can re-optimize code hotspots on-the-fly etc.
It seems that if you make the constructor accessible, it will execute much faster. Now it's only about 10-20 times slower than the other version.
Constructor<B> c = B.class.getDeclaredConstructor();
c.setAccessible(true);
for (int i = 0; i < numTrials; i++) {
c.newInstance();
}
Normal instaniation took: 47ms
Reflecting instantiation took:718ms
And if you use the Server VM, it is able to optimize it more, so that it's only 3-4 times slower. This is quite typical performance. The article that Geo linked is a good read.
Normal instaniation took: 47ms
Reflecting instantiation took:140ms
But if you enable scalar replacement with -XX:+DoEscapeAnalysis then the JVM is able to optimize the regular instantiation away (it will be 0-15ms) but the reflective instantiation stays the same.
Your test may be flawed. Generally though the JVM may optimize the normal instantiation but could not make optimizations for the reflective use case.
For those wondering what the times were, I added a warmup phase and used an array to maintain the created objects (more similar to what a real program might do). I ran the test code on my OSX, jdk7 system and got this:
Reflecting instantiation took:5180ms
Normal instaniation took: 2001ms
Modified test:
public class Test {
static class B {
}
public static long timeDiff(long old) {
return System.nanoTime() - old;
}
public static void main(String args[]) throws Exception {
int numTrials = 10000000;
B[] bees = new B[numTrials];
Class<B> c = B.class;
for (int i = 0; i < numTrials; i++) {
bees[i] = c.newInstance();
}
for (int i = 0; i < numTrials; i++) {
bees[i] = new B();
}
long nanos;
nanos = System.nanoTime();
for (int i = 0; i < numTrials; i++) {
bees[i] = c.newInstance();
}
System.out.println("Reflecting instantiation took:" + TimeUnit.NANOSECONDS.toMillis(timeDiff(nanos)) + "ms");
nanos = System.nanoTime();
for (int i = 0; i < numTrials; i++) {
bees[i] = new B();
}
System.out.println("Normal instaniation took: " + TimeUnit.NANOSECONDS.toMillis(timeDiff(nanos)) + "ms");
}
}