Java中可變參數(shù)與數(shù)組混用導(dǎo)致方法調(diào)用異常的解決方案
引言
在Java開發(fā)中,可變參數(shù)(Varargs)是個非常實用的語法糖,能讓我們輕松處理數(shù)量不固定的方法參數(shù)。但如果不小心和數(shù)組混用,很容易就會觸發(fā)讓人摸不著頭腦的方法調(diào)用異常。本文就結(jié)合實際場景,拆解這個隱形坑的來龍去脈,幫你徹底避開它。
問題現(xiàn)場:看似正常的代碼為何報錯?
先來看一段看似普通的代碼:
public class VarargsDemo {
public static void print(String... args) {
System.out.println("可變參數(shù)方法被調(diào)用");
for (String arg : args) {
System.out.println(arg);
}
}
public static void print(String[] args) {
System.out.println("數(shù)組參數(shù)方法被調(diào)用");
for (String arg : args) {
System.out.println(arg);
}
}
public static void main(String[] args) {
String[] strArray = {"Java", "Python", "Go"};
print(strArray); // 這里會調(diào)用哪個方法?
}
}這段代碼定義了兩個同名方法,一個接收可變參數(shù),一個接收數(shù)組參數(shù)。在main方法中,我們傳入一個String數(shù)組調(diào)用print方法,你覺得會觸發(fā)哪個方法?
運(yùn)行后你會發(fā)現(xiàn),程序調(diào)用了print(String[] args)方法。但如果我們稍微修改一下調(diào)用方式:
print("Java", "Python", "Go");這時程序會調(diào)用print(String... args)方法,這符合我們對可變參數(shù)的預(yù)期。
但如果我們把代碼改成這樣:
public class VarargsDemo2 {
public static void print(Object... args) {
System.out.println("可變參數(shù)方法被調(diào)用");
for (Object arg : args) {
System.out.println(arg);
}
}
public static void print(String[] args) {
System.out.println("數(shù)組參數(shù)方法被調(diào)用");
for (String arg : args) {
System.out.println(arg);
}
}
public static void main(String[] args) {
String[] strArray = {"Java", "Python", "Go"};
print(strArray); // 這里會發(fā)生什么?
}
}運(yùn)行這段代碼,你會發(fā)現(xiàn)程序報錯了:
Error: reference to print is ambiguous both method print(Object...) in VarargsDemo2 and method print(String[]) in VarargsDemo2 match
明明是同樣的調(diào)用方式,只是把可變參數(shù)的類型從String改成了Object,為什么就出現(xiàn)方法引用模糊的異常了?
底層邏輯:可變參數(shù)的本質(zhì)與方法匹配規(guī)則
要搞懂這個問題,我們得先從可變參數(shù)的底層實現(xiàn)說起。
Java的可變參數(shù)String... args其實是語法糖,編譯后會被轉(zhuǎn)換成String[] args。但在方法重載的匹配規(guī)則中,它和真正的數(shù)組參數(shù)方法有著不同的優(yōu)先級:
- 精確匹配優(yōu)先:當(dāng)傳入的參數(shù)類型和某個方法的參數(shù)類型完全一致時,JVM會優(yōu)先選擇這個方法。
- 可變參數(shù)匹配次之:如果沒有精確匹配的方法,JVM才會考慮將參數(shù)打包成數(shù)組,匹配可變參數(shù)方法。
在第一個例子中,String[]類型的參數(shù)和print(String[] args)方法精確匹配,所以JVM直接選擇了這個方法。
而在第二個例子中,String[]既是String[]類型,同時也可以被向上轉(zhuǎn)型為Object類型,作為可變參數(shù)Object... args的第一個元素(因為數(shù)組本身也是Object的子類)。這時JVM就無法判斷我們到底想調(diào)用哪個方法,于是拋出了方法引用模糊的異常。
解決方案:三招徹底避開這個坑
1. 避免重載:使用不同方法名
最直接的解決方案就是給兩個方法起不同的名字,從根源上避免方法重載帶來的歧義:
public class VarargsDemo3 {
public static void printWithVarargs(Object... args) {
System.out.println("可變參數(shù)方法被調(diào)用");
for (Object arg : args) {
System.out.println(arg);
}
}
public static void printWithArray(String[] args) {
System.out.println("數(shù)組參數(shù)方法被調(diào)用");
for (String arg : args) {
System.out.println(arg);
}
}
public static void main(String[] args) {
String[] strArray = {"Java", "Python", "Go"};
printWithArray(strArray); // 明確調(diào)用數(shù)組參數(shù)方法
printWithVarargs(strArray); // 明確調(diào)用可變參數(shù)方法
}
}2. 顯式轉(zhuǎn)換:明確指定參數(shù)類型
如果必須使用重載,我們可以通過顯式類型轉(zhuǎn)換來明確告訴JVM要調(diào)用哪個方法:
public class VarargsDemo4 {
public static void print(Object... args) {
System.out.println("可變參數(shù)方法被調(diào)用");
for (Object arg : args) {
System.out.println(arg);
}
}
public static void print(String[] args) {
System.out.println("數(shù)組參數(shù)方法被調(diào)用");
for (String arg : args) {
System.out.println(arg);
}
}
public static void main(String[] args) {
String[] strArray = {"Java", "Python", "Go"};
print((String[]) strArray); // 明確調(diào)用數(shù)組參數(shù)方法
print((Object) strArray); // 明確調(diào)用可變參數(shù)方法
}
}3. 借助包裝類:統(tǒng)一參數(shù)類型
我們還可以把數(shù)組包裝在一個容器類中,讓參數(shù)類型變得唯一:
public class ArrayWrapper {
private final String[] array;
public ArrayWrapper(String[] array) {
this.array = array;
}
public String[] getArray() {
return array;
}
}
public class VarargsDemo5 {
public static void print(Object... args) {
System.out.println("可變參數(shù)方法被調(diào)用");
for (Object arg : args) {
System.out.println(arg);
}
}
public static void print(ArrayWrapper wrapper) {
System.out.println("包裝類參數(shù)方法被調(diào)用");
for (String arg : wrapper.getArray()) {
System.out.println(arg);
}
}
public static void main(String[] args) {
String[] strArray = {"Java", "Python", "Go"};
print(new ArrayWrapper(strArray)); // 明確調(diào)用包裝類參數(shù)方法
print(strArray); // 調(diào)用可變參數(shù)方法
}
}避坑總結(jié)
- 牢記匹配優(yōu)先級:精確匹配 > 可變參數(shù)匹配,當(dāng)數(shù)組類型可以被向上轉(zhuǎn)型為可變參數(shù)的元素類型時,就可能引發(fā)歧義。
- 謹(jǐn)慎使用重載:在包含可變參數(shù)的方法中,盡量避免使用同名的數(shù)組參數(shù)方法。
- 顯式優(yōu)于隱式:如果必須使用重載,通過顯式類型轉(zhuǎn)換或包裝類明確指定調(diào)用的方法。
可變參數(shù)雖然方便,但在和數(shù)組混用時暗藏玄機(jī)。希望通過本文的解析,你能徹底搞懂這個問題的底層邏輯,在今后的開發(fā)中輕松避開這個隱形坑。
以上就是Java中可變參數(shù)與數(shù)組混用導(dǎo)致方法調(diào)用異常的解決方案的詳細(xì)內(nèi)容,更多關(guān)于Java可變參數(shù)與數(shù)組混用方法調(diào)用異常的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring?Boot日志SLF4J和Logback示例詳解
這篇文章主要介紹了Spring?Boot日志SLF4J和Logback詳解,Logback相比于Log4j,性能提高了10倍以上的性能,占用的內(nèi)存也變小了,并且文檔十分詳細(xì),推薦使用Slf4j+Logback,需要的朋友可以參考下2023-07-07
使用Java?Socket實現(xiàn)GPS定位數(shù)據(jù)處理
在許多應(yīng)用場景中,如車輛追蹤、移動設(shè)備定位等,GPS定位數(shù)據(jù)的實時獲取和處理至關(guān)重要,本文將介紹如何使用Java?Socket編程來接收GPS設(shè)備發(fā)送的數(shù)據(jù)并進(jìn)行處理,需要的朋友可以參考下2024-07-07
java對象數(shù)組實現(xiàn)學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java對象數(shù)組實現(xiàn)學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-06-06
java獲取登錄者IP和登錄時間的兩種實現(xiàn)代碼詳解
這篇文章主要介紹了java獲取登錄者IP和登錄時間的實現(xiàn)代碼,本文通過兩種結(jié)合實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07

