Does autoboxing call valueOf()?

前端 未结 4 2095
北恋
北恋 2020-12-01 11:45

I\'m trying to determine whether the following statements are guaranteed to be true:

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


        
相关标签:
4条回答
  • 2020-12-01 12:22

    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 :

    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.

    Remember that there are multiples compilers for Java. To be "legal" they must follow the contract given in the 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.

    0 讨论(0)
  • 2020-12-01 12:33

    Until the language specification mentions it, it is not guaranteed that autoboxing is equivalent to a call to the static valueOf methods. 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.

    In practice, there are many Sun JDK bug reports (e.g. 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:

    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.

    But that's only for javac, not necessarily all compilers.

    0 讨论(0)
  • 2020-12-01 12:36

    Autoboxing is absolutely implemented using valueOf() ...in the 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.

    ((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). 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.

    Long, Short, Character and Byte incidentally implement this caching too, but unlike Integer, it's not tunable. Byte will always work if you're comparing autobox/valueOf() references since obviously, you can't go out of range. Float and Double will unsurprisingly always create a new instance.


    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. There are no guarantees for anything else.

    0 讨论(0)
  • 2020-12-01 12:36

    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. 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. Below is some code and the bytecode for it. The bytecode shows it is using 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. Will try it out.

    0 讨论(0)
提交回复
热议问题