我最近给我fork的我的项目QuickTheories减少了一个接口:
@FunctionalInterfacepublic interface QuadFunction<A, B, C, D, E> { E apply(A a, B b, C c, D d);}
这让十分好奇一个办法可能有多少个类型参数呢?据我所知,Java的语言标准并没有提到这个问题。1
对于在实现上这个阈值的定义,我有两个猜想:
- 编译器会强制一个可预测的阈值,例如255或者65535。
- 因为实现细节的起因,编译器的异样解决会施加意想不到的限度。
我不想通过我单薄的C++技能来测试源代码,所以我决定间接来测试编译器2。我写了一个Python脚本,通过二分法找到一个会触发谬误的最小值。残缺的代码请见连贯Github Repo。
最间接的方法就是生成办法。侥幸的是,咱们不用应用任何已有的类型参数,只须要依照<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的所定义的。
所以,我之前的猜想都不是齐全的正确。类型参数的最大个数是一个意料之外的值,而不是一个确定值。然而,编译器的实现自身并不是导致谬误的起因3。相同,是JVM类文件的格局要求限度了类型参数可应用的数量。其实JVM对泛型自身无所不知。
这同时也示意类型参数的最大个数取决于你写的办法代码4。我尝试用另外一种类型参数的编码方案(先前链接文中的write_type_compact
),应用全副非法的ASCII字符。这个实现是有点繁琐的,因为字符0-9是非法的,但不能作为标识符的首字母,并且Java关键字也不能作为类型参数。我仅仅将if
和do
替换为等长的UTF-8字符。采纳这种更紧凑的编码方案让类型参数的个数从2776晋升到了3123。
还是有一些不太不便的中央,例如_A
是一个非法的Java标识符,然而_
不是。我的编码在不应用_
作为首字幕的状况下,最高生成了3392个2字节的类型参数。所以我感觉不必思考_
作为首字母的状况了。
另外一个技巧
通过反编译类文件,我察看到65536个字符中大部分都不是我生成的类型参数,而是反复的字符串Ljava/lang/Object;
。这是因为类型参数没有蕴含额定的信息,所以类文件将其视为Object
的继承,并将它们编入办法签名内。我通过批改我的生成器来优化这个问题。
循环的要害代码批改为:
s = type_var(i)f.write(s)if (s != 'A'): f.write(" extends A")
除开一个实例之外,所有的类型参数都从继承java/lang/Object
改为继承A
。这个批改将类型参数的数量晋升到9851个。
类型参数的数量晋升了十分多,而我所应用的编码方法还能够持续改良。例如应用非ASCII unicode标识符,不过我曾经比较满意当初的成果了。
这些都不重要
在理论状况中是不太可能达到上述数量限度的。代码生成时可能会达到语言或者编译器的某些极限,就算常见的遇到了生成上百个类型参数的状况,那间隔几千个的限度依然还相距很远。
尽管如此,如果我是规定的制定者,我将不容许任何类或者办法应用超过255个类型参数的状况。即便只影响了百万分之一的程序,有明确的限度会更好。
- §4.4, §8.1.2, §9.1.2, §8.4.4, §8.8.4 这些章节都和办法或者类的类型参数无关,然而都没有指明容许有多少个类型参数。
- 当我写这段话时,我想起了Hotspot是C++写的,javac是Java写的。就算这样我仍然会抉择做代码试验,而不是浏览代码。浏览他人代码是种煎熬
- 逗号之后的空格不会影响,因为编译器会规范化它的输入。
- 这也示意与我应用哪个JVM无关。为了完整性,我在Fedora 29上应用了1.8.0_191-b13版本的OpenJdk。
本文作者:justinblank, 翻译:1 Way
原文链接:https://justinblank.com/exper...
译文首发:http://blog.didispace.com/how...
本文有spring4all技术翻译组实现,更多国外前沿常识和干货好文,欢送关注公众号:后端面试那些事儿。