【问题标题】:Is List<Item> faster than List?List<Item> 比 List 快吗?
【发布时间】:2016-12-20 03:38:55
【问题描述】:

我正在开发一个带有许多List-s 和程序的Java 应用程序,我需要它快速执行。我想知道当我指定列表的类型元素时,循环是否更快。

一个例子:

代码 1:

List list = new ArrayList();
Item item;
list.add(...);
list.add(...);
list.add(...);
int t = list.size();
for(int i = 0; i < t; i++){
    item = (Item)list.get(i);
    //...
}

代码 2:

List<Item> list = new ArrayList<Item>();
Item item;
list.add(...);
list.add(...);
list.add(...);
int t = list.size();
for(int i = 0; i < t; i++){
    item = list.get(i);
    //...
}

code 2code 1 快吗?

【问题讨论】:

  • 为什么不测量它?此外,它应该是 - List list = new ArrayList();或 List list = new ArrayList();
  • 你是怎么计时的?
  • @ElliottFrisch 我认为这就是问题 - 它更快吗?
  • @cricket_007 也许吧。如果您测试了示例一,那么示例二第二个可能是 JIT 版的?如果我们知道 OP 对 item(s) 做了什么,这个问题会更有趣。
  • @Juan Camacho,你测量过性能吗?您注意到性能差异了吗?

标签: java performance list arraylist


【解决方案1】:

它们具有相同的运行时性能,因为 Java 泛型是使用类型擦除实现的。以下描述来自 Oracle/Sun 的 Java 泛型教程

https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

类型擦除

...

类型擦除确保不会为参数化创建新类 类型;因此,泛型不会产生运行时开销

【讨论】:

  • 更多的是在运行时没有泛型类型,只有List&lt;Object&gt;,所以泛型对运行时性能的影响应该不大。
【解决方案2】:

它们将具有完全相同的性能,因为它们编译成完全相同的代码。这就是type erasure 的工作方式:它用List 删除你所有的List&lt;Foo&gt;,并用Foo foo = (Foo) list.get(i) 替换Foo foo = list.get(i)(和类似的调用)。这就是为什么,例如,您不能询问是否有 instanceof List&lt;Foo&gt;&lt;Foo&gt; 信息在运行时丢失,因为它在编译时被删除。

您可以自己验证这一点。如果您参加简单的课程,例如:

public class Test {
  public void raw() {
    String s;
    List list = new ArrayList();
    for (int i = 0, t = list.size(); i < t; i++) {
      s = (String) list.get(i);
    }
  }

  public void generic() {
    String s;
    List<String> list = new ArrayList<>();
    for (int i = 0, t = list.size(); i < t; i++) {
      s = list.get(i);
    }
  }
}

您可以编译它,然后使用javap -c Test 反编译它并查看这两种方法。它们将是相同的。

Code:
   0: new           #2                  // class java/util/ArrayList
   3: dup
   4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
   7: astore_2
   8: iconst_0
   9: istore_3
  10: aload_2
  11: invokeinterface #4,  1            // InterfaceMethod java/util/List.size:()I
  16: istore        4
  18: iload_3
  19: iload         4
  21: if_icmpge     41
  24: aload_2
  25: iload_3
  26: invokeinterface #5,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
  31: checkcast     #6                  // class java/lang/String
  34: astore_1
  35: iinc          3, 1
  38: goto          18
  41: return

请特别注意第 31 字节的 checkcast 操作及其注释。那是(String) 演员表。

【讨论】:

    【解决方案3】:

    我希望这两个代码的性能几乎相同。原因是您的代码的两个版本实际上都将使用以下List

    List<Object> list = new ArrayList<>();
    

    在第一种情况下,Object 是集合的默认类型,而在第二种情况下,List&lt;Item&gt; 在类型擦除后将变为List&lt;Object&gt;

    【讨论】:

      【解决方案4】:

      把这两个代码放到这个程序里,你自己就可以看到结果了:

       class Longest
       {
           public static void main(String[] args)
           {
                  long start,end;
      
                  start=System.currentTimeMillis();
      
                  //Paste your above code here
      
                  end=System.currentTimeMillis();
      
                  System.out.println("Take taken by above code to execute:"+(end-start));
           }
         }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-31
        • 2017-12-17
        • 2022-10-08
        • 2015-07-24
        • 2022-12-26
        相关资源
        最近更新 更多