[英]Method overload resolution in java
這是我對java中重載解析的了解:
編譯器試圖從給定的重載方法定義中解析方法調用的過程稱為重載解析。 如果編譯器找不到精確匹配,它只使用向上轉換來尋找最接近的匹配(向下轉換永遠不會完成)。
這是一個類:
public class MyTest {
public static void main(String[] args) {
MyTest test = new MyTest();
Integer i = 9;
test.TestOverLoad(i);
}
void TestOverLoad(int a){
System.out.println(8);
}
void TestOverLoad(Object a){
System.out.println(10);
}
}
正如預期的那樣,輸出為 10。
但是,如果我稍微更改類定義並更改第二個重載方法。
public class MyTest {
public static void main(String[] args) {
MyTest test = new MyTest();
Integer i = 9;
test.TestOverLoad(i);
}
void TestOverLoad(int a){
System.out.println(8);
}
void TestOverLoad(String a){
System.out.println(10);
}
}
輸出為 8。
在這里我很困惑。 如果從不使用向下轉換,那么為什么要打印 8 呢? 為什么編譯器選擇將int
作為參數的TestOverLoad
方法,該參數是從Integer
向下轉換為int
的參數?
編譯器不會考慮向下轉換,而是考慮重載解析的拆箱轉換。 在這里, Integer
i
將成功拆箱為int
。 不考慮String
方法,因為Integer
不能擴展為String
。 唯一可能的重載是考慮拆箱的重載,因此打印8
。
第一個代碼的輸出是10
的原因是編譯器將考慮在拆箱轉換上擴大引用轉換( Integer
到Object
)。
JLS 的第 15.12.2 節在考慮適用哪些方法時指出:
- 第一階段(第 15.12.2.2 節)執行重載決議,不允許裝箱或拆箱轉換,或使用變量 arity 方法調用。 如果在此階段沒有找到適用的方法,則處理繼續到第二階段。
- 第二階段(第 15.12.2.3 節)執行重載解決方案,同時允許裝箱和拆箱 [...]
在 Java 中,在方法重載的情況下解析方法按以下優先級完成:
1. 加寬
2.自動裝箱
3. 可變參數
java 編譯器認為擴大原始參數比執行自動裝箱操作更可取。
換句話說,由於在 Java 5 中引入了自動裝箱,編譯器會在選擇較新的樣式(自動裝箱)之前選擇較舊的樣式(加寬),從而使現有代碼更加健壯。 var-args也是如此。
在您的第一個代碼片段中,發生了引用變量的擴展,即
Integer
到Object
而不是取消裝箱,即Integer
到int
。 在您的第二個片段中,從Integer
到String
的擴展不會發生,因此會發生拆箱。
考慮下面的程序,它證明了上述所有陳述:
class MethodOverloading {
static void go(Long x) {
System.out.print("Long ");
}
static void go(double x) {
System.out.print("double ");
}
static void go(Double x) {
System.out.print("Double ");
}
static void go(int x, int y) {
System.out.print("int,int ");
}
static void go(byte... x) {
System.out.print("byte... ");
}
static void go(Long x, Long y) {
System.out.print("Long,Long ");
}
static void go(long... x) {
System.out.print("long... ");
}
public static void main(String[] args) {
byte b = 5;
short s = 5;
long l = 5;
float f = 5.0f;
// widening beats autoboxing
go(b);
go(s);
go(l);
go(f);
// widening beats var-args
go(b, b);
// auto-boxing beats var-args
go(l, l);
}
}
輸出是:
double double double double int,int Long,Long
僅供參考,這是我關於 Java 中方法重載的博客。
PS:我的答案是 SCJP 中給出的示例的修改版本。
擴大節拍拳擊,拳擊節拍 var-args。 在您的示例中,不會發生擴大,因此對其應用的裝箱和 Integer 未裝箱。 沒有什么不尋常的。
實際上在第二個例子中沒有發生向下轉換。 發生了以下事情——
1.整數被解包/拆箱為原始類型int
。
2 、然后TestOverLoad(int a)
方法。
在 main 方法中,您聲明 Integer 像 -
Integer i = 9;
然后打電話——
test.TestOverLoad(i);
而您有 2 個重載版本的TestOverLoad()
-
TestOverLoad(int a);
TestOverLoad(String a);
這里TestOverLoad()
的第二個重載版本采用完全不同的參數String
。 這就是為什么Integer
i
被拆箱為原始類型int
,然后調用第一個重載版本。
Java 中的所有對象都擴展了 Object 類,包括 Integer 類。 這兩個類有如下關系: Integer "is a(n)" Object 因為 Integer extends Object。 在您的第一個示例中,使用了帶有 Object 參數的方法。
在第二個示例中,沒有找到接受整數的方法。 在這種情況下,Java 使用所謂的自動拆箱將 Integer 包裝器類解析為原始 int。 因此,使用帶有 int 參數的方法。
雖然@rgettman 的接受答案導致了非常正確的來源,但更准確地說, JLS 第 15.12.2 節的 §15.12.2.2 和 §15.12.2.3討論了適用性,而不是解決方案- OP 所要求的。 在示例中,OP 提供的兩個testOverLoad
方法都適用,.ie 將在沒有另一個方法的情況下成功解析。 相反, 15.12.2.5。 選擇最具體的方法討論了適用方法的分辨率。 上面寫着:
一個適用的方法 m1 比另一種適用的方法 m2 更具體,用於使用參數表達式 e1、...、ek 的調用,如果以下任何一項為真:...
m1 和 m2 可通過嚴格或松散調用來應用,並且 m1 具有形參類型 S1、...、Sn 和 m2 具有形參類型 T1、...、Tn,對於自變量 ei,類型 Si 比 Ti 更具體對於所有 i (1 ≤ i ≤ n, n = k)。
因此,在 OP 提供的第一個示例中,對於Integer
類型的參數i
方法testOverLoad(Object a)
比testOverLoad(int a)
更具體。
這是由於加寬和收窄類型鑄造而發生的
加寬意味着小字體可以容納在大字體中,而不會丟失任何信息。 擴大類型轉換是自動的。 這意味着字節值可以自動轉換為 short、int、long 或 double。
byte->short->int->float->double 從左到右變寬。
希望這能回答你的問題!
您可以再查看一個示例:
公共類 HelloWorld {
void show(String c){
System.out.println("int double overloaded method");
}
void show(Object c){
System.out.println("double int overloaded method");
}
}
在這里你會得到:double int 重載方法
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.