简体   繁体   English

Class.forName() 缓存

[英]Class.forName() caching

In one of my applications I am using the following:在我的一个应用程序中,我使用了以下内容:

public void calculate (String className)
{
  ... 
  Class clazz = Class.forName(className);
  ...
}

This function is called several times / second.这个函数被调用几次/秒。 There are about 10 possible class names.大约有 10 个可能的类名。 And while I do realize there is some internal caching inside this function, I think this caching is only available on native level.虽然我确实意识到这个函数中有一些内部缓存,但我认为这种缓存仅在本机级别可用。

For this reason I am starting to wonder if I should add my own caching.出于这个原因,我开始怀疑是否应该添加自己的缓存。

private static Map<String,Class> classMap;

public void calculate (String className)
{
  ... 
  Class clazz = classMap.get(className);
  if (clazz == null) 
  {
      clazz = Class.forName(className);
      if (classMap == null) classMap = new HashMap<String, Class>(40);
      classMap.put(className, clazz);
  }
  ...
}

Will this be a performance gain or does it really make no difference ?这是性能提升还是真的没有区别?

Thank you in advance先感谢您

I wrote a little script to calculate the execution time of both functions.我写了一个小脚本来计算两个函数的执行时间。

This is the Main class that I used.这是我使用的 Main 类。

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这是使用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.这是使用HashMap缓存Class对象的第二个实现。

  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. 1100 毫秒,无缓存。
  • only 15 ms with caching.缓存只有 15 毫秒。

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.我强烈希望Class.forName无论如何都会缓存它,并且在您的应用程序中增加更多的复杂性并没有好处。

Class.forName() does two things: Class.forName()做了两件事:

  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.第 1 部分非常快。 #2 is where the real work starts (where the JVM might hit the hard disk or even the network, depending on the classloader). #2 是真正开始工作的地方(JVM 可能会访问硬盘甚至网络,具体取决于类加载器)。 And if you pass the same parameters in, then all but the first invocations will never get to step #2.如果您传入相同的参数,那么除了第一次调用之外的所有调用都将永远不会到达第 2 步。

So no: it's probably not worth optimizing.所以不:它可能不值得优化。

No you shouldn't.不,你不应该。 Class.forName will not load the same class twice but will try to find the class among the loaded classes. Class.forName 不会两次加载同一个类,而是会尝试在加载的类中查找该类。 It's done at native level and supposed to be very efficient.它是在本机级别完成的,应该非常有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM