今天有人遇到這樣的問題:在重構(gòu)一個(gè)Util jar時(shí)匕积,發(fā)現(xiàn)有個(gè)靜態(tài)方法設(shè)計(jì)的還不夠抽象; 參數(shù)用更高層次的接口會(huì)比較好, 比如 A extend B泵三,那么使用B 來代替 A; 因?yàn)槭褂?Super Type 作為參數(shù),從而認(rèn)為此前調(diào)用該方法的地方也不需要重寫; 本地將重新構(gòu)建的Util jar放到本地eclipse項(xiàng)目中測試一下, 測試結(jié)果ok! 但是將Util.jar放到運(yùn)行環(huán)境下, 就發(fā)生了NoSuchMethod 異常;
問題原因:方法參數(shù)的重載方法是靜態(tài)綁定的,在編譯時(shí)就確定了畜普, 根據(jù)申明的Type去判斷選擇合適的方法,而不是實(shí)際的Object群叶;
下面舉個(gè)簡單的例子;
設(shè)計(jì)一個(gè)簡單的工具吃挑,判斷集合中是否元素存在;
public class Util {
public static boolean hasData(List<?> l) {
if(l != null && l.size() > 0) {
return true;
}
return false;
}
}
在另一個(gè)類中調(diào)用測試;
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
System.out.println(Util.hasData(list));
}
}
后來為了更廣泛的使用, 我們將List 修改Collection;
public class Util {
public static boolean hasData(Collection<?> l) {
if(l != null && l.size() > 0) {
return true;
}
return false;
}
}
此時(shí), 如果我們在不重新編譯Test.class的情況下, 運(yùn)行class文件就會(huì)拋錯(cuò)钝荡;
打印出字節(jié)碼就可以發(fā)現(xiàn)的問題所在; 第12行的調(diào)用參數(shù); 那么在運(yùn)行,系統(tǒng)拋出NoSuchMethod hasData:(Ljava/util/List;) 也就一點(diǎn)都不意外了;
public static void main(java.lang.String[]);
Code:
0: new #16 // class java/util/ArrayList
3: dup
4: invokespecial #18 // Method java/util/ArrayList."<init>":()V
7: astore_1
8: getstatic #19 // Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: invokestatic #25 // Method simpletest/Util.hasData:(Ljava/util/List;)Z
18: return
- 靜態(tài)綁定是喪失了動(dòng)態(tài)特性為代價(jià)可以提供更佳的性能(編譯時(shí)確定)舶衬;它與動(dòng)態(tài)綁定的區(qū)別埠通,一言以蔽之就是一個(gè)根據(jù)Type判斷,而另一個(gè)根據(jù)Object判斷逛犹;
- 除了上面的例子端辱,即方法的重載是靜態(tài)綁定以外;此外對(duì)Object上調(diào)用static method虽画, private method & final method 這些不能override的方法舞蔽,都是靜態(tài)綁定(invokestatic);
- 根據(jù)上面兩點(diǎn),只有Type 和 Sub Type的其他方法, 只有在方法參數(shù)完全一致(對(duì)于泛型而言狸捕,即使是類型擦除喷鸽,Java也要求泛型參數(shù)的類型必須一直才可以重載众雷,可以自己試著自己在IDE里測試一下)的情況下才有存在Override灸拍;這也是開發(fā)者容易犯的一個(gè)錯(cuò);
- 在自動(dòng)化發(fā)布的過程中, 如果上層的Jar修改了, 下層的Jar即使不需要修改砾省,也需要重新編譯鸡岗。這里就是一個(gè)例子;