日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
一個(gè)Java方法能使用多少個(gè)參數(shù)?

我最近給我fork的項(xiàng)目QuickTheories增加了一個(gè)接口:

站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到新?lián)峋W(wǎng)站設(shè)計(jì)與新?lián)峋W(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:成都做網(wǎng)站、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、申請(qǐng)域名、網(wǎng)絡(luò)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋新?lián)岬貐^(qū)。

 
 
 
  1. @FunctionalInterface 
  2. public interface QuadFunction { 
  3.     E apply(A a, B b, C c, D d); 

這讓非常好奇一個(gè)方法能夠有多少個(gè)類(lèi)型參數(shù)呢?據(jù)我所知,Java的語(yǔ)言規(guī)范并沒(méi)有提到這個(gè)問(wèn)題。1

關(guān)于在實(shí)現(xiàn)上這個(gè)閾值的定義,我有兩個(gè)猜測(cè):

編譯器會(huì)強(qiáng)制一個(gè)可預(yù)測(cè)的閾值,例如255或者65535。

由于實(shí)現(xiàn)細(xì)節(jié)的原因,編譯器的異常處理會(huì)施加意想不到的限制。

我不想通過(guò)我薄弱的C++技能來(lái)測(cè)試源代碼,所以我決定直接來(lái)測(cè)試編譯器2。我寫(xiě)了一個(gè)Python腳本,通過(guò)二分法找到一個(gè)會(huì)觸發(fā)錯(cuò)誤的最小值。完整的代碼請(qǐng)見(jiàn)連接Github Repo。

最直接的辦法就是生成方法。幸運(yùn)的是,我們不必使用任何已有的類(lèi)型參數(shù),只需要按照

 
 
 
  1. def write_type_plain(count): 
  2.     with open('Test.java', 'w') as f: 
  3.         f.write("public class Test {\n") 
  4.         f.write("public <") 
  5.         for i in range(count): 
  6.             if (i > 0): 
  7.                 f.write(", ") 
  8.             f.write("A" + str(i + 1)) 
  9.         f.write("> void testMethod() {}") 
  10.         f.write("}") 

運(yùn)行這個(gè)二分法的代碼會(huì)有如下輸出:

 
 
 
  1. >>> error: UTF8 representation for string "
  2. >>> largest type: 2776 

這個(gè)錯(cuò)誤讓人有點(diǎn)費(fèi)解,但是從事后來(lái)看還是可以理解的。編譯器生成的類(lèi)文件包含多個(gè)字符串,包括每個(gè)方法的方法簽名。這些字符串保存在常量池內(nèi),而常量池的內(nèi)容有最大65535字節(jié)數(shù)的限制,這個(gè)是JVM的所定義的。

所以,我之前的猜測(cè)都不是完全的正確。類(lèi)型參數(shù)的最大個(gè)數(shù)是一個(gè)意料之外的值,而不是一個(gè)確定值。但是,編譯器的實(shí)現(xiàn)本身并不是導(dǎo)致錯(cuò)誤的原因3。相反,是JVM類(lèi)文件的格式要求限制了類(lèi)型參數(shù)可使用的數(shù)量。其實(shí)JVM對(duì)泛型本身一無(wú)所知。

這同時(shí)也表示類(lèi)型參數(shù)的最大個(gè)數(shù)取決于你寫(xiě)的方法代碼4。我嘗試用另外一種類(lèi)型參數(shù)的編碼方案(先前鏈接文中的write_type_compact),使用全部合法的ASCII字符。這個(gè)實(shí)現(xiàn)是有點(diǎn)繁瑣的,因?yàn)樽址?-9是合法的,但不能作為標(biāo)識(shí)符的首字母,并且Java關(guān)鍵字也不能作為類(lèi)型參數(shù)。我僅僅將if和do替換為等長(zhǎng)的UTF-8字符。采用這種更緊湊的編碼方案讓類(lèi)型參數(shù)的個(gè)數(shù)從2776提升到了3123。

還是有一些不太方便的地方,例如_A是一個(gè)合法的Java標(biāo)識(shí)符,但是_不是。我的編碼在不使用_作為首字幕的情況下,最高生成了3392個(gè)2字節(jié)的類(lèi)型參數(shù)。所以我覺(jué)得不用考慮_作為首字母的情況了。

另外一個(gè)技巧

通過(guò)反編譯類(lèi)文件,我觀(guān)察到65536個(gè)字符中大部分都不是我生成的類(lèi)型參數(shù),而是重復(fù)的字符串Ljava/lang/Object;。這是因?yàn)轭?lèi)型參數(shù)沒(méi)有包含額外的信息,所以類(lèi)文件將其視為Object的繼承,并將它們編入方法簽名內(nèi)。我通過(guò)修改我的生成器來(lái)優(yōu)化這個(gè)問(wèn)題。

循環(huán)的關(guān)鍵代碼修改為:

 
 
 
  1. s = type_var(i) 
  2. f.write(s) 
  3. if (s != 'A'): 
  4.     f.write(" extends A") 

除開(kāi)一個(gè)實(shí)例之外,所有的類(lèi)型參數(shù)都從繼承java/lang/Object改為繼承A。這個(gè)修改將類(lèi)型參數(shù)的數(shù)量提升到9851個(gè)。

類(lèi)型參數(shù)的數(shù)量提升了非常多,而我所使用的編碼方法還可以繼續(xù)改進(jìn)。例如使用非ASCII unicode標(biāo)識(shí)符,不過(guò)我已經(jīng)比較滿(mǎn)意現(xiàn)在的效果了。

這些都不重要

在實(shí)際情況中是不太可能達(dá)到上述數(shù)量限制的。代碼生成時(shí)可能會(huì)達(dá)到語(yǔ)言或者編譯器的某些極限,就算罕見(jiàn)的遇到了生成上百個(gè)類(lèi)型參數(shù)的情況,那距離幾千個(gè)的限制仍然還相距很遠(yuǎn)。

盡管如此,如果我是規(guī)則的制定者,我將不允許任何類(lèi)或者方法使用超過(guò)255個(gè)類(lèi)型參數(shù)的情況。即使只影響了百萬(wàn)分之一的程序,有明確的限制會(huì)更好。

  1. §4.4, §8.1.2, §9.1.2, §8.4.4, §8.8.4 這些章節(jié)都和方法或者類(lèi)的類(lèi)型參數(shù)有關(guān),但是都沒(méi)有指明允許有多少個(gè)類(lèi)型參數(shù)。
  2. 當(dāng)我寫(xiě)這段話(huà)時(shí),我想起了Hotspot是C++寫(xiě)的,javac是Java寫(xiě)的。就算這樣我依然會(huì)選擇做代碼實(shí)驗(yàn),而不是閱讀代碼。閱讀別人代碼是種煎熬
  3. 逗號(hào)之后的空格不會(huì)影響,因?yàn)榫幾g器會(huì)規(guī)范化它的輸出。
  4. 這也表示與我使用哪個(gè)JVM無(wú)關(guān)。為了完整性,我在Fedora 29上使用了1.8.0_191-b13版本的OpenJdk。

本文作者:justinblank, 翻譯:Lephix


分享文章:一個(gè)Java方法能使用多少個(gè)參數(shù)?
URL標(biāo)題:http://www.dlmjj.cn/article/cdcpegi.html