Is this really widening vs autoboxing?

后端 未结 3 1080
醉梦人生
醉梦人生 2021-01-07 16:41

I saw this in an answer to another question, in reference to shortcomings of the Java spec:

There are more shortcomings and this is a subtle topic. Check

相关标签:
3条回答
  • 2021-01-07 17:10

    Yes it is, try it out in a test. You will see "long" printed. It is widening because Java will choose to widen the int into a long before it chooses to autobox it to an Integer, so the hello(long) method is chosen to be called.

    Edit: the original post being referenced.

    Further Edit: The reason the second option would print Integer is because there is no "widening" into a larger primitive as an option, so it MUST box it up, thus Integer is the only option. Furthermore, java will only autobox to the original type, so it would give a compiler error if you leave the hello(Long) and removed hello(Integer).

    0 讨论(0)
  • 2021-01-07 17:25

    In the first case, you have a widening conversion happening. This can be see when runinng the "javap" utility program (included w/ the JDK), on the compiled class:

    public static void main(java.lang.String[]);
      Code:
       0:   iconst_ 5
       1:   istore_ 1
       2:   iload_ 1
       3:   i2l
       4:   invokestatic    #6; //Method hello:(J)V
       7:   return
    
    }
    

    Clearly, you see the I2L, which is the mnemonic for the widening Integer-To-Long bytecode instruction. See reference here.

    And in the other case, replacing the "long x" with the object "Long x" signature, you'll have this code in the main method:

    public static void main(java.lang.String[]);
      Code:
       0:   iconst_ 5
       1:   istore_ 1
       2:   iload_ 1
       3:   invokestatic    #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       6:   invokestatic    #7; //Method hello:(Ljava/lang/Integer;)V
       9:   return
    
    }
    

    So you see the compiler has created the instruction Integer.valueOf(int), to box the primitive inside the wrapper.

    0 讨论(0)
  • 2021-01-07 17:29

    Another interesting thing with this example is the method overloading. The combination of type widening and method overloading only working because the compiler has to make a decision of which method to choose. Consider the following example:

    public static void hello(Collection x){
       System.out.println("Collection");
    }
    
    public static void hello(List x){
       System.out.println("List");
    }
    
    public static void main(String[] args){
       Collection col = new ArrayList();
       hello(col);
    }
    

    It doesn't use the run-time type which is List, it uses the compile-time type which is Collection and thus prints "Collection".

    I encourage your to read Effective Java, which opened my eyes to some corner cases of the JLS.

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