简体   繁体   English

autoboxing是否调用valueOf()?

[英]Does autoboxing call valueOf()?

I'm trying to determine whether the following statements are guaranteed to be true: 我正在尝试确定以下语句是否保证是真的:

((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
((Integer)1) == Integer.valueOf(1)

I've always assumed that autoboxing was equivalent to calling valueOf() on the corresponding type. 我一直认为autoboxing相当于在相应的类型上调用valueOf() Every discussion that I've seen on the topic seems to support my assumption. 我在这个主题上看到的每一个讨论似乎都支持我的假设。 But all I could find in the JLS was the following ( §5.1.7 ): 但我在JLS中找到的只有以下内容( §5.1.7 ):

If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between '\' and '\' inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p . 如果值p被装箱是文本类型的整数int之间-128127包容(§3.10.1)或布尔值truefalse (§3.10.3),或一个之间文字字符'\''\'包含(§3.10.4),然后让ab成为p的任意两次拳击转换的结果。 It is always the case that a == b . a == b总是如此。

That describes behavior identical similar* to that of valueOf() . 这描述了 valueOf()相似的行为*。 But there doesn't seem to be any guarantee that valueOf() is actually invoked, meaning there could theoretically be an implementation that keeps a separate, dedicated cache for autoboxed values. 但似乎没有任何保证valueOf()实际上被调用,这意味着理论上可以有一个实现为自动装箱值保留一个单独的专用缓存。 In such a case, there might not be identity equality between cached autoboxed values and regular cached boxed values. 在这种情况下,缓存的自动装箱值与常规缓存的装箱值之间可能不存在标识相同性。

Oracle's autoboxing tutorial states matter-of-factly that li.add(i) is compiled to li.add(Integer.valueOf(i)) , where i is an int . Oracle的自动装箱教程事实上说明了li.add(i)被编译为li.add(Integer.valueOf(i)) ,其中i是一个int But I don't know whether the tutorial should be considered an authoritative source. 但我不知道该教程是否应被视为权威来源。


*It's a slightly weaker guarantee than valueOf() , as it only refers to literal values. *它比valueOf()稍微弱一些,因为它只引用文字值。

I first tought your question was a dupe of What code does the compiler generate for autoboxing? 我首先提出你的问题是编译器为自动装箱生成了什么代码?

However, after your comment on @ElliottFrisch I realized it was different : 但是,在您对@ElliottFrisch发表评论后,我发现它有所不同:

I know the compiler behaves that way. 我知道编译器的行为方式。 I'm trying to figure out whether that behavior is guaranteed. 我想弄清楚这种行为是否得到保证。

For other readers, assume that "behaves that way" means using valueOf . 对于其他读者,假设“行为方式”意味着使用valueOf

Remember that there are multiples compilers for Java. 请记住,Java有多个编译器。 To be "legal" they must follow the contract given in the JLS . 为了“合法”,他们必须遵守JLS中给出的合同。 Therefore, as long as all the rules here are respected, there is no guarantee of how autoboxing is internally implemented. 因此,只要遵守此处的所有规则,就无法保证内部如何实施自动装箱。

But I don't see any reason to not use valueOf , specially that it uses the cached values and is the recommended way as per this article by Joseph D. Darcy. 但我没有看到任何理由不使用valueOf ,特别是它使用缓存值,并且是Joseph D. Darcy在本文中推荐的方法。

Until the language specification mentions it, it is not guaranteed that autoboxing is equivalent to a call to the static valueOf methods. 在语言规范提到它之前,不能保证自动装箱等同于对静态valueOf方法的调用。 It is an implementation aspect, not part of the boxing conversion specification. 它是一个实现方面,不是装箱转换规范的一部分。 An implementation is theoretically free to use another mechanism as long as it conforms to the rule you mentioned from the JLS. 理论上,只要符合您在JLS中提到的规则,实现就可以自由使用其他机制。

In practice, there are many Sun JDK bug reports (eg JDK-4990346 and JDK-6628737 ) that clearly imply that when autoboxing was introduced in Java 5, the intention was having the compiler to rely on valueOf as stated in JDK-6628737 : 在实践中,有许多Sun JDK错误报告(例如JDK-4990346JDK-6628737 )明确暗示当在Java 5中引入自动装箱时,目的是让编译器依赖于JDK-6628737中所述的valueOf

The static factory methods Integer.valueOf(int), Long.valueOf(long), etc. were introduced in JDK 5 for javac to implement the caching behavior required by the autoboxing specification. JDK 5中为javac引入了静态工厂方法Integer.valueOf(int),Long.valueOf(long)等,以实现自动装箱规范所需的缓存行为。

But that's only for javac, not necessarily all compilers. 但这只适用于javac,不一定是所有编译器。

Autoboxing is absolutely implemented using valueOf() ...in the OpenJDK. 自动装箱绝对执行valueOf() ...在OpenJDK的。 If that's your implementation, read on... if not, skip to below. 如果这是您的实施,请继续阅读......如果没有,请跳至下方。

((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)

Java documentation states that Boolean.valueOf() always returns Boolean.TRUE or Boolean.FALSE , therefore your reference comparisons in these cases will succeed. Java文档声明Boolean.valueOf()始终返回Boolean.TRUEBoolean.FALSE ,因此在这些情况下您的引用比较将成功。

((Integer)1) == Integer.valueOf(1)

For this particular example, under the OpenJDK implementation with default settings, it will probably work by virtue of the fact that you picked a value < 128 which is cached at startup (although this can be overridden as a commandline arg). 对于这个特定的例子,在具有默认设置的OpenJDK实现下,它可能会因为您选择了一个在启动时缓存的值<128这一事实而工作(虽然这可以作为命令行arg重写)。 It may also work for larger values if it's frequently used enough to be cached. 它也用于较大的值工作,如果是经常使用的,足以被缓存。 Unless you're working under "safe" assumptions about the Integer cache, don't expect the reference comparison to be an equality. 除非您在关于Integer缓存的“安全”假设下工作,否则不要期望引用比较是相等的。

Long , Short , Character and Byte incidentally implement this caching too, but unlike Integer , it's not tunable. LongShortCharacterByte偶然实现了这个缓存,但与Integer不同,它不可调。 Byte will always work if you're comparing autobox/ valueOf() references since obviously, you can't go out of range. 如果你比较autobox / valueOf()引用, Byte将始终有效,因为很明显,你不能超出范围。 Float and Double will unsurprisingly always create a new instance. FloatDouble毫不奇怪总是会创建一个新实例。


Now, in purely generic terms? 现在,用纯粹的通用术语? See this section of the JLS - you MUST be given equal references for boolean and any int or char within the -128 to 127 range. 请参阅JLS的这一部分 - 您必须在-128到127范围内为boolean和任何intchar提供相同的引用。 There are no guarantees for anything else. 其他任何事情都无法保证

Oracle's autoboxing tutorial states matter-of-factly that li.add(i) is compiled to li.add(Integer.valueOf(i)), where i is an int. Oracle的自动装箱教程事实上说明了li.add(i)被编译为li.add(Integer.valueOf(i)),其中i是一个int。 But I don't know whether the tutorial should be considered an authoritative source. 但我不知道该教程是否应被视为权威来源。

I'm running Oracle Java 1.7.0_72 it looks like it does use valueOf. 我正在运行Oracle Java 1.7.0_72,看起来它确实使用了valueOf。 Below is some code and the bytecode for it. 下面是一些代码和它的字节码。 The bytecode shows it is using valueOf. 字节码显示它正在使用valueOf。

public class AutoBoxing {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Integer x = 5;
        int i = x;
        System.out.println(x.toString());
    }

}





Compiled from "AutoBoxing.java"
public class testing.AutoBoxing {
  public testing.AutoBoxing();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_5
       1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       4: astore_1
       5: aload_1
       6: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
       9: istore_2
      10: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      13: aload_1
      14: invokevirtual #5                  // Method java/lang/Integer.toString:()Ljava/lang/String;
      17: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: return

But I do not know what Open JDK uses. 但我不知道Open JDK使用的是什么。 Will try it out. 会尝试一下。

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

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