当前位置: 首页 > 科技观察

一个Java方法可以带多少个参数?

时间:2023-03-12 18:35:43 科技观察

我最近在我的fork项目QuickTheories中添加了一个接口:@FunctionalInterfacepublicinterfaceQuadFunction{Eapply(Aa,Bb,Cc,Dd);}这让人很好奇一个方法可以有有多少类型参数?据我所知,Java的语言规范并没有提到这个问题。1关于实现中此阈值的定义,我有两种猜测:编译器将强制执行一个可预测的阈值,例如255或65535。由于实现细节,编译器异常处理可能会施加意外限制。我不想用我薄弱的C++技能测试源代码,所以我决定直接测试编译器2。我写了一个python脚本来找到一个二分法触发错误的最小值。有关完整代码,请参阅指向GithubRepo的链接。最直接的方法是生成方法。幸运的是,我们不必使用任何现有的类型参数,只需按照defwrite_type_plain(count):withopen('Test.java','w')asf:f.write("publicclassTest{\n")f.write("public<")foriinrange(count):if(i>0):f.write(",")f.write("A"+str(i+1))f.write(">voidtestMethod(){}")f.write("}")运行二分法代码会有如下输出:>>>error:UTF8representationforstring">>largesttype:2776这个错误有点迷惑,但事后看来可以理解。编译器生成的类文件包含几个字符串,包括每个方法的方法签名。这些字符串存储在常量池中,常量池的内容最大限制为65535字节,这是JVM定义的。所以,我之前的猜测没有一个是完全正确的。类型参数的最大数量是一个意外的值,不是一个固定值。然而,编译器的实现本身并不是导致错误3的原因。而是JVM类文件的格式要求限制了可以使用的类型参数的数量。事实上,JVM对泛型本身一无所知。这也意味着类型参数的最大数量取决于你编写的方法代码4。我尝试对类型参数使用另一种编码方案(之前链接的文章中的write_type_compact),使用所有合法的ASCII字符。这种实现方式有点繁琐,因为0-9字符是合法的,但不能作为标识符的首字母,Java关键字也不能作为类型参数。我只是用等长的UTF-8字符替换了if和do。采用这种更紧凑的编码方案,类型参数的数量从2776个增加到3123个。仍然有一些不方便的地方,比如_A是一个有效的Java标识符,但_不是。我的编码生成多达3392个2字节类型的参数,而不使用_作为第一个字幕。所以我认为没有必要考虑_作为第一个字母的情况。另一个trick通过反编译class文件,我观察到这65536个字符大部分不是我生成的类型参数,而是重复的字符串Ljava/lang/Object;。这是因为类型参数不包含任何附加信息,所以类文件将它们视为从Object继承而来,并将它们编码到方法签名中。我通过修改生成器优化了这个问题。循环的关键代码修改为:s=type_var(i)f.write(s)if(s!='A'):f.write("extendsA")除一个实例外,所有类型参数都被继承fromjava/lang/Object改为继承A。这次修改增加了类型参数的个数,增加到9851个。类型参数的个数明显增加,我使用的编码方式还可以继续改进。例如使用非ASCIIunicode标识符,但我对它现在的工作方式非常满意。这些都不重要,在实践中也不太可能达到上述数量限制。代码生成可能会达到语言或编译器的某些限制。即使在生成数百个类型参数的罕见情况下,它仍然远未达到数千个的极限。不过,如果我是规则制定者,我不会允许任何类或方法采用超过255个类型参数。即使只有百万分之一的程序受到影响,最好有明确的限制。§4.4、§8.1.2、§9.1.2、§8.4.4、§8.8.4这些部分都涉及方法或类类型参数,但没有指定允许多少类型参数。写这段话的时候,我想起了Hotspot是用C++写的,javac是用Java写的。尽管如此,我还是选择做代码实验而不是阅读代码。阅读别人的代码是一种痛苦。逗号后的空格无关紧要,因为编译器会规范化其输出。这也意味着我使用哪个JVM并不重要。为了完整起见,我在Fedora29上使用1.8.0_191-b13版本的OpenJdk。本文作者:justinblank,翻译:Lephix原文链接:https://justinblank.com/experiments/howmanytypeparameterscanajavamethodhave.html版权属于作者,转载请注明作者、原文、译者等出处信息