Java Double.valueOf

fab*_*tch 14 java jvm

在我的工作中,所有开发人员都使用Double.valueOf而不是new Double构造函数。在每种情况下。对于 Integer 或 Short 我可以理解它的缓存值但不是 fordoublefloat

在 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);
}
Run Code Online (Sandbox Code Playgroud)

所以它只是调用Doubles 构造函数。我可以理解为什么存在与整数/短一致的方法...

但对该方法的评论:

这种方法通常应该优先于构造函数使用

在我看到它对每种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;")       
Run Code Online (Sandbox Code Playgroud)

所以在我Double.valueOf在源代码中grep 之后,我找到了withebox.cpp

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

和框方法代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

而这段代码...

好吧,我还没进阶。这个方法 box() 真的是在服务器模式下调用的吗?

简历的 3 个问题 :D

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

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

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

apa*_*gin 11

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

    弃用评论告诉

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

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

  2. 另一个原因是这Double.valueOf确实是 HotSpot 中的一个内在方法。JVM知道自动装箱方法,并在EliminateAutoBox优化中使用这些知识。

    有两个相关的优化:EliminateAllocations 和 EliminateAutoBox。尽管它们都由 Escape Analysis 提供并且看起来相似,但它们应用在略有不同的上下文中,因此可能会发生一种优化有效而另一种无效的情况,反之亦然。

    当自动装箱消除成功时,例如,当 JIT 编译器发现匹配valueOfdoubleValue调用时,并且对象没有转义,优化器会完全消除这两个调用。

    顺便说一句,提到的白代码是无关紧要的。除了用于内部 HotSpot 测试目的之外,它不会被使用。

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

    目前的想法是让intdouble直列类型,与IntegerDouble其基准凸。作为迁移步骤,Integer并且Double将成为密封的抽象类,因此将无法通过构造函数实例化它们。

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


And*_*eas 6

简短的回答:一致性

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


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

这是一个称为面向未来的概念,这也是您在编码时应该争取的。