Java Double.valueOf

2022-09-04 02:33:12

在我的工作中,所有开发人员都使用Double.valueOf而不是新的Double构造函数。在每种情况下。对于整数或短整型,我可以理解缓存值,但对于 和 则不理解。doublefloat

我在OpenJDK源代码中查看Double.valueOf:

 /**
 * Returns a {@code Double} instance representing the specified
 * {@code double} value.
 * If a new {@code Double} instance is not required, this method
 * should generally be used in preference to the constructor
 * {@link #Double(double)}, as this method is likely to yield
 * significantly better space and time performance by caching
 * frequently requested values.
 *
 * @param  d a double value.
 * @return a {@code Double} instance representing {@code d}.
 * @since  1.5
 */
public static Double valueOf(double d) {
    return new Double(d);
}

所以它只调用 s 构造函数。我可以理解为什么存在与整数/短整型相干的方法...Double

但是对方法的评论:

此方法通常应优先于构造函数使用

在我看到它对每个方法的相同评论之后。(整数,短 ...)valueOf()

评论是假的吗?还是其他流程干预?

我听说过Java中的内在方法,下一步是在热点代码和vmSymbol.hpp中搜索。

/* boxing methods: */                                                                                                 \
   do_name(    valueOf_name,              "valueOf")                                                                    \
  do_intrinsic(_Boolean_valueOf,          java_lang_Boolean,      valueOf_name, Boolean_valueOf_signature, F_S)         \
   do_name(     Boolean_valueOf_signature,                       "(Z)Ljava/lang/Boolean;")                              \
  do_intrinsic(_Byte_valueOf,             java_lang_Byte,         valueOf_name, Byte_valueOf_signature, F_S)            \
   do_name(     Byte_valueOf_signature,                          "(B)Ljava/lang/Byte;")                                 \
  do_intrinsic(_Character_valueOf,        java_lang_Character,    valueOf_name, Character_valueOf_signature, F_S)       \
   do_name(     Character_valueOf_signature,                     "(C)Ljava/lang/Character;")                            \
  do_intrinsic(_Short_valueOf,            java_lang_Short,        valueOf_name, Short_valueOf_signature, F_S)           \
   do_name(     Short_valueOf_signature,                         "(S)Ljava/lang/Short;")                                \
  do_intrinsic(_Integer_valueOf,          java_lang_Integer,      valueOf_name, Integer_valueOf_signature, F_S)         \
   do_name(     Integer_valueOf_signature,                       "(I)Ljava/lang/Integer;")                              \
  do_intrinsic(_Long_valueOf,             java_lang_Long,         valueOf_name, Long_valueOf_signature, F_S)            \
   do_name(     Long_valueOf_signature,                          "(J)Ljava/lang/Long;")                                 \
  do_intrinsic(_Float_valueOf,            java_lang_Float,        valueOf_name, Float_valueOf_signature, F_S)           \
   do_name(     Float_valueOf_signature,                         "(F)Ljava/lang/Float;")                                \
  do_intrinsic(_Double_valueOf,           java_lang_Double,       valueOf_name, Double_valueOf_signature, F_S)          \
   do_name(     Double_valueOf_signature,                        "(D)Ljava/lang/Double;")       

因此,在我进入源代码并找到witebox之后.cppDouble.valueOf

static jobject doubleBox(JavaThread* thread, JNIEnv* env, jdouble value) {
  return box(thread, env, vmSymbols::java_lang_Double(), vmSymbols::Double_valueOf_signature(), value);
}

和框方法代码:

template <typename T>
static jobject box(JavaThread* thread, JNIEnv* env, Symbol* name, Symbol* sig, T value) {
  ResourceMark rm(thread);
  jclass clazz = env->FindClass(name->as_C_string());
  CHECK_JNI_EXCEPTION_(env, NULL);
  jmethodID methodID = env->GetStaticMethodID(clazz,
        vmSymbols::valueOf_name()->as_C_string(),
        sig->as_C_string());
  CHECK_JNI_EXCEPTION_(env, NULL);
  jobject result = env->CallStaticObjectMethod(clazz, methodID, value);
  CHECK_JNI_EXCEPTION_(env, NULL);
  return result;
}

和此代码...

好吧,我还没有进步。此方法 box() 真的在服务器模式下调用的吗?

简历:D的3个问题

  1. JVM 拦截调用此框方法?Double.valueOf()

  2. Double.valueOf不使用 JDK 源代码,也不执行 ?new Double()

  3. 评论只是转储复制/粘贴,并具有相同的效果?Double.valueOf()Double.valueOfnew Double


答案 1
  1. Integer(int),并且类似的构造函数被弃用(是的,它们实际上被标记为 ),因为Java 9作为JEP 277的一部分。Double(double)@Deprecated

    弃用注释告诉我们

    静态工厂通常是一个更好的选择,因为它可能会产生更好的空间和时间性能。valueOf(double)

    尽管 OpenJDK 目前不缓存盒装双精度,但静态工厂方法为将来的优化开辟了一条路径。如果决定在 JVM 或类库中改进双精度值的自动装箱,则应用程序将自动从优化中受益,而无需用户端进行任何更改。

  2. 另一个原因是这确实是HotSpot中的一种固有方法。JVM了解自动装箱方法,并将这些知识用于消除自动框优化。Double.valueOf

    有两个相关的优化:消除分配和消除自动框。尽管它们都是由逃逸分析提供的,并且看起来很相似,但它们应用于略有不同的上下文中,因此可能会发生一个优化起作用的情况,而另一个优化不起作用,反之亦然。

    当自动框消除成功时,例如,当 JIT 编译器发现匹配和调用,并且对象未转义时,优化程序将完全删除这两个调用。valueOfdoubleValue

    顺便说一句,提到的白盒代码是无关紧要的。除了用于内部 HotSpot 测试目的外,它不用于其他用途。

  3. 目前正在积极开发的Valhalla项目导致了对原始包装器的完全重新思考。

    目前的想法是使 ,等内联类型,以及它们的参考投影。作为迁移步骤,并且将成为密封的抽象类,因此无法通过构造函数实例化它们。intdoubleIntegerDoubleIntegerDouble

    因此,请考虑弃用构造函数作为Valhalla项目的中间步骤。通过鼓励使用工厂方法,JDK开发人员为他们可以在引擎盖下进行的许多优化扫清了道路,包括尽可能内联实例。Double


答案 2

简短的回答:一致性

这是您在编码时应该努力实现的概念,因为它减少了出错的机会,并使代码更易于阅读。


此外,您永远不知道随时可以添加哪些优化,因此请使用该方法,除非您需要新值(这是非常罕见的)。仅仅因为它现在不缓存通用值,并不意味着将来不会缓存,或者不会在不同的实现中缓存。valueOf()Double

这是一个称为面向未来的概念,这也是您在编码时应该努力实现的目标。


推荐