代码之家  ›  专栏  ›  技术社区  ›  Jonas Byström

对吸气剂的每个爪哇

  •  5
  • Jonas Byström  · 技术社区  · 14 年前

    如果javac按照我的想法做,那么下面的行将产生相同的性能:

    for (Object o: getObjects()) {}
    List<Object> os = getObjects(); for (Object o: os) {}
    

    是不是这样?或者它可能是特定于实现的?如果是:有人知道GWT吗?

    5 回复  |  直到 14 年前
        1
  •  5
  •   Jason Hall    14 年前

    从纯Java的角度来看,这些答案似乎都是正确的。此外,如果可以的话,GWT编译器会在生成javascript之前将增强的for循环进一步重写为常规的for循环。所以它最终会看起来像:

    for (int i = 0; i < getObjects().size(); i++) {
      Object o = getObjects().get(i);
      // ...
    }
    

    原因何在?如果从未引用列表迭代器对象,则可以将其声明为死代码,并且不会在javascript中重写,从而导致较小的下载大小。这种优化对代码的实际执行应该没有任何影响。

    Optimizing apps with the GWT compiler 从今年的Google I/O中,可以了解更多关于GWT编译器为减小JS大小而做的其他疯狂事情的详细信息。

        2
  •  7
  •   SLaks    14 年前

    性能相同。

    Java编译器将每个循环转换成一个循环。 Iterator 通过调用 iterator() 方法。
    因此,实际列表实例只使用一次。(打电话) 迭代器() )

        3
  •  7
  •   Pascal Thivent    14 年前

    从Java语言规范:

    14.14.2 The enhanced for statement

    增强的for语句具有 形式:

    EnhancedForStatement:
            for ( VariableModifiersopt Type Identifier: Expression) Statement
    

    表达式必须具有类型 Iterable 否则它一定是 数组类型(_§10.1),或编译时 出现错误。

    声明的局部变量的范围 在窗体参数部分 增强 for 声明(_§14.14)是 包含的声明

    增强的含义 对于 语句通过翻译成 基本的 对于 语句。

    如果类型 Expression 是一个 亚型 可迭代的 然后让 I 是 表达式的类型 表达式。 iterator() . 增强型 对于 语句是等价的 基本 对于 声明 形式:

    for (I #i = Expression.iterator(); #i.hasNext(); ) {
    
            VariableModifiersopt Type Identifier = #i.next();
       Statement
    }
    

    在哪里? #i 是否生成编译器 与任何 其他标识符(编译器生成 或其他)属于范围(_§6.3) 在这一点上, 出现语句。

    正如你所看到的, 表情 只在for循环表达式的第一部分中提到,因此只计算一次。所以你的两条线会产生相同的性能。

        4
  •  3
  •   Jack    14 年前

    从实际的角度来看,您可以检查两个字节码并进行比较:

     m1()V
       L0
        ALOAD 0
        INVOKEVIRTUAL it/funge/Console.getObjects()Ljava/util/List;
        INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
        ASTORE 2
        GOTO L1
       L2
       FRAME FULL [it/funge/Console T java/util/Iterator] []
        ALOAD 2
        INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
        ASTORE 1
       L1
       FRAME SAME
        ALOAD 2
        INVOKEINTERFACE java/util/Iterator.hasNext()Z
        IFNE L2
       L3
        RETURN
    
    m2()V
       L0
        ALOAD 0
        INVOKEVIRTUAL it/funge/Console.getObjects()Ljava/util/List;
        ASTORE 1
       L1
        ALOAD 1
        INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
        ASTORE 3
        GOTO L2
       L3
       FRAME FULL [it/funge/Console java/util/List T java/util/Iterator] []
        ALOAD 3
        INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
        ASTORE 2
       L2
       FRAME SAME
        ALOAD 3
        INVOKEINTERFACE java/util/Iterator.hasNext()Z
        IFNE L3
       L4
        RETURN
    

    它们是相等的,唯一的区别是第二个代码段有两个单独的部分来加载 List 然后获取迭代器。这也会消耗更多的本地人,因为它也有一个 ALOAD 和一个 ASTORE 更多的,它被用来储存 getObjects 结果通过两行代码,而在第一个代码片段中,它直接使用它。

        5
  •  2
  •   Edward Dale    14 年前

    没有区别。foreach构造只获取 Iterator 从对象。这就是为什么它必须实现 Iterable 接口。