为了账号安全,请及时绑定邮箱和手机立即绑定

你知道Java方法能定义多少个参数吗?

标签:
Java

一:为什么研究这么无聊的问题

这两天在读一本老书《Orange'S 一个操作系统的实现》,把丢了很长时间没研究的操作系统又重新拾起来了,在第三章讲解“保护模式”时,作者提到了调用门描述符中的Param Count只有5位,也就是说,最多只支持32个参数,这本来只是一个不是特别重要的细节,但是却勾起了我的思索:在JVM中,一个Java方法,最多能定义多少参数呢?我知道这是一个很无聊的问题,即使能定义一万个,十万个,谁又会真的去这么做呢。但是作为一个Coder,最重要的不就是好奇心吗,没有好奇心,和一条咸鱼又有什么区别呢?

二:实地考察

这种问题,第一步当然就是看看JVM中关于方法的定义,这里以openJDK10中的HotSpot为例。

在ConstMethod中,代表参数数量的字段为_size_of_parameters。

  u2                _size_of_parameters;         // size of the parameter block (receiver + arguments) in words

_size_of_parameters的类型为u2,在JVM中,u2为2个字节长,那么理论上来说,HotSpot支持的方法最大参数数量为2^16 - 1,即65535。这个答案究竟是否正确呢?实践出真知!

当然我不会傻到真的去一个个定义65535个参数,那我岂不成了“数一亿粒米”的幼师?Coder就得按照Coder的办法:

public static void main(String[] args) {    for (int i = 0; i < 65535; i++) {
        System.out.print("int a" + i + ",");
    }
}

完美解放了生产力 。

生成完参数列表,定义好方法,当我满怀信心的开始编译时,编译器给了我狠狠一刀:

webp

屏幕快照 2018-09-09 上午2.01.07.png

居然不是65535?那应该是多少呢?难道是一个字节长?废话不多说,我立即来实验了下255个参数,编译通过,再试了一下256,和65535时一样报错。那么结果很明显了,Java方法最多可以定义255个参数。

我查看了下Javac源码,在生成方法的字节码时,有方法参数数量限制判断:

if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras > ClassFile.MAX_PARAMETERS) {    log.error(tree.pos(), "limit.parameters");
    nerrs++;
}

其中 ClassFile.MAX_PARAMETERS = 255。

事情到这里我很不甘心,HotSpot中明明是用两个字节长来定义的方法参数数量,莫非只是Javac在编译过程中做了限制?只要能成功编译出一个有256个参数的java方法,在虚拟机中一试便知,但是怎么才能绕过Javac呢?

我觉得主要有以下两种办法:
一:修改Javac源码,干掉以上参数限制这一段代码,再重新编译;
二:利用字节码修改工具,硬改字节码,加上一个拥有256个参数的方法。

第一种方法看似简单,但是其实从openJDK中提取出来的Javac项目不能直接run,需要很多配置,而且源码依赖了很多jdk中的不可见类,操作起来很麻烦。所以这里我采用了第二种方法,工具选用的是老朋友javassist。

其实javassist使用起来很简单,这里我只需要对一个已有的class文件加上一个新方法即可:

    try {
        StringBuilder sb = new StringBuilder();

        sb.append("public static void testMax(");        for (int i = 0; i < 256; i++) {
            sb.append("int a" + i);            if(i < 255) {
                sb.append(",");
            }
        }
        sb.append("){}");

        ClassPool cPool = new ClassPool(true);
        cPool.insertClassPath("/Users/wanginbeijing/Documents/MyProgramings/java/Mine/test/src");
        CtClass cClass = cPool.get("com.wangxiandeng.test.Test");
        CtMethod newMethod = CtNewMethod.make(sb.toString(), cClass);
        cClass.addMethod(newMethod);
        cClass.writeFile("/Users/wanginbeijing/Documents/MyProgramings/java/Mine/test/src");
    } catch (NotFoundException e) {
        e.printStackTrace();
    } catch (CannotCompileException e) {
        e.printStackTrace();
    } catch (
            IOException e) {
        e.printStackTrace();
    }



作者:半栈工程师
链接:https://www.jianshu.com/p/a216b10c4624


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消