在 JVM 中,一個 Java 方法,最多能定義多少引數呢?這是一個很無聊的問題,即使能定義一萬個,十萬個,誰又會真的去這么做呢,
但是作為一個 coder,最重要的不就是好奇心嗎,沒有好奇心,和一條咸魚又有什么區別呢?本文作者就是這樣一位充滿好奇心的 coder,

我最近給我的 QuickTheories 分支添加了一個介面:
@FunctionalInterface
public interface QuadFunction<A, B, C, D, E> {
E apply(A a, B b, C c, D d);
}
讓我好奇的是這個方法能有多少個型別引數,到目前為止,我敢說,Java 語言規范并沒有談及這個問題,
對于實作定義的限制可能是什么,我有兩個猜測:
-
編譯器會設定一個可預測的限制,如 255 或 65535,
-
編譯器的緊急行為會由于實作細節(堆疊溢位或同樣不可預測/不相關的東西)而設定意外的限制,
我不想在源代碼上測驗我那點可憐的 C++技巧,所以我決定只測驗編譯器做了什么,我寫了一個 Python 腳本,它使用二進制搜索找到最少的致錯型別引數,完整的腳本放在 Github repo (https://github.com/hyperpape/java-max-type-params) 中,
腳本地址:https://github.com/hyperpape/java-max-type-params
生成方法很簡單,幸運的是,我們不必使用任何型別引數,只需以<a,b,c…>的形式發出它們:
def write_type_plain(count):
with open('Test.java', 'w') as f:
f.write("public class Test {\n")
f.write("public <")
for i in range(count):
if (i > 0):
f.write(", ")
f.write("A" + str(i + 1))
f.write("> void testMethod() {}")
f.write("}")
運行二進制搜索可以得到以下輸出:
>>> error: UTF8 representation for string "<A1:Ljava/lang/Objec..." is too long for the constant pool
>>> largest type: 2776
這個錯誤有點模糊,但事后看來是可以預見的,編譯器生成的類檔案包含許多字串,包括類中每個方法的方法簽名,這些字串存盤在常量池中,常量池中的條目最大為 65535 位元組,這是由 JVM 規范規定的限制,
所以,我之前的猜測都不完全正確,型別引數的最大數目是一個突現特征(emergent property),而不是一個明確的決定,不過,并不是編譯器本身的實作導致了錯誤,
相反,JVM 的類檔案格式限制了可以在類檔案中表示的型別引數的數量,這是真的,盡管 JVM對泛型一無所知,這也意味著型別引數的最大數目完全取決于如何撰寫方法,
我嘗試了一種新的編碼型別引數的方法(先前鏈接檔案中的 write_Type_Compact),使用完整的合法 ASCII 字符(A-Z、a-z、$和_),該實作有點過于復雜,因為可以使用字符 0~9,但不能是識別符號的初始字符,因為 Java 關鍵字不能作為型別引數出現,我只是用等長的 UTF-8 字符替換了短單詞「if」和「do」,更緊湊的編碼將引數數量從 2776 增加到 3123,
不方便的是,A 是一種合法的 Java 識別符號,但 _ 不是,謝天謝地,我的編碼在不使用初始_情況下就生成了 3392 個 2 位元組型別引數,因此我覺得沒有必要進行簿記以發出初始字符,
再來一個小技巧
解壓類檔案顯示,65536 個字符的大部分不是我生成的型別引數,而是子字串 Ljava/lang/object 的重復實體,因為沒有提供關于型別引數的資訊,所以類檔案顯示它們擴展了物件,并在方法簽名中對其進行編碼,我修改了生成器來解決這個問題,
回圈的關鍵部分是:
s = type_var(i)
f.write(s)
if (s != 'A'):
f.write(" extends A")
在型別引數中,除了一個實體 java/Lang/Object 之外的所有實體都被替換為 A,在進行了這個更改之后,編譯了一個具有 9851 個型別引數的方法,
由于引數的數量增加了很多,所以我使用的代碼肯定需要調整,使用非 ASCII Unicode 識別符號可能是完全高效的必要條件,但簡單地指出這是可以做到的我就很滿意了,
這些都不重要
很難想象有人會達到這個極限,代碼生成有時會達到語言或編譯器的限制,但即使生成的代碼似乎也不太可能使用成百上千的型別引數,
盡管如此,如果我是規則制定者,我會考慮明確禁止任何類或方法具有 255 個以上的型別引數,明確的限制似乎更好,即使它只影響百萬分之一的程式,
著作權申明:本文經機器之心(微信公眾號:almosthuman2014)授權轉載,禁止二次轉載
原文鏈接:http://justinblank.com/experiments/howmanytypeparameterscanajavamethodhave.html
機器之心編譯,參與:李志偉、張倩
關注公眾號Java技術堆疊回復"面試"獲取我整理的2020最全面試題及答案,
推薦去我的博客閱讀更多:
1.Java JVM、集合、多執行緒、新特性系列教程
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
4.Java、后端、架構、阿里巴巴等大廠最新面試題
覺得不錯,別忘了點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/144241.html
標籤:Java
