当前位置: 首页 > 面试题库 >

Java的varargs性能

党俊健
2023-03-14
问题内容

编码我来检查Java的vararg性能。

我编写以下测试代码:

public class T {

    public static void main(String[] args) {

        int n = 100000000;
        String s1 = new String("");
        String s2 = new String("");
        String s3 = new String("");
        String s4 = new String("");
        String s5 = new String("");

        long t = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            foo();
        }
        System.err.println(System.currentTimeMillis() - t);


        t = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            baz(s1, s2, s3, s4, s5);
        }
        System.err.println(System.currentTimeMillis() - t);

        t = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            bar(s1, s2, s3, s4, s5);
        }
        System.err.println(System.currentTimeMillis() - t);

    }

    static void foo() {
    }

    static void bar(String a1, String a2, String a3, String a4, String a5) {
    }

    static void baz(String... a) {
    }
}

在我的机器上,平均输出为:

78
4696
78

似乎将变量传递给方法是免费的!好!

但是使用varags慢60倍!为什么呢

一种解释可能是程序必须在堆上创建数组,而时间是由GC花费的。但是对于更少的循环,我仍然得到输出:

0
62
0

什么花费了这些额外的时间,反正编译器拥有将其解决为fix变量调用的所有信息…

这不是我打算为此进行优化的意图,但是我发现这很好奇…

更新资料

我添加了一个新测试

t = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
    baz(s1);
}
System.err.println(System.currentTimeMillis() - t);

而且这个参数版本仍然慢30倍。也许在幕后有一个ArrayList.toArray()?

因此,请注意代码中不需要的varags方法,并进行重构以固定长度。这可能会提高性能。


问题答案:

静态参数列表与数组完全不同。当您以这种方式传递它们时,编译器将为引用保留空间,并在调用该方法时填充它们。

Varargs与array等效。要调用这种方法,必须在运行时创建并填充数组。这就是为什么您观察到差异。

String[]并且String...是同义词。如果比较它们,应该会看到相同的性能。



 类似资料:
  • 问题内容: 考虑方法声明: 该Object …参数只是对Objects 数组的引用。有没有办法在引用实际Object数组时使用此方法?如果我将Object数组传递给…参数-结果参数值将是一个二维数组-因为an Object[]本身就是an Object: 因此,数组的第一个组件(String.format方法中使用了哪个)将是一个数组,他将生成: 然后由于数组大小为1而发生错误。 该大胆的顺序是真

  • 问题内容: 我想用泛型和varargs实现一个函数。 这里的意图是断言传递给该函数的所有参数都是扩展作为第一个参数给出的Class的Class对象。因此main方法的前两行将进行编译,而第三行将生成错误。 我的问题是: 为什么前两行会显示“类型安全性:为varargs参数创建了Class的通用数组”消息? 我在这里想念什么吗? 附加问题: 如何重新设计它以防止在调用“ doNastyThingsT

  • 问题内容: 我不明白以下原因为何不起作用: 我的理解是编译器将“ int … args”转换为数组,因此上述代码应该可以工作。 不工作,我得到: 找不到符号符号:构造函数ArrayList(java.util.List >)位置:类java.util.ArrayList > 那就奇怪了。我没有将数组添加到数组列表中,而是将列表中的每个元素添加到arraylist中。这是怎么回事? 问题答案: Ja

  • 问题内容: 我对Java的 varargs 方法有些困惑: 当我尝试在不传递任何参数的情况下进行调用时,将调用方法的版本。我不明白为什么;通常,编译器必须引发错误。 相比之下,当我尝试不带任何参数的情况下,以下代码会生成编译器错误: 问题答案: 这里适用的一般规则是:如果一个方法签名严格比另一个方法签名 更具体 ,则Java选择它时不会出错。 从直觉上讲,如果您可以完全删除一个方法签名,则该方法签

  • 问题内容: 以下代码无法编译。 发出编译时错误。 对test的引用是模棱两可的,varargspkg.Main中的方法test(int …)和varargspkg.Main中的方法test(float …) 这似乎很明显,因为方法调用中的参数值可以提升为 如果任何一个或两个参数都带有或作为后缀,则会进行编译。 但是,如果我们用相应的包装器类型表示方法签名中的接收参数,如下所示 那么对该方法的调用不

  • Creates a group element Parameters varargs…elements to nest within the group Returns: object the g element Usage var c1 = paper.circle(), c2 = paper.rect(), g = paper.g(c2, c1); // note that the order