方法重載,為什么不能根據返回類型來區分?


詳見:四

一、方法重載簡述

任何程序設計語言都具備一項重要特性就是對名字的運用。當創建一個對象時,也就給此對象分配到的存儲空間取一個名字。

所謂方法,則是給某個動作取的名字。通過這個名字,你可以引用所有的對象和方法。名字起的好可以使系統更易於理解和修改。

在日常生活中,相同的詞可以表達多種不同的含義——它們被“重載”了。特別是含義之間的差別很小時,這種方式十分有用。比起“以洗襯衫的方式洗襯衫”、“以洗狗的方式洗狗”、“以洗車的方式洗車”,“洗洗襯衫”、“洗洗狗”、“洗洗車”顯得更加簡潔和方便。

   wash(Shirt shirt); wash(Dog dog); wash(Car car);

大多數程序設計語言(尤其是C)要求為每個方法都提供一個獨一無二的標識符。所以絕不能用名為print()的函數顯示一個整數之后,有用print()顯示浮點數。即不支持重載,每個函數都要有唯一的名稱。

Java和C++支持重載(例如:構造方法重載,通過不同的構造方法,用多種方式創建一個對象)。

 

二、區分重載方法

規則很簡單:每個重載方法都必須有一個獨一無二的參數類型列表

  1、參數個數

  2、參數類型

  3、參數順序(一般不用,容易造成維護困難)

 

三、涉及基本類型的重載

1、當實參類型小於形參類型,實際數據類型就會被提升。

  注意:char類型略有不同,如果無法找到恰好接受char參數的方法,就會把char直接提升至int型。

示例代碼:

 1 package com.mianshi.easy;  2 
 3 public class Overload {  4     
 5     void f1(char x){System.out.print("f1(char)"+"、");};  6     void f1(byte x){System.out.print("f1(byte)"+"、");};  7     void f1(int x){System.out.print("f1(int)"+"、");};  8     void f1(long x){System.out.print("f1(long)"+"、");};  9     void f1(float x){System.out.print("f1(float)"+"、");};  10     void f1(short x){System.out.print("f1(short)"+"、");};  11     void f1(double x){System.out.print("f1(double)"+"、");};  12     
 13     void f2(byte x){System.out.print("f2(byte)"+"、");};  14     void f2(int x){System.out.print("f2(int)"+"、");};  15     void f2(long x){System.out.print("f2(long)"+"、");};  16     void f2(float x){System.out.print("f2(float)"+"、");};  17     void f2(short x){System.out.print("f2(short)"+"、");};  18     void f2(double x){System.out.print("f2(double)"+"、");};  19     
 20     void f3(int x){System.out.print("f3(int)"+"、");};  21     void f3(long x){System.out.print("f3(long)"+"、");};  22     void f3(float x){System.out.print("f3(float)"+"、");};  23     void f3(short x){System.out.print("f3(short)"+"、");};  24     void f3(double x){System.out.print("f3(double)"+"、");};  25     
 26     void f4(int x){System.out.print("f4(int)"+"、");};  27     void f4(long x){System.out.print("f4(long)"+"、");};  28     void f4(float x){System.out.print("f4(float)"+"、");};  29     void f4(double x){System.out.print("f4(double)"+"、");};  30     
 31     void f5(long x){System.out.print("f5(long)"+"、");};  32     void f5(float x){System.out.print("f5(float)"+"、");};  33     void f5(double x){System.out.print("f5(double)"+"、");};  34     
 35     void f6(float x){System.out.print("f6(float)"+"、");};  36     void f6(double x){System.out.print("f6(double)"+"、");};  37     
 38     void f7(double x){System.out.print("f7(double)"+"、");};  39     
 40     void testConstVal(){  41         System.out.print("5:"+"      ");  42         f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5);  43  }  44     
 45     void testChar(){  46         char x = 'x';  47         System.out.print("char:"+"   ");  48  f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);  49  }  50     
 51     void testByte(){  52         byte x = 0;  53         System.out.print("byte:"+"   ");  54  f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);  55  }  56     
 57     void testShort(){  58         byte x = 0;  59         System.out.print("short:"+"  ");  60  f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);  61  }  62     
 63     void testInt(){  64         int x = 0;  65         System.out.print("int:"+"    ");  66  f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);  67  }  68     void testLong(){  69         long x = 0;  70         System.out.print("long:"+"   ");  71  f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);  72  }  73     
 74     void testFloat(){  75         float x = 0;  76         System.out.print("float:"+"  ");  77  f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);  78  }  79     
 80     void testDouble(){  81         double x = 0;  82         System.out.print("double:"+" ");  83  f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);  84  }  85     
 86     public static void main(String[] args) {  87         
 88         Overload o = new Overload();  89         
 90         //按順序一一解注釋下面代碼,觀察結果
 91  o.testChar();  92         /*o.testByte();  93  o.testConstVal();  94  o.testInt();  95  o.testShort();  96  o.testLong();  97  o.testFloat();  98  o.testDouble();*/
 99  } 100 }
