Java方法声明中参数的最大数量

146
Java中一个方法最多可以有多少个参数以及原因是什么?
我正在64位Windows系统上使用Java 1.8。
StackOverflow上所有的答案都说技术限制是255个参数,但没有说明为什么。
确切地说,对于静态方法,限制是255个,而对于非静态方法,限制是254个(在这种情况下,this将成为第255个)。
我认为这可能可以在某种规范中描述,并且只有预定义的最大参数数量。但是,这仅对于int和所有4字节类型有效。
我做了一些带有long参数的测试,在那种情况下,我只能声明127个参数。
通过使用String参数,我从测试推断出允许的最大数量为255(可能是因为Java中的引用大小为4字节?)。
但是,由于我使用的是64位系统,所以引用大小应该是8字节宽的,因此在具有String参数的情况下,最大允许数量应该与long类型类似为127。
这个限制如何精确应用?这个限制与方法的堆栈大小有关吗?
注意:我真的不会在任何方法中使用这么多参数,但这个问题只是为了澄清确切的行为。

40
7,如果你不想因易读性而发疯。(我知道你实际上在问什么)。 - Adam
14
我认为应该是 <= 4。任何更多的内容都应该打包成一个对象。 - Vivin Paliath
5
为什么这是一个有趣的问题?如果您正在编写程序并且到达了这个限制,那么您的设计是错误的。我不明白为什么这样一个实际上没有用的问题会得到如此多的赞同票。 - Jesper
21
好的,我会尽力完成翻译。以下是需要翻译的内容:@Jesper 因为这个问题涉及 JVM 规范的知识。这个问题并不是在问“如何做某事?”而是在问“为什么需要这样做?”……+1 有趣的问题 Userv - Amit
3
@amit,正是我所想的。原帖作者只是对此感到好奇。 - Evan Carslake
显示剩余6条评论
3个回答

122

限制在JVM规范中定义:

方法参数数量受方法描述符的定义(§4.3.3)限制,上限为255个,其中对于实例或接口方法调用,该限制包括一个单位用于this

§4.3.3节提供了一些额外信息:

方法描述符的有效性仅当它表示长度小于等于255的方法参数时才成立,在实例或接口方法调用的情况下,该长度包括this的贡献。

总长度是通过汇总各个参数的贡献来计算的,其中类型为long或double的参数对长度贡献两个单位,任何其他类型的参数对长度贡献一个单位。

您的观察是正确的,双字节基本数据类型(long/double)需要比通常的4字节变量和4字节对象实例引用多一倍的空间。

关于您问题中涉及到的64位系统,规范定义了每个参数贡献多少单位,即使在64位平台上,仍必须遵守规范的这部分,64位JVM将容纳255个实例参数(例如您的255个Strings),无论内部对象的指针大小如何。


10
我想补充一下这个答案,在64位架构中,栈也是64位的。因此,由于参数计数限制受到堆栈大小的限制,64位堆栈允许存储相同的255个对象引用。无论系统架构如何,对“long”和“double”的特殊处理在规范的许多地方都会出现,并且似乎是32位时代的遗留问题。 - Forketyfork
我正在编辑那部分内容 :) 同意,在不同的平台上仍然必须遵守规范。 - uraimo
1
是的,如果参数数量是字长的函数,那么这将破坏可移植性;你不能在不同的架构上成功编译相同的Java程序。 - Vivin Paliath
3
可变参数(Varargs)会被转换为一个 Object 数组,只能在参数列表中使用一次,并且占据最后的位置。考虑到这一点,使用可变参数可以将参数数量“扩展”到 254+Integer.MAX_VALUE(至少对程序员来说是这样,参数仍然为 255),因此使用这个技巧可以拥有 Integer.MAX_VALUE 个对象参数。 - uraimo
1
@MrTsjolder,请查看关于varargs的这个答案 - Vivin Paliath
显示剩余8条评论

12

JVM规范第4.3.3节中包含了您需要的信息:

方法描述符仅在表示方法参数总长度小于等于255时才有效,其中该长度包括在实例或接口方法调用情况下的this贡献。 总长度通过汇总各个参数的贡献计算得出,其中类型为long或double的参数对长度有两个单位的贡献,而任何其他类型的参数都对长度有一个单位的贡献。

因此,无论主机机器是32位还是64位,似乎都不会影响参数的数量。如果您注意到,文档使用“单位”的术语,其中一个“单位”的长度是字长的函数。如果参数数量与字长成正比,就会存在可移植性问题;您将无法在不同架构上编译相同的Java程序(假设至少有一种方法在具有较大字长的架构上使用了最大数量的参数)。


10

我从一封新闻简报中发现了一个有趣的问题,http://www.javaspecialists.eu/archive/Issue059.html

ClassFile结构中16位constant_pool_count字段限制了每个类或接口常量池的条目数不超过65535个,这作为单个类或接口总复杂度的内部限制。 每个非本地、非抽象方法的代码量由Code属性中exception_table、LineNumberTable和LocalVariableTable的索引大小限制在65536字节以内。

在方法调用时创建的帧的局部变量数组中最大局部变量数量由方法代码的max_locals项的Code属性大小限制为65535。需要注意的是,类型为long和double的值都被认为是占用两个局部变量并对max_locals值贡献两个单位,因此使用这些类型的局部变量会进一步降低此限制。

一个类或接口声明的字段数由ClassFile结构中fields_count项目的大小限制为65535。需要注意的是,ClassFile结构中fields_count项目的值不包括从超类或超接口继承的字段。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接