Overloading with Widening、Boxing and Var-args

来源:互联网 发布:angular js 跨域访问 编辑:程序博客网 时间:2024/05/21 21:41


区别不同函数的唯一标志是参数列表,重载的函数,它们的函数名相同,返回类型可以相同也可以不同,但它们的参数列表一定不能相同。与继承中的方法重写不同,重写的方法要求函数名和参数列表一定相同。


There are three factors that make overloading a little tricky:

(1) Widening

(2) Boxing

(3) Var-args


1. 自动提升时的规则

class EasyOver {    static void go(short x) { System.out.print("short "); }    static void go(int x) { System.out.print("int "); }    static void go(long x) { System.out.print("long "); }    static void go(double x) { System.out.print("double "); }        public static void main(String [] args) {        char c = 'a';        byte b = 5;                                                                                    short s = 5;        long l = 5;        float f = 5.0f;        go(c);         //go(int)        go(b);         //go(short)        go(s);         //go(short)        go(l);         //go(long)        go(f);         //go(double)    }}

Which produces the output:



This probably isn't much of a surprise. 

In every case, when an exact match isn't found, the JVM uses the method with the smallest argument that is wider than the parameter.

char produces a slightly different effect, since if it do not find an exactchar match,it is promoted toint. char can not be promotedbyte andshort whenever it is, it can be promotedlong,float anddouble if int does not exist.


2. Overloading with Boxing and Var-args

(1) overloading with boxing

class AddBoxing {    static void go(Integer x) { System.out.println("Integer"); }    static void go(long x) { System.out.println("long"); }        public static void main(String [] args) {        int i = 5;        go(i); // which go() will be invoked?     }} 

Does the compiler think that widening a primitive parameter is more desirable than performing an autoboxing operation? The answer is that the compiler willchoose widening over boxing, so the output will be:
     


(2) overloading with var-args

class AddVarargs {    static void go(long x, long y) { System.out.println("long,long");}    static void go(byte... x) { System.out.println("byte... "); }               public static void main(String[] args) {        byte b = 5;        go(b,b);      // which go() will be invoked?    }}

The output is:



So far, we have seen that

(*) Wideningbeats boxing

(**) Widening beats var-args


At this point, inquiring minds want to know, does boxing beat var-args?

(3) Box or Var-args

class BoxOrVararg {    static void go(Byte x, Byte y) { System.out.println("Byte, Byte"); }    static void go(byte... x) { System.out.println("byte... "); }                                              public static void main(String [] args) {        byte b = 5;        go(b,b);         // which go() will be invoked?    }}

As it turns out, the output is



So we have seen another rule:

(*) boxing beats var-args

And var-args is the last choice to select.


3. Overloading When Combining Widening and Boxing

In this case the compiler will have to widen and then autobox the parameter for a match to be made:

class WidenAndBox {    static void go(Long x) { System.out.println("Long"); }    public static void main(String [] args) {        byte b = 5;        go(b);      //widen then box, it is illegal                                                }}

This is just too much for the compiler:



Widen then box, it is illegal.

Strangely enough, it IS possible for the compiler to perform a boxing operation followed by a widening operation in order to match an invocation to a method.

class BoxAndWiden {    static void go(Object o) {        Byte b2 = (Byte) o;     // ok - it's a Byte object        System.out.println(b2);    }    public static void main(String [] args) {        byte b = 5;        go(b);                 // can this byte turn into an Object ?                              }}

This compiles (!), and produces the output:



It should box then widen.

Wow! Here's what happened under the covers when the compiler, then the JVM, got to the line that invokes the go() method:
1) The byte b was boxed to a Byte.
2) The Byte reference was widened to an Object (since Byte extends Object).
3) The go() method got an Object reference that actually refers to a Byte object.
4) The go() method cast the Object reference back to a Byte reference (remember, there was never an object of type Object in this scenario, only anobject of type Byte!).
5) The go() method printed the Byte's value.


4. Overloading in Combination with Var-args

What happens when we attempt to combine var-args with either widening or boxing in a method-matching scenario? Let's take a look:

class Vararg {    static void wide_vararg(long... x) { System.out.println("long..."); }    static void box_vararg(Integer... x) { System.out.println("Integer..."); }                                                                                         public static void main(String [] args) {        int i = 5;        wide_vararg(i,i);      // needs to widen and use var-args        box_vararg(i,i);       // needs to box and use var-args    }}

This compiles and produces:



As we can see, you can successfully combine var-args with either widening or boxing. 

So the following codes wil be failed.

class Ambiguous {    static void vararg(long... x) { System.out.println("long..."); }    static void vararg(Integer... x) { System.out.println("Integer..."); }    public static void main(String [] args) {        int i = 5;        vararg(i,i);      // widen first or box first and before using var-arg? Both yes!    }                                                                                          }

This is just too much for the compiler:



Another example:

public class Ambiguous2 {    public static void test(float a, Character... c) {        System.out.println("float, Character...");    }    public static void test(Character... c) {        System.out.println("Character...");    }    public static void main(String[] args) {        test('a', 'b'); // widen first or box first before using var-arg ?    }}

This is also too much for the compiler:



5. review of the rules for overloading methods using widening, boxing, and var-args


(1) Primitive widening uses the "smallest" method argument possible.

(2) Used individually, boxing and var-args are compatible with overloading.

(3) You CANNOT widen from one wrapper type to another. (IS-A fails.)

(4) You can box and then widen. (An int can become an Object, via Integer.)

(4) You can combine var-args with either widening or boxing.



原创粉丝点击