View Code

結果:

char:   f1(char)、f2(int)、f3(int)、f4(int)、f5(long)、f6(float)、f7(double)、

當傳入參數為char類型時,f1中有接受char型參數的方法,直接調用,f2-f4中沒有接受char型參數的方法,將直接提升為int型,然后f5-f7中逐步提升。

注釋第一條,解注釋第二條:

結果:

byte:   f1(byte)、f2(byte)、f3(short)、f4(int)、f5(long)、f6(float)、f7(double)、

f1、f2中有接受byte型參數的方法,直接調用,f3-f7中沒有接受byte型參數的方法,將逐步提升。

注釋前兩條,解注釋第三條:

結果:

5:      f1(int)、f2(int)、f3(int)、f4(int)、f5(long)、f6(float)、f7(double)、

常量值 5 被當做int型值進行處理,所以如果某個重載方法接受int型參數,它就會被調用,f1-f4中接受int型數據,之后逐步提升。

注釋前三條,解注釋第四條:

結果:

int:    f1(int)、f2(int)、f3(int)、f4(int)、f5(long)、f6(float)、f7(double)、

同上。

注釋前四條,解注釋第五條:

結果:

short:  f1(short)、f2(short)、f3(short)、f4(int)、f5(long)、f6(float)、f7(double)、

注釋前五條,解注釋第六條:

結果:

long:   f1(long)、f2(long)、f3(long)、f4(long)、f5(long)、f6(float)、f7(double)、

注釋前六條,解注釋第七條:

結果:

float:  f1(float)、f2(float)、f3(float)、f4(float)、f5(float)、f6(float)、f7(double)、

注釋前七條,解注釋第八條:

結果:

double: f1(double)、f2(double)、f3(double)、f4(double)、f5(double)、f6(double)、f7(double)、

 

2、當實參類型大於形參類型,必須強制轉換。

 1 package com.mianshi.easy;  2 
 3 public class Overload {  4     
 5     void f1(char x){System.out.print("f1(char)"+"、");};  6     void f1(byte x){System.out.print("f1(byte)"+"、");};  7     void f1(short x){System.out.print("f1(short)"+"、");};  8     void f1(int x){System.out.print("f1(int)"+"、");};  9     void f1(long x){System.out.print("f1(long)"+"、");}; 10     void f1(float x){System.out.print("f1(float)"+"、");}; 11     void f1(double x){System.out.print("f1(double)"+"、");}; 12     
13     void f2(byte x){System.out.print("f2(byte)"+"、");}; 14     void f2(int x){System.out.print("f2(int)"+"、");}; 15     void f2(long x){System.out.print("f2(long)"+"、");}; 16     void f2(float x){System.out.print("f2(float)"+"、");}; 17     void f2(short x){System.out.print("f2(short)"+"、");}; 18     void f2(char x){System.out.print("f2(char)"+"、");}; 19     
20     void f3(int x){System.out.print("f3(int)"+"、");}; 21     void f3(long x){System.out.print("f3(long)"+"、");}; 22     void f3(byte x){System.out.print("f3(byte)"+"、");}; 23     void f3(short x){System.out.print("f3(short)"+"、");}; 24     void f3(char x){System.out.print("f3(char)"+"、");}; 25     
26     void f4(int x){System.out.print("f4(int)"+"、");}; 27     void f4(short x){System.out.print("f4(short)"+"、");}; 28     void f4(byte x){System.out.print("f4(byte)"+"、");}; 29     void f4(char x){System.out.print("f4(char)"+"、");}; 30     
31     void f5(short x){System.out.print("f5(short)"+"、");}; 32     void f5(byte x){System.out.print("f5(byte)"+"、");}; 33     void f5(char x){System.out.print("f5(char)"+"、");}; 34     
35     void f6(byte x){System.out.print("f6(byte)"+"、");}; 36     void f6(char x){System.out.print("f6(char)"+"、");}; 37     
38     void f7(char x){System.out.print("f7(char)"+"、");}; 39     
40     void testDouble(){ 41         double x = 0; 42         System.out.print("double:"+" "); 43         f1(x);f2((float)x);f3((long)x);f4((int)x);f5((short)x);f6((byte)x);f7((char)x); 44  } 45     
46     public static void main(String[] args) { 47         
48         Overload o = new Overload(); 49         
50  o.testDouble(); 51  } 52 }
View Code

