一个Java方法能有多少个参数类型?这个好奇coder作了个实验

在 JVM 中,一个 Java 方法,最多能定义多少参数呢?这是一个很无聊的问题,即便能定义一万个,十万个,谁又会真的去这么作呢。可是做为一个 coder,最重要的不就是好奇心吗,没有好奇心,和一条咸鱼又有什么区别呢?本文做者就是这样一位充满好奇心的 coder。

选自 justinblank,机器之心编译,参与:李志伟、张倩。
html

我最近给个人 QuickTheories 分支添加了一个接口:java

@FunctionalInterfacepublic interface QuadFunction<A, B, C, D, E> {    E apply(A a, B b, C c, D d);}复制代码

让我好奇的是这个方法能有多少个类型参数。到目前为止,我敢说,Java 语言规范并无谈及这个问题。git

对于实现定义的限制多是什么,我有两个猜想:github

  1. 编译器会设置一个可预测的限制,如 255 或 65535。bash

  2. 编译器的紧急行为会因为实现细节(堆栈溢出或一样不可预测/不相关的东西)而设置意外的限制。app

我不想在源代码上测试我那点可怜的 C++技巧,因此我决定只测试编译器作了什么。我写了一个 Python 脚本,它使用二进制搜索找到最少的致错类型参数。完整的脚本放在 Github repo (github.com/hyperpape/j…) 中。测试

脚本地址:github.com/hyperpape/j…ui

生成方法很简单。幸运的是,咱们没必要使用任何类型参数,只需以<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("}")复制代码

运行二进制搜索能够获得如下输出:spa

>>> 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 个以上的类型参数。明确的限制彷佛更好,即便它只影响百万分之一的程序。

原文连接:justinblank.com/experiments…

相关文章
相关标签/搜索