Class.forName() caching

Class.forName() does two things:

  1. it fetches a loaded class from the classloader
  2. if no such class is found, it tries to load it.

Part #1 is pretty quick. #2 is where the real work starts (where the JVM might hit the hard disk or even the network, depending on the classloader). And if you pass the same parameters in, then all but the first invocations will never get to step #2.

So no: it's probably not worth optimizing.


I wrote a little script to calculate the execution time of both functions.

This is the Main class that I used.

public class Benchmark
{
  public static void main(String... pArgs)
  {
    // prepare all data as much as possible.
    // we don't want to do this while the clock is running.
    Class[] classes = {Object.class, Integer.class, String.class, Short.class, Long.class, Double.class,
                       Float.class, Boolean.class, Character.class, Byte.class};
    int cycles = 1000000;
    String[] classNames = new String[cycles];
    for (int i = 0; i < cycles; i++) 
    {
      classNames[i] = classes[i % classes.length].getName();
    }

    // THERE ARE 2 IMPLEMENTATIONS - CLASSIC vs CACHING
    Implementation impl = new Caching();   // or Classic();

    // Start the clocks !
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < cycles; i++)
    {
      impl.doStuff(classNames[i]);
    }
    long endTime = System.currentTimeMillis();

    // calculate and display result
    long totalTime = endTime - startTime;
    System.out.println(totalTime);
  }
}

Here is the classic implementation that uses Class.forName

  private interface Implementation
  {
    Class doStuff(String clzName);
  }

  private static class Classic implements Implementation
  {
    @Override
    public Class doStuff(String clzName)
    {
      try
      {
        return Class.forName(clzName);
      }
      catch (Exception e)
      {
        return null;
      }
    }
  }

Here is the second implementation that uses a HashMap to cache the Class objects.

  private static class Caching implements Implementation
  {
    private Map<String, Class> cache = new HashMap<String, Class>();

    @Override
    public Class doStuff(String clzName)
    {
      Class clz = cache.get(clzName);
      if (clz != null) return clz;
      try
      {
        clz = Class.forName(clzName);
        cache.put(clzName, clz);
      }
      catch (Exception e)
      {
      }
      return clz;
    }
  }

The results:

  • 1100 ms without caching.
  • only 15 ms with caching.

Conclusion:

  • Is it a significant difference --> yes !
  • Does it matter for my application --> not at all.

Will this be a performance gain or does it really make no difference?

I would be astonished if it made a significant difference - and if you're only calling it "several times per second" (rather than, say, a million) it's really not worth optimizing.

You should at least try this in isolation in a benchmark before committing to this more complicated design. I would strongly expect Class.forName to be caching this anyway, and adding more complexity into your app does no good.