結果:

double: f1(double)、f2(float)、f3(long)、f4(int)、f5(short)、f6(byte)、f7(char)、

通過這種轉換來執行窄化轉換,否則編譯器會出錯。

 

四、以返回值區分重載方法

  如下兩個方法:

    void f(){}

    int f(){ return 1;}

只要編譯器可以根據語境明確判斷出語義,比如在int x = f();中,那么的確可以據此區分重載方法。不過,有時你並不關心方法的返回值,你想要的是方法調用的其他效果(這常被稱為“為了副作用而調用”),這時你可能會調用方法而忽略其返回值,所以如果像下面的調用:

    fun();

此時Java如何才能判斷調用的是哪一個 f() 呢?別人如何理解這種代碼呢?所以,根據方法返回值來區分重載方法是行不通的。

 

以上參考《Java 編程思想》 

 

五、網上看到的兩個小例子,熟悉一下:(轉自:http://www.knowsky.com/369172.html)

 1 package com.mianshi.easy;  2 
 3 public class TestOverLoad  4 {  5     public static void main(String[] args)  6  {  7         Test test = new Test();  8         test.print(null);  9  } 10 } 11 
12 class Test 13 { 14     //定義一個方法print()
15     public void print(String some) 16  { 17         System.out.println("String version print"); 18  } 19     //重載print()方法
20     public void print(Object some) 21  { 22         System.out.println("Object version print"); 23  } 24 }
View Code

結果:

String version print

這個題目明顯是考察方法重載的,重載使得java的類可以有具有多個相同方法名的方法。編譯器可以通過方法的參數的類型和個數來區分他們。而返回值和異常是不能作為區別標志的。上面的程序輸出了String version print是遵循了方法重載中准確性的原則,null是作為一個很非凡的參數傳給了方法print(),因為你可以認為null是String,也可以認為null是Object。但是從層次上看Object處在更上層,String是從Object繼續過來的,調用print(String some)將更准確。

  假如在TestOverLoad類中再添加一個方法如下所示,這樣會如何呢?

 1 package com.mianshi.easy;  2 
 3 public class TestOverLoad  4 {  5     public static void main(String[] args)  6  {  7         Test test = new Test();  8         test.print(null);  9  } 10 } 11 
12 class Test 13 { 14     //定義一個方法print()
15     public void print(String some) 16  { 17         System.out.println("String version print"); 18  } 19     //重載print()方法
20     public void print(Object some) 21  { 22         System.out.println("Object version print"); 23  } 24     //重載print()方法
25     public void print(StringBuffer some) 26  { 27       System.out.println("StringBuffer version print"); 28  } 29 }
View Code

結果:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: The method print(String) is ambiguous for the type Test at com.mianshi.easy.TestOverLoad.main(TestOverLoad.java:8)

答案是不能通過編譯,為什么呢?

由於StringBuffer和String並沒有繼續上的關系,因此編譯器感覺StringBuffer和String作為參數的方法都很准確,它就不知道到時候會運行哪個方法了,因此會出現編譯錯誤,這是方法重載中唯一性的原則。假如我們把參數null修改為"hello world",那么就可以通過編譯並運行輸出String version print了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM