2012-02-16 5 views
14

次のループでオブジェクトのコピーが作成されるのではなく、オブジェクトへの参照を与えるかどうか疑問に思っています。理由は、最初の例では配列オブジェクトを割り当てないが、2番目の例では配列オブジェクトを割り当てるためです。Java:For-Eachループと参照

MyObject objects[] = new MyObject[6]; 
for (MyObject o: objects) { 

    o = new MyObject(); 
} 

MyObject objects[] = new MyObject[6]; 
for(int i = 0; i < objects.length; i++) { 

    objects[i] = new MyObject(); 
} 
+0

最初にjavaのようなforループ構文がありますか? –

+0

@ChandraSekhar:[for-each loop java](http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html)。 – RanRag

+0

@ChandraSekhar RanRagが正しいです。しかし、それは質問には関係ありません。多分、OPはコピー/貼り付けではなく、彼の好みの言語で考えた彼のコードを書き直しました。 –

答えて

15

Javaは他の多くの言語とは少し異なります。最初の例のoは単にオブジェクトへの参照です。あなたがo = new MyObject()を言うときoobjects[index]を参照するのに対し、

は、それは、型MyObjectに、そのオブジェクトへの参照oの新しいオブジェクトを作成します。

つまり、オブジェクト[インデックス]自体は、メモリ内の別のオブジェクトへの参照に過ぎません。したがって、オブジェクト[index]を新しいMyObjectに設定するには、オブジェクト[index]が指し示す場所を変更する必要があります。これはオブジェクト[index]を使ってのみ行うことができます。

画像:(私のひどい塗装スキル:D)

enter image description here

説明: これは、Javaのメモリ管理がどのように機能するかを大まかにです。どんな手段でも厳密にはそうではありませんが、おおよそ。 A1を参照するオブジェクトがあります。オブジェクト配列にアクセスすると、最初の参照点(A1)から開始し、前方にXブロック移動します。たとえば、インデックス1を参照するとB1になります。 B1は次に、A2のオブジェクトを探していることを伝えます。 A2はC2に位置するフィールドを持っていることを示します。 C2は基本データ型の整数です。検索が完了しました。

は、A1またはB1を参照せず、C1またはC2を参照しています。 new ...と言うと、新しいオブジェクトが作成され、そこに配置されます(たとえば、スロットA3)。 A1またはB1には影響しません。

私は少し物事をクリアできるかどうか教えてください。

+0

確かに、それは意味します。したがって、最初の例では、oはC++ポインタのようなもので、変数自体であり、valueは別の変数のアドレスです。だから、それに何かを割り当てると、それが指しているものではなく、変数が設定されます。 ありがとう! – rhughes

+0

正確:D C++とは異なり、Javaはポインタコントロールなどの面で多くのことを持っていません。変数参照はメモリに置かれ、 '= 'はそれらを再参照します。参照した場所に新しい変数を作成することはできません。ただし、この変数を変更することはできます。 'o'がすでに初期化されていて、' o.x'がフィールドであれば、 'o.x'がどこを指しているかを変更して、' o.x'を再割り当てすることができます。 –

3

foreachループはコレクションの要素を反復ので、最初のものは、あなたの配列オブジェクトを割り当てるされていません。

ループにforeachループを入力すると、コレクションに要素がなくなり、サイズが6に初期化された空の配列になります。そのため、オブジェクトは配列に追加されません。

また、あなたは配列内の要素を持っていた場合でも、foreachループはそれらの上に割り当てないことに注意してください:

o = new MyObject(); 

基本的にoMyObjectの新しいインスタンスを割り当てることが、o自体がありえません配列objectsの一部です。これは、配列の要素を反復処理するために使用される一時的なコンテナですが、この場合は存在しません。

+0

それは本当に空ではない、それはちょうど6ヌルが内部にあります。そうでなければ、良い答え。 +1 –

+0

は、その内部に 'MyObject'の要素がないという意味では空です。 –

+0

私たちは同じことを別の言葉で言っていると思います。 –

8

短い回答:はい、コピーのようなものがあります。

長い答え:あなたが投稿するJava foreachループは、内容を変更しないforeachループ内の何かに等しい基準を設定し、脱糖バージョンが示しているように

MyObject objects[] = new MyObject[6]; 

Iterator<MyObject> it = objects.iterator(); 
while (it.hasNext()) { 
    MyObject o = it.next(); 
    // The previous three lines were from the foreach loop 

    // Your code inside the foreach loop 
    o = new MyObject(); 
} 

ためのシンタックスシュガーでありますアレイ。

2

オブジェクトは、オブジェクトのクローンを明示すると明示的に指定すると(このオブジェクトはクローン機能を明示的に実装します)、「コピー」されます。

参照と名前を混同しているようです。

最初の例では、foreach内でローカル変数oは、objectsからのオブジェクトが格納されているメモリの領域を参照します。 o = new MyObject()を実行すると、新しいMyObjectがメモリの他の領域で初期化され、o参照がこの新しいメモリ領域を指すように書き換えられます。

objects[i] = new MyObject()を書くと、objects[i]の参照を書き換える必要があり、ローカルのo変数は書き換えないと言います。

4

それぞれの例に何が起こっているのかを明確にするためにコメントを追加しました。

まず例:

MyObject objects[] = new MyObject[6]; 
for(MyObject o: objects) { 

    // Construct a new object of type MyObject and assign a reference to it into 
    // the iteration variable o. This has no lasting effect, because the foreach 
    // loop will automatically assign the next value into the iteration variable 
    // in the the next iteration. 
    o = new MyObject(); 
} 

第二の例:私は言及したい

MyObject objects[] = new MyObject[6]; 
for(int i = 0; i < objects.length; i++) { 

    // Construct a new object of type MyObject and store a reference to it into the 
    // i-th slot in array objects[]: 
    objects[i] = new MyObject(); 
} 
+0

Javaのキーワードではないので、まったくコンパイルされません。そこでコロン(:)を置く必要があります。 –

+0

編集前にユーザーの元のコードをコピーしてしまいました。それは、私の答えのポイントを変更しないと言いました。 –

+0

イワールはなぜ彼らがそれをしたのかを誰にでも伝えるべきだ。あなたが改善のための説明を提供しない場合、否定的なフィードバックは役に立たない。イゴール、深さの不足のために-1と思っています。 –

0

まず最初は、非ゼロ長の配列は常にforeachループ

for(MyObject o in objects) 
内mutable.Andされていることです

これは、各繰り返しで次のように動作します。

o = objects[0] // first iteration 
o = objects[1] // 2nd iteration 

しかし、あなたの場合、別のオブジェクトを参照に割り当てます。配列内のオブジェクトではありません。単純に以下のようになります。

ObjeMyObject objects[] = new MyObject[6]; 
MyObject o = Object[0]; 
0 = new MyObject(); 

しかし、元のオブジェクト[0]はまだヌルオブジェクトを指しています。

0

「新しい」演算子を使用するたびに、演算子JVMは新しいインスタンスを作成し、代入演算子の左辺オペランドに割り当てられます。 各ループまたはforループには関係ありません。各ループ ために (MyObjectにO:オブジェクト) Oは、それがインスタンス化されず、オブジェクトの配列から値が

O = Object[0] 
O = Object[1] 
O = Object[2] 
O = Object[3] 
O = Object[4] 
O = Object[5] 

ようなOでコピーを維持するMyObjectにのことながら、一度だけ作成されます

カウンターを増やす必要はありません。それぞれのループの美しさです。