天天看點

拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除

1 當反射遇見重載

重載level方法,入參分别是int和Integer。

拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除

若不使用反射,選用哪個重載方法很清晰,比如:

傳入666就走int參數重載

傳入Integer.valueOf(“666”)走Integer重載

那反射調用方法也是根據入參類型确定使用哪個重載方法嗎?

使用getDeclaredMethod擷取 grade方法,然後傳入Integer.valueOf(“36”)

拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除

結果是:

拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除

因為反射進行方法調用是通過

方法簽名

來确定方法。本例的

getDeclaredMethod

傳入的參數類型

Integer.TYPE

其實代表

int

拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除

是以不管傳包裝類型還是基本類型,最終都是調用int入參重載方法。

将Integer.TYPE改為Integer.class,則實際執行的參數類型就是Integer了。且無論傳包裝類型還是基本類型,最終都調用Integer入參重載方法。

綜上,反射調用方法,是以反射擷取方法時傳入的方法名和參數類型來确定調用的方法。

2 泛型的類型擦除

泛型允許SE使用類型參數替代精确類型,執行個體化時再指明具體類型。利于代碼複用,将一套代碼應用到多種資料類型。

泛型的類型檢測,可以在編譯時檢查很多泛型編碼錯誤。但由于曆史相容性而妥協的泛型類型擦除方案,在運作時還有很多坑。

案例

現在期望在類的字段内容變動時記錄日志,于是SE想到定義一個泛型父類,并在父類中定義一個統一的日志記錄方法,子類可繼承該方法。上線後總有日志重複記錄。

  • 父類
  • 拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除
  • 子類1
  • 拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除
  • 通過反射調用子類方法:
  • 拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除
  • 雖Base.value正确設定為了JavaEdge,但父類setValue調用了兩次,計數器顯示2
  • 拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除
  • 兩次調用Base.setValue,是因為getMethods找到了兩個

    setValue

  • 拼夕夕三輪面經:被問到反射的bug,你中招了嗎?(上)1 當反射遇見重載2 泛型的類型擦除

繼續閱讀