当我编写一些API时,它有时会使用Collection<Model>
作为参数。当然,如果您知道ArrayList
已足以处理所有用例,则可以使用ArrayList
。
我的问题是,例如在传递参数时将ArrayList<Model>
强制转换为Collection<Model>
是否会产生相当大的性能成本。
收藏尺寸是否也会影响铸造性能?有什么建议吗?
感谢Peter的回答。
我认为答案足以阻止我浪费时间去改变它。
修改
正如已接受的答案中所述,实际上是在调用接口方法时支付了费用。 保持这种灵活性并不是免费的。但成本并不是那么可观。
答案 0 :(得分:6)
与大多数表演问题一样,答案是;编写清晰和简单的代码,应用程序通常也可以正常运行。
转换为接口可能需要大约10 ns(少于方法调用)根据代码的优化方式,它可能太小而无法测量。
泛型类型之间的转换是编译器时间检查,在运行时实际上没有发生任何事情。
当你施放时,它是更改的引用类型,所有引用都是相同的大小。他们指出的大小并不重要。
BTW:所有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,因为它检测到循环没有做任何事情。 ;)
答案 1 :(得分:0)
与使用任何对象执行任何相比:绝对没有。
即使这样做,也要确保任何程序都涉及花费数百万更多时间的事情!
答案 2 :(得分:0)
收藏是interface。您始终必须提供具体的implementation,例如ArrayList。
通常会是这个
Collection<Model> myCollection = new ArrayList<Model>();
设计接口实际上是一种很好的做法,因此请使用Collection作为方法参数。