当我编写一些API时,有时会使用Collection<Model>
为参数。当然,你可以使用ArrayList
如果你知道ArrayList
已经足以处理所有用例。
我的问题是,例如转换 ArrayList<Model>
时是否会产生相当大的性能成本?至Collection<Model>
传递参数时。
集合大小也会影响类型转换的性能吗?有什么建议吗?
感谢彼得的回答。
我认为答案足够漂亮,足以阻止我浪费时间进行更改。
编辑
正如接受的答案中所说,成本实际上是在接口(interface)方法的调用中付出的。 保持这种灵 active 并不是免费的。但成本并没有那么可观。
最佳答案
与大多数性能问题一样,答案是:编写清晰且简单的代码,应用程序通常也能正常运行。
转换为接口(interface)可能需要大约 10 ns(少于方法调用),具体取决于代码的优化方式,它可能太小而无法测量。
泛型类型之间的转换是编译器时间检查,运行时实际上什么也没有发生。
当你转换时,改变的是引用类型,所有引用的大小相同。它们所指向的内容的大小并不重要。
顺便说一句:所有 ArrayList 对象的大小相同,所有 LinkedList 对象的大小相同,所有 HashMap 对象的大小相同等等。它们可以引用一个数组,该数组在不同的集合中可以有不同的大小。
<小时/>您可以看到未经 JIT 处理的代码中的差异。
public static void main(String... args) throws Throwable {
ArrayList<Integer> ints = new ArrayList<>();
for(int i=0;i<100;i++) ints.add(i);
sumSize(ints, 5000);
castSumSize(ints, 5000);
sumSize(ints, 5000);
castSumSize(ints, 5000);
}
public static long sumSize(ArrayList<Integer> ints, int runs) {
long sum = 0;
long start = System.nanoTime();
for(int i=0;i<runs;i++)
sum += ints.size();
long time = System.nanoTime() - start;
System.out.printf("sumSize: Took an average of %,d ns%n", time/runs);
return sum;
}
public static long castSumSize(ArrayList<Integer> ints, int runs) {
long sum = 0;
long start = System.nanoTime();
for(int i=0;i<runs;i++)
sum += ((Collection) ints).size();
long time = System.nanoTime() - start;
System.out.printf("castSumSize: Took an average of %,d ns%n", time/runs);
return sum;
}
打印
sumSize: Took an average of 31 ns
castSumSize: Took an average of 37 ns
sumSize: Took an average of 28 ns
castSumSize: Took an average of 34 ns
但是差异可能是由于方法调用更昂贵。唯一的字节码差异是
invokevirtual #9; //Method java/util/ArrayList.size:()I
和
invokeinterface #15, 1; //InterfaceMethod java/util/Collection.size:()I
一旦 JIT 优化了代码,就不会有太大区别。运行足够长的时间,-server JVM 的时间会降至 0 ns,因为它检测到循环没有执行任何操作。 ;)
关于java - 将具体集合类型转换到其接口(interface)的性能成本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7309703/