java 语法糖

Java 语法糖(四): Varargs (变长参数)

2021-06-18  本文已影响0人  jyjz2008

正文

java 支持变长参数, 那么这个功能是如何实现的呢?
先写段简单的程序尝试一下

package com.fake;

public class VarArgsTest {

    public static void main(String... args) {
        System.out.println(args.getClass());
    }
}

运行结果如下图所示


运行结果.png

名为 args 的参数的类型看起来就是 String[]

那么我们在 VarArgsTest 类中写两个函数试一试 varargs 和普通的数组参数有何不同(新的代码如下)。

package com.fake;

public class VarArgsTest {
    private void f1(int... args) {

    }

    private void f2(int[] args) {

    }

    public static void main(String[] args) {
        new VarArgsTest().f1(999, 888, 777);
        new VarArgsTest().f2(new int[]{999, 888, 777});
    }
}

build 之后,在 IntelliJ IDEA 里借助 Bytecode viewer 插件看一看 f1(...)f2(...) 有何不同。

圖片.png

对比之后,不难发现,两个函数的 access flag 是不同的(但是 入参类型 以及 返回值类型 都是完全相同的)

圖片.png

前往 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6 会看到 access flags 的描述

圖片.png

下面还有一段补充

The ACC_VARARGS flag indicates that this method takes a variable number of arguments at the source code level. A method declared to take a variable number of arguments must be compiled with the ACC_VARARGS flag set to 1. All other methods must be compiled with the ACC_VARARGS flag set to 0.

那么当我们调用 varargs 方法时,编译器会帮我们把参数转化为数组吗?
实践出真知,我们来试一试。
我在刚才的 VarArgsTest 类中写了一个 main 方法

public static void main(String[] args) {
    new VarArgsTest().f1(999, 888, 777);
    new VarArgsTest().f2(new int[]{999, 888, 777});
}

继续借助 Bytecode viewer 插件,看一看字节码中对应的内容(有两张图)

图一.png

图一里的红框部分相当于执行了

f1(new int[]{999, 888, 777})
图二.png

图二里的红框部分相当于执行了

f2(new int[]{999, 888, 777})

这么一对比,就会发现,编译器会帮忙把
new VarArgsTest().f1(999, 888, 777); 转化为
new VarArgsTest().f1(new int[]{999, 888, 777});

由此可以推测,在调用 varargs 方法时,编译器会自动把 创建数组 以及 填写数组元素 的过程给补上。

参考文章

  1. https://www.benf.org/other/cfr/varargs.html
  2. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6
上一篇下一篇

猜你喜欢

热点阅读