本文深入探討Java泛型在方法引用中的行為,特別是類型擦除如何影響方法調用,并提供有效的解決方案。
問題背景:
文中以mybatis-Plus為例,說明了redCar和YellowCar繼承自Car類,并分別擁有getStatus方法。泛型類BaseCarController的子類RedCarController和YellowCarController分別使用RedCar和YellowCar作為泛型類型參數。BaseCarController中的test方法試圖使用方法引用t::getStatus調用子類的getStatus方法,但實際運行時卻調用了Car類的getStatus方法,導致數據更新失敗。此外,文章還探討了如何動態獲取RedCar對象實例的getStatus方法引用。
立即學習“Java免費學習筆記(深入)”;
問題分析:
問題的核心在于Java泛型的類型擦除機制。編譯時,泛型類型信息會被擦除,t::getStatus在編譯后實際變為Car::getStatus。這是因為Java泛型只在編譯期存在,運行期類型信息丟失,虛擬機看到的只有原始類型Car。因此,BaseCarController中的t::getStatus無法根據運行時的實際類型(RedCar或YellowCar)進行動態綁定。
解決方案:
為了解決第一個問題(在BaseCarController中正確調用子類的getStatus方法),應使用實例方法引用代替靜態方法引用。修改后的BaseCarController的test方法需要接收一個t類型的實例作為參數:
public class BaseCarController<T extends Car> { @Autowired CommonService cs; public void test(T car, int id) { cs.toggle(id, car::getStatus); // 使用實例方法引用 } }
這樣,調用test方法時需傳入對應的RedCar或YellowCar實例,car::getStatus將正確引用實例對應的getStatus方法。
第二個問題(動態獲取RedCar對象的getStatus方法引用)的解決方法與第一個問題相同,直接使用實例方法引用:
RedCar redCar = new RedCar(); cs.toggle(id, redCar::getStatus); // 直接使用 redCar 對象的方法引用
這同樣利用實例方法引用避免了類型擦除問題,確保根據實際對象類型調用對應的getStatus方法。 CommonService.toggle方法需要能夠接受一個Supplier
通過使用實例方法引用,我們有效地規避了類型擦除的限制,實現了根據運行時實際對象類型調用相應getStatus方法的目標。