【问题标题】:Why is Class.getSimpleName() not cached?为什么 Class.getSimpleName() 没有被缓存?
【发布时间】:2013-06-28 16:21:10
【问题描述】:

如果您查看 Sun 实现 Class.getSimpleName() 的源代码,您会注意到每次调用它时似乎都会返回一个新的 String 实例。但是,Class 类中的许多其他功能都被缓存了。

由于简单的名称计算似乎并不容易,并且 JavaDoc 中没有说明它每次都必须返回一个新实例,因此它应该是缓存的一个很好的候选者。我想知道为什么没有缓存有任何设计原因?

我之所以这么问,是因为许多框架一直都使用简单的名称,而这很容易缓存。

【问题讨论】:

  • 缓存它会增加每个类所持有的内存,从而获得值得怀疑的性能提升。
  • 如果您愿意,您可以随时使用 AspectJ 添加自己的缓存。
  • @JBNizet 但是对于任何非数组类型,操作是一个潜在的 intern'ed 字符串的子字符串,不需要太多额外的内存。
  • 似乎这是要问 Sun 的问题,而不是 SO。
  • 缓存,至少在Java 12中。请参阅Class.java的OpenJDK源代码并搜索private ReflectionData<T> reflectionData()调用的方法getSimpleName 方法。

标签: java


【解决方案1】:

更新:名称缓存在 OpenJDK 11 中

类名 在 OpenJDK 11 及更高版本中被缓存。请参阅 Class.java 的 OpenJDK 源代码并搜索从 getSimpleName 方法调用的 private ReflectionData<T> reflectionData() 方法。

详情见票JDK-8187123

【讨论】:

    【解决方案2】:

    可能是因为它不是一种昂贵的方法,所以缓存它并没有什么好处。

    String.substring 是一种廉价的方法——它重用底层的char[] 而不复制它,并且新的String 对象只是在该数组中具有不同的偏移量和长度。所以真正唯一的成本是(1)对象分配——这在Java中相当便宜——和(2)lastIndexOf调用。该调用在技术上是 O(N),但这里的 N 是类的简单名称,在实践中不会很大。

    你可以缓存它,但代价是更多的内存。我的猜测是,有人做出了主观但有根据的猜测,即收益不会超过成本。

    【讨论】:

    • 这里最重要的成本不是 substring(),而是为了将字符串转换为子字符串而调用的其他方法。还有getSimpleBinaryName()无条件调用getEnclosingClass()调用getEnclosingMethodInfo()等等,整个过程在我看来并不便宜。
    • @billc.cn 我不知道,它都终止于像getEnclosingMethod0() 这样的原生方法。很难知道它有多便宜或多贵。
    • substring sometimes 使用底层的 char 数组 -- 这取决于具体的实现。
    • @HotLicks OP 询问了 Sun 的实现并链接到特定版本 (openjdk-6-b14) 中的代码。我在回答中假设了这种情况。
    • 我想指出,这不再是真的。 Java 7 使 substring 实际上复制了底层字符串。 stackoverflow.com/questions/16123446/… 。我在 LinkedIn 上分析了很多 Java 8 服务器应用程序,由于这个事实,访问类的简单名称会占用大量 CPU(5-10% 之间)。
    【解决方案3】:

    有趣的问题。由于 String 是一个不可变类,因此返回不同的实例或对同一对象的引用并不重要。 我的猜测是(而且我主要是听听我是对还是错)也许该方法不会经常被调用,并且重新创建 (String) 对象比将其存储在其中更有意义记忆。但同样,这只是一个猜测。

    【讨论】:

      猜你喜欢
      • 2023-03-20
      • 1970-01-01
      • 2011-05-17
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      • 2016-09-28
      • 1970-01-01
      相关资源
      最近更新 更多