Overloading with Widening、Boxing and Var-args


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


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 to int. char can not be promotedbyte and short whenever it is, it can be promotedlong,float and double 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.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值