這是關于 Java 中使用參數化類型的簽名方法的另一個問題。假設您有以下兩種方法: static void f(List<Integer> l) {}
static void f(List<String> l) {}編譯器會抱怨兩種方法在類型擦除后具有相同的簽名(兩種參數類型都被擦除為僅List)。stackoverflow 上的許多類似問題都詢問為什么會這樣,但問題始終是關于實例(非靜態)方法(例如,請參閱方法與類型中的另一個方法具有相同的擦除)。通常一半的答案基于以下(非常錯誤的)論點:編譯器將刪除字節碼中的所有類型參數并使方法無法區分。好吧,只需打印字節碼javap,您就會看到是否所有內容都被刪除了?。m然字節碼丟失了大量參數化數據,但實際上保留了完整的方法簽名,當您想要使用包含泛型類和方法的依賴項編譯新類時,這絕對有用)。另一方面,最好的答案通常引用 JLS 8.4.2 并解釋說,為了與舊的、預通用的 Java 版本(以及較新版本中的原始類型)兼容,禁止使用具有覆蓋等效簽名的方法。我同意后一個論點,但它只意味著實例方法(非靜態),因為靜態方法無論如何都不能被覆蓋。靜態方法可能有類似的解釋,但我未能指出它。有人可以幫助我理解這一點嗎?
1 回答

MYYA
TA貢獻1868條經驗 獲得超4個贊
關于向后兼容性的爭論仍然成立。
如果您有這段代碼(不使用泛型,強烈建議不要使用,但即使在今天也是合法的,并且在應該仍然可以編譯的 Java 1.4 代碼中完全正常),編譯器應該選擇您的兩種方法中的哪一種?
List rawList = new ArrayList(); YourClass.f(rawList);
更重要的是,假設您以某種方式選擇兩者之一,在生成的調用站點字節碼中,泛型仍然會被刪除,因此在運行時,JVM 不知道您指的是兩者中的哪一個f(List)
。方法調用指定方法名稱和簽名,但該簽名不包括泛型。這并不是出于兼容性問題。他們是否可以嘗試使用帶有擴展調用規范的新操作碼之類的東西來更努力地推動這一點?或許。但現在就是這樣。
另一方面,最好的答案通常引用 JLS 8.4.2 并解釋說,為了與舊的、預通用的 Java 版本(以及較新版本中的原始類型)兼容,禁止使用具有覆蓋等效簽名的方法。
我同意后一個論點,但它只意味著實例方法(非靜態),因為靜態方法無論如何都不能被覆蓋。
好吧,您不能覆蓋靜態方法,但是您的兩個方法仍然是“覆蓋等效的”,這意味著它們的簽名非常接近,以至于您一次只能擁有其中一個(在子類情況下,一個如果因此而繼承,則會覆蓋另一個方法 --- 但這也意味著您不能在同一個類上擁有兩個這樣的方法)。
請注意,這不會造成任何實際問題,因為您始終可以通過更改為不同的方法名稱來避免“重載”。
添加回答
舉報
0/150
提交
取消