Java 方法重載是靜態(tài)綁定 --基礎(chǔ)而容易忽視的知識(shí)

今天有人遇到這樣的問題:在重構(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)目中測(cè)試一下, 測(cè)試結(jié)果ok! 但是將Util.jar放到運(yùn)行環(huán)境下, 就發(fā)生了NoSuchMethod 異常;
問題原因:方法參數(shù)的重載方法是靜態(tài)綁定的,在編譯時(shí)就確定了, 根據(jù)申明的Type去判斷選擇合適的方法,而不是實(shí)際的Object

下面舉個(gè)簡(jiǎn)單的例子;
設(shè)計(jì)一個(gè)簡(jiǎn)單的工具,判斷集合中是否元素存在;

public class Util { 
    public static boolean hasData(List<?> l) {
        if(l != null && l.size() > 0) {
            return true;
        }
        return false;
    }
}

在另一個(gè)類中調(diào)用測(cè)試;

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í), 如果我們?cè)诓恢匦戮幾gTest.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里測(cè)試一下)的情況下才有存在Override;這也是開發(fā)者容易犯的一個(gè)錯(cuò);
  • 在自動(dòng)化發(fā)布的過程中, 如果上層的Jar修改了, 下層的Jar即使不需要修改,也需要重新編譯。這里就是一個(gè)例子;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容