一个 Java 方法,最多能定义多少参数?
钉钉、微博极速扩容黑科技,点击观看阿里云弹性计算年度发布会!>>>
云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!
在 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 语言规范并没有谈及这个问题。
对于实现定义的限制可能是什么,我有两个猜测:
1.编译器会设置一个可预测的限制,如 255 或 65535。
2.编译器的紧急行为会由于实现细节(堆栈溢出或同样不可预测/不相关的东西)而设置意外的限制。
我不想在源代码上测试我那点可怜的 C++技巧,所以我决定只测试编译器做了什么。我写了一个 Python 脚本,它使用二进制搜索找到最少的致错类型参数。完整的脚本放在 Github repo (https://github.com/hyperpape/java-max-type-params) 中。
脚本地址:https://github.com/hyperpape/java-max-type-params
生成方法很简单。幸运的是,我们不必使用任何类型参数,只需以的形式发出它们:
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 个以上的类型参数。明确的限制似乎更好,即使它只影响百万分之一的程序。
【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/zhibo立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK
原文发布时间:2020-07-01
本文作者:互联网架构师
本文来自:“互联网架构师 微信公众号 ”,了解相关信息可以关注“[互联网架构师](https://mp.weixin.qq.com/s/oXETScz5zt73YQJWDy2IIw)
- Java方法能定义多少个参数你知道吗
- Java 定义一个参数类型一样,但个数不固定的方法
- JAVA--定义一个包含整型数组参数的方法,用来接收成绩数组,进行成绩排序并输出前三名
- 如果java中一个方法不知道要传递多少参数也不知道传递过来的是什么类型的数据你会怎么做?
- java中一个方法可以有多少个参数
- Java中 每个类在没有声明构造方法的前提下,会自动生成一个不带参数的构造方法
- Java 编程下通过反射获取一个类中的方法名和对应参数名
- Java:构造一个Car类,包含无参数和有参数两种构造方法。
- Java利用反射来获取一个方法的 范型化参数 Vector<Integer>的类型
- java一个方法形参有两个,如何在调用的时候只传入一个参数
- python定义方法时传入参数中,参数名中带一个*与带两个*的意义
- 为什么Java匿名内部类中的方法参数必须定义为final
- java 中 如何让一个方法内最多只能指定数量线程访问
- C# 001 --- 正确的删除一个控件的事件函数 --- 解决错误: “A”不包含“B”的定义,并且找不到可接受类型为“A”的第一个参数的扩展方法“B”(是否缺少 using 指令或程序集引用?)
- 在一个程序中需要用到全局变量(在多个class之间共享数据),请问如何定义具有这种功能的变量?或者是否有其他的方法解决多个class之间的数据共享(尽量简单实现)。 首先应该明确 Java中没有全局变
- java反射,反射常用方法,获取类模板,通过类模板对象创建实体对象,类中未定义有参或无参构造器的情况下创建对象,不调用方法尝试给一个类的私有属性赋值,通过反射获取一个类的父类并获取它实现的接口
- 定义平面中的一个Circle类, 1编写一个无参数构造函数, 2编写一个有参的构造函数 3在主函数中调用无参构造函数生成圆的实例c1,调用有参构造函数生成圆的实例c2,调用实例方法判断c1和c2是否重
- Java 把对象作为参数传到一个方法里,这个是值传递还是引用传递, 为什么结果这么怪?
- c#定义一个方法,根据存储过程名称和存储过程参数数组,执行对应的存储过程
- java中自己定义一个类,类中必须有一个自己定义的构造方法,否则编译系统识别不了