7

Java の学習を始めたばかりで、最初に遭遇したのはforeachループです。最初に行ったのは、それがどのように機能するかを知りませんでした:

int[] array = new int [10];
for (int i: array){
    i = 1;
}

1そして明らかに、配列のすべての要素への割り当てに失敗しました。System.out.print(i);次に、ループの本体に(after )を追加i = 1;すると、画面の出力が次のようになっていることがわかりましたが、ループ内で1111111111何かを行うことは有効であるため、配列のすべての要素のコピーである可能性がi最も高いのではないでしょうか? i(最初の質問)

上記が当てはまる場合foreach、配列の各要素のコピーを作成する必要があるため、ループが一般的な for ループよりもはるかに遅いことを意味しませんか? または、Javaポインターとポインター演算がないため、oprator[]すべての要素をコピーする方が実際には高速であるという他の「悪い」方法で設計されている可能性がありますか?

そして、上記の仮定が正しい場合、foreach一般的なループの代わりに明らかに遅いループを使用するのはなぜでしょうforか?

要するに質問:

  • iの各要素のコピーですかarray? そうでない場合、それは何ですか?

  • foreachループは一般的なループより遅くありませんか? そうでない場合、どの程度「ひどく」operator[]設計されていますか?

  • foreachループで勝つには、読みやすさ以外に何もありませんか?

4

4 に答える 4

11

コード内

for (int i: array){

i各ループ反復で配列内の次の要素の値を取得する変数を宣言しますが、それはその要素への参照ではありません。

i = 1;

配列内の要素ではなく、変数に新しい値を割り当てます。

foreach ループで配列要素の値を直接設定することはできません。そのために通常のforループを使用します

for (int i = 0; i < array.length; i++) {
    array[i] = ...; // some value
}

上記の例では、宣言された変数iを配列内の要素へのインデックスとして使用しています。

array[i] 

値を変更できる要素自体にアクセスしています。


Ans は明らかに、配列のすべての要素に 1 を割り当てることに失敗しました。System.out.print(i); を追加しました。ループの本体に移動すると、画面の出力が 1111111111 であることがわかりましたが、ループ内で i を使用して何かを行うことは有効であるため、おそらく i は配列のすべての要素のコピーですよね? (最初の質問)

System.out.print(i)の後にを付けたに違いありませi = 10000000

上記が当てはまる場合、配列の各要素のコピーを作成する必要があるため、foreach ループは一般的な for ループよりもはるかに遅いということではありませんか? または、Java にはポインターとポインター演算がないため、oprator[] は、すべての要素をコピーする方が実際には高速であるという他の「悪い」方法で設計されている可能性があります。

foreach ループがどのように機能するかについては、こちらをご覧ください。配列の場合、

for (int i: array){
    i = 1;
}

と同等です

for (int index = 0; index < array.length; index++) {
    int i = array[index];
    i = 1;
}

だから遅くはない。スタック上でもう 1 つの原始的な作成を行っています。

実装に依存します。配列の場合、決して遅くはありません。それは単に異なる目的を果たします。

一般的な forloop の代わりに、明らかに遅い foreach ループを使用するのはなぜですか?

理由の1つは読みやすさです。もう 1 つは、配列の要素参照を変更する必要はなく、現在の参照を使用する場合です。

参照型の例を見てみましょう

public class Foo {
    public int a;
}

Foo[] array = new Foo[3];
for (int i = 0; i < array.length; i++) {
    array[i] = new Foo();
    array[i].a = i * 17;
}

for (Foo foo : array) {
    foo.a = 0; // sets the value of `a` in each Foo object
    foo = new Foo(); // create new Foo object, but doesn't replace the one in the array
}

プリミティブ型では、そのようなことは機能しません。

for (int index = 0; index < array.length; index++) { 
    int i = array[index];
    i = 1; // doesn't change array[index]
}
于 2013-09-13T14:04:07.020 に答える
3

intはプリミティブ型であるため、参照による値の設定は機能しませんでした。どの種類の Object[] でも機能します。プリミティブ型のコピーの作成は非常に高速であり、気付かないうちにプロセッサによって何度も実行されます。

ループは読みやすくなっていforeachますが、書きやすくもなっています。一般的なプログラマ エラーは次のとおりです。

for (int i = 0; i < 10; i++)
{
    for(int j = 0; j < 10; i++) //oops, incrementing wrong variable!
    {
        //this will not execute as expected
    }
}

foreachループを使用してこのエラーを発生させることは不可能です。

于 2013-09-13T14:14:22.370 に答える
2

for ステートメントには、コレクションと配列を介した反復用に設計された別の形式もあります。この形式は、拡張 for ステートメントと呼ばれることもあり、ループをよりコンパクトで読みやすくするために使用できます。 http://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html

だから、あなたは正しいです。ここでの主な利点は読みやすさです。for each ループ、または強化された for ループの詳細については、orce のブログ エントリを参照してください

for each はIterable<E>インターフェイスの機能を利用したため、パフォーマンスは実装に依存します。

于 2013-09-13T14:26:15.517 に答える