web-dev-qa-db-ja.com

ループ内でのオブジェクトの作成

ループ内でオブジェクトを作成するのは良い習慣ですか?私は次のコードを指しています:

for(some condition){
    SomeClass a = new SomeClass ();
    System.out.println(a);
}

したがって、これにより、反復ごとにSomeClassの新しいインスタンスが作成されます。したがって、インスタンスの数は反復の数に等しくなります。そして、これらは後でGCによって収集されます。

ループ内でSomeClassオブジェクトを再利用する方が良いでしょうか。このようなもの:

SomeClass a = null;

for(some condition) {
    a = new SomeClass();
    System.out.println(a);
}

私がこれを理解している限り、2番目の方法のほうが優れています。これは、SomeClassオブジェクトを1回作成し、すべての反復で再利用するためです。しかし、私は疑っています。これを確認するか、基本が間違っている箇所をお知らせください。

19
Sambhav Sharma

違いは、2番目のケースでは、ループが終了してもa変数がスコープ内にあることです。

それ以外は、ガベージコレクションの観点からも本質的に同じです。

文字列は参照型(不変ではありますが)であり、文字列に対して新しい変数を宣言するか、毎回同じ変数を単に上書きするかは問題ではありません。毎回、まったく新しい文字列を作成しています。

13
Sam I am

Stringは不変であるため、どちらも同等の量の文字列を作成します。 Stringに新しい値が割り当てられるたびに、新しいStringが作成されます。

例で可変オブジェクトを使用するつもりだったと仮定しましょう。

オプション1

for(some condition)
{
    Object o = new Object();
    System.out.println(o);
}

これにより、ループの反復ごとに新しいオブジェクトoが作成されます。

オプション2

Object o;
for(some condition)
{
    o = new Object();
    System.out.println(o);
}

これにより、ループの反復ごとに新しいObject oが作成されます。

可変オブジェクトの場合でも、どちらの方法でも同じ結果が得られます!

5
Rainbolt

「オブジェクト」自体と「オブジェクト」への「参照」を混同しないように注意してください。

たとえば、次のコードは(null)参照を作成しますが、オブジェクトは作成されません。

Object a = null;

次のコードは、オブジェクトとそのオブジェクトへの参照の両方を作成します(参照は「a」という変数に保持されます)。

Object a = new Object();

次のコードは、新しいオブジェクトを作成し、既存の(参照)変数を新しいオブジェクトを指すように「再ポイント」します。変数「a」がすでに別の参照を保持している場合、「a」はそれを忘れました。 [しかし、これはother変数が 'a'によって参照される古いオブジェクトを指す可能性があることを意味するものではありません]。

a = new Object(); // it is the reference 'a' that is 're-used' here not the object...

ループ内で上記のステートメントを再実行するたびに。あなたは確かに新しいオブジェクトを作成しています;そして、その新しいオブジェクトを「再ポイント」「a」しています。

以前の参照(つまり、「a」に保持されている参照)は毎回忘れられます。 (ここにシングルスレッドプログラムがあると仮定すると)それは、それが指しているオブジェクトがそれを指すゼロ参照を持つことを意味します。つまり、オブジェクトはガベージコレクションの対象となります。この時点でこのガベージコレクションが発生するかどうか-私は恐れているのか分からない。

しかし、私は言うでしょう:ガベージコレクションがいつ発生するかという点では、コーディング例に違いはありません。 「ポインタ型」がループ外で「オブジェクト」としてすでに定義されているか、ループ内で繰り返し再定義されているかどうか。

次の(役に立たない)例は、コードが一度に行う「オブジェクトの作成」アクションと「参照のポイント」アクションの違いを説明するのに役立ちます。

// This creates an object ; but we don't hold a reference to it.
    public class TestClass {
    public static void main(String[] args) {
    for (int n=0;n<100;n++) {
        new Object();
    }
    }
    }

対照的に:

// This creates a reference ; but no object is created
// This is identical to setting the reference to 'null'.
public class TestClass {
public static void main(String[] args) {
for (int n=0;n<100;n++) {
        Object o;
}
}
}
5
monojohnny

オブジェクトを割り当てる変数を、実際のオブジェクトインスタンスと混同しています。

両方のコードサンプルは、同等の量のオブジェクトを作成します。 2番目のインスタンスは、1つのインスタンスをより大きなスコープに保持するため、より長い時間利用できます。

3
Zavior

2番目は「より良い」ものではありません。

String a="foo";は、文字列プールからリテラル文字列を再利用します。つまり、aの内外でloopを宣言しても、メモリの面で違いはありません。しかし、それらのスコープは異なります。別の問題だと思います。

編集したバージョン、一般的なSomeClassを使用した場合でも、あなたが思っていたものとは異なります:

2番目の方法の方が優れています。これは、SomeClassオブジェクトを1回作成するだけで、繰り返しごとに再利用するためです。

各ループステップで新しいオブジェクトを作成します。 aはオブジェクトへの単なる参照です。ポイントは、作成したオブジェクトが他のオブジェクトによって参照されている場合、GCはそれを収集せず、メモリを解放することです。たとえば、古い(<= Java1.6)String.subString()メソッドは、元の文字列をchar[]として保持するため、GCは元の文字列を消去しません。

3
Kent

唯一の違いは、2番目のケースでは、ループが終了しても変数がスコープ内にあるということです。文字列は不変なので、両方の場合に作成されるオブジェクトの数は等しい

この場合も質問を編集したばかりなので、両方の場合で各反復でメモリに新しいオブジェクトが作成されます

3
Girish

私の知識によると-より大きなアプリケーション(これではありません)では、オブジェクト作成にstatic blockを使用する方が良いです-静的ブロックコードは、クラスがメモリにロードされるときに1回だけ実行されるためです。技術的には、クラスには複数の静的ブロックを含めることができますが、あまり意味はありません

覚えておいてください:Static block can access only static variables and methods

3
DRastislav

トピックがかなり変わったので。更新します:

reuseを一度作成したい場合は、そのコードを自分で記述する必要があります。次の原則に従うことができます。

_SomeClass a = new SomeClass();

for(some condition) {
    a.reset();
    //do something with a
}
_

SomeClass.reset()メソッドがすべての詳細を処理します(オブジェクトの実際の使用法に依存します)。

2
SebastianH

スコープがすべてです。

2番目の方法を実行する場合:

SomeType someFunction(){
   ...
    SomeClass a = null;

    for(some condition) {
        a = new SomeClass();


           System.out.println(a);
        }
     ...
     return something
    }

オブジェクトaはsomeFunctionの終わりまでメモリ内に存在しますが、最初のメソッドの場合、そのライフサイクルはループの単一の反復内にあります

2
user902383