为什么 Double.valueof javadoc 说它会缓存值,而实际上却没有?
在 OpenJDK 中,对于方法:
public static Double valueOf(double d)
javadoc 说:
返回表示指定双精度值的 Double 实例。如果不需要新的 Double 实例,通常应优先使用此方法而不是构造函数 Double(double),因为此方法可能通过缓存频繁请求的值来产生显着更好的空间和时间性能。
这是实际的代码:
public static Double valueOf(double d) {
return new Double(d);
}
缓存是一个谎言!这是怎么回事?
In OpenJDK, for the method:
public static Double valueOf(double d)
The javadoc says:
Returns a Double instance representing the specified double value. If a new Double instance is not required, this method should generally be used in preference to the constructor Double(double), as this method is likely to yield significantly better space and time performance by caching frequently requested values.
Here's the actual code:
public static Double valueOf(double d) {
return new Double(d);
}
The cache is a lie! What's going on here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
该方法存在多种类型:
Integer
、Long
、BigDecimal
等,并且文档始终相同:在某些情况下(这些情况不是) t 定义),该方法可以返回相同的结果。AFAIK,缓存仅针对整数类型实现,并且它返回 -128 到 127(最常见的值)之间的值的缓存实例。对于
BigDecimal
,缓存当前适用于 0 到 10 之间的值。Java的更高版本可能将此行为扩展到其他值/更多类型。因此,今天使用此代码是明智的,因为它可能会使您明天的代码更快(并且今天的代码不会变慢)。
例如,Java 编译器在生成自动装箱代码时使用此 API。
The method exists for many types:
Integer
,Long
,BigDecimal
and others and the documentation is always the same: Under some circumstances (which aren't defined), the method can return the same result.AFAIK, the caching is only implemented for integer types and it returns cached instances for values between -128 and 127 (most common values). For
BigDecimal
, the cache currently works for values from 0 to 10.Later versions of Java might extend this behavior to other values/more types. So it's smart to use this code today because it might make your code faster tomorrow (and the code won't be slower today).
The Java compiler, for example, uses this API when generating code for autoboxing.
API文档没有任何问题:
也就是说,允许实现在这里进行缓存,而这对于构造函数来说是不可能的。然而,这不是必需的。但是,由于您很可能有一个执行缓存的实现,因此应优先使用此方法而不是使用构造函数。
There is nothing wrong with the API doc:
That is, an implementation is allowed to do caching here, which is simply not possible with a constructor. However, it is not required to. But, since chances are that you have an implementation that performs caching, this method should be preferred over using a constructor.
从 Java 1.5+ 开始,JVM/JIT 保证
Integer
的缓存 -127 到 127。因此,对于Integer
,首选方法是使用valueOf
。通常,您应该使用valueOf
而不是使用double
的构造函数,因为这样 JIT 就能够根据需要优化您的代码。例如,考虑以下循环:在这种情况下,JIT 可以预先计算 double 对象并在循环的每次迭代中重新分配相同的值,而如果您要使用
new Double(0.0);
它无法做到这一点。From Java 1.5+, the JVM/JIT guarantees the caching of
Integer
s -127 to 127. So that is why forInteger
the preferred approach is to usevalueOf
. You should generally usevalueOf
over using the constructor fordouble
because then the JIT is able to optimise your code as it sees fit. For example, consider the following loop:In this instance, the JIT can precalculate the double object and reassign the same value on each iteration of the loop, whereas if you were to use
new Double(0.0);
it would not be able to do that.API 的设计者可能不想限制替代实现。现在可以自由地将缓存添加到
Double
类中。The designers of the API probably didn’t want to restrict alternate implementation. Those are now free to add caching to the
Double
class.这些
valueOf()
方法存在于每个数字类型中,目的是支持缓存。事实上,对于 Double 来说,除了 Integer 和 Long 之外,它不使用任何缓存。These
valueOf()
methods exist in every numeric type for the purpose to support caching. In fact, for Double it does not use any cache but forInteger
andLong
.请记住,JVM 的创建是为了减少嵌入式设备的代码大小(主要是)——它是一个机顶盒操作系统。我在一些嵌入式java平台上工作过,在这些平台上,valueOf的“值”会更加明显,在某些情况下它会节省相当多的空间。
大多数情况下,该方法存在是因为“新”无法使用缓存的实例。 valueOf 可以实现为使用缓存实例(否则您将始终使用 new),并且可能会在任何证明可以节省时间的地方执行此操作。
如果他们(或您)用实际缓存值的方法替换该方法,那么您的所有代码都将获得这一更改的优势,但如果不通过提供像“valueOf”这样的方法进行准备,它永远不会发生(好吧,实际上永远不会 -您可以调整编译器/字节码执行器以具有“新”返回缓存值,但我认为这会破坏一些合同)
因此缓存并不是真正的谎言,只是一种心态。
Remember that the JVM was created to reduce code size for embedded devices (mostly)--it's a set-top box operating system. I've worked on a few embedded java platforms and on those the "value of" valueOf would be more obvious, it would save quite a bit of space in some cases.
Mostly the method exists because "new" cannot ever use cached instances. valueOf MAY be implemented to use cached instances (otherwise you would just always use new) and likely does wherever it proves to save time.
If they (or you) replaced that method with one that actually did cache values then all your code would gain the advantage of that change, but without preparing by providing a method like "valueOf" it could never happen (well, practically never--you could tweak the compiler/bytecode executor to have "new" return cached values but I think that would break some contracts)
So the cache isn't really a lie, just a state of mind.