7

javacが私が思うことを実行した場合、次の行で同じパフォーマンスが得られます。

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

そうですか?それとも、おそらく実装固有ですか?もしそうなら:GWTについて知っている人はいますか?

4

5 に答える 5

8

パフォーマンスは同じになります。

Javaコンパイラは、ループするオブジェクトのメソッドをIterator呼び出すことにより、for-eachループをオブジェクトの周りのループに変換します。 したがって、実際のリストインスタンスは1回だけ使用されます。(呼び出すには)iterator()
iterator()

于 2010-06-04T12:17:15.780 に答える
8

Java言語仕様から:

14.14.2拡張されたforステートメント

拡張forステートメントの形式は次のとおりです。

EnhancedForStatement:
        for ( VariableModifiersopt Type Identifier: Expression) Statement

式は型 Iterableであるか、配列型(§10.1)である必要があります。そうでない場合、コンパイル時エラーが発生します。

for拡張ステートメント(§14.14)のFormalParameter部分で宣言されたローカル変数のスコープは、含まれているステートメントです。

拡張ステートメントの意味はfor 、基本ステートメントへの翻訳によって与えられforます。

Expressionのタイプがのサブタイプである場合、式のタイプとIterableIます iterator()。拡張ステートメントは、次の形式forの基本ステートメントと同等です。for

for (I #i = Expression.iterator(); #i.hasNext(); ) {

        VariableModifiersopt Type Identifier = #i.next();
   Statement
}

#i拡張forステートメントが発生する時点でスコープ(§6.3)にある他の識別子(コンパイラー生成またはその他)とは異なるコンパイラー生成識別子はどこにありますか。

ご覧のExpressionとおり、forループ式の最初の部分でのみ言及されているため、一度だけ評価されます。したがって、2つのラインで同じパフォーマンスが得られます。

于 2010-06-04T12:21:49.390 に答える
5

これらの答えはすべて、純粋なJavaの観点からは正しいように思われます。さらに、可能であれば、GWTコンパイラーは、JavaScriptを生成する前に、拡張されたforループを通常のforループに実際に書き換えます。したがって、実際には次のようになります。

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

理由?Listイテレータオブジェクトが参照されない場合、デッドコードとして宣言でき、JavaScriptで書き換えられないため、ダウンロードサイズが小さくなります。この最適化は、コードの実際の実行にはまったく影響しません。

GWTコンパイラがJSサイズを縮小するために行うその他のクレイジーなことの詳細については、今年のGoogle I/Oの「GWTコンパイラを使用したアプリの最適化」を参照してください。

于 2010-06-04T14:06:39.177 に答える
4

実用的な観点から、両方のバイトコードを検査して比較することができます。

 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

それらは等しく、唯一の違いは、2番目のスニペットがListイテレータをロードして取得するための2つの別個の部分を持っていることです。これはまた、クラスのより多くのローカルを消費します。実際には、さらに多くのローカルがあり、ALOAD最初のスニペットでは直接使用しますが、2行のコードを介して結果ASTOREを格納するために使用されます。getObjects

于 2010-06-04T12:29:01.857 に答える
2

違いはありません。foreach構造Iteratorは、オブジェクトからをフェッチするだけです。そのため、Iterableインターフェイスを実装する必要があります。

于 2010-06-04T12:18:23.040 に答える