2014-02-18 88 views
17

在循環內創建對象是一種很好的做法。我指向以下代碼:在循環內創建對象

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); 
} 

據我瞭解這一點,第二個方法是,因爲這會創建SomeClass的對象一次更好,將重新使用它在每次迭代。但我很懷疑。請確認這一點,或讓我知道我的基本面不正確。

+2

由於字符串池,字符串文字不是最好的例子。同樣,你的例子在每個循環迭代中創建「新實例」。 – Pshemo

+0

好吧,現在我不想那麼說了,那麼套件和列表又如何呢?如果我在循環內部或外部循環中創建Set對象,會有什麼區別? –

+0

它們是對象,就像字符串。從這個角度來看,他們的表現完全一樣。 – Zavior

回答

11

不同的是,在第二種情況下,你的a變量仍然是在範圍上,當循環結束

除此之外,他們基本上是相同的,即使從一個垃圾收集點。

字符串是引用類型(雖然是不可變的),並且無論您爲它們聲明新變量還是每次只覆蓋相同變量都無關緊要。你每次都會創建一個全新的字符串。

+3

請澄清「每次創建一個全新的字符串」。我不記得任何創建任何字符串的OP代碼版本。 –

+0

@HotLicks OP編輯它。 –

+3

其實,不,OP沒有編輯它,別人做了。如果您檢查編輯歷史記錄,則永遠不會有執行「新字符串」操作的版本。 –

3

您將您分配對象的變量混淆到實際的對象實例。

這兩個代碼示例創建等量的對象。第二個將在一個更大的範圍內保留一個實例,因此它將可用更長的時間。

5

兩者都創建等量的字符串,因爲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對於循環的每次迭代。

即使對於可變對象,也可以得到相同的結果!

+0

兩者都創建相同數量的字符串,因爲它們都不會創建任何字符串。 –

+1

@HotLicks你到底在想什麼? – Rainbolt

+0

在原始代碼中(自編輯以來)不會在任何地方創建任何字符串。 「foo」是預先存在的字符串文字。 –

3

第二個不是「更好」。

String a="foo";重新使用字符串池中的文字字符串。也就是說,無論您在loop之內還是之外申報a,在內存方面都沒有區別。但他們有不同的範圍。我認爲這是另一個問題。

即使你編輯的版本,一般SomeClass,它不像你想什麼:

第二個方式是這更好的將剛剛創建SomeClass的對象一次,將重新使用它在每次迭代。

它在每個循環步驟中創建新對象。 a只是對象的引用。重點是,如果您創建的對象被其他對象引用,則GC將不會收集它,並釋放內存。例如,舊的(< = java1.6)String.subString()方法,它將原始String保存爲char[],因此GC將不會清除原始String。

+0

關於特定行爲或字符串關於它們正在彙集的好處...... – monojohnny

3

唯一的區別是,在第二種情況下,當循環結束時,變量仍然在範圍內。這是在兩種情況下創建的對象是平等的字符串是不可變

像你剛纔在這種情況下,新對象在內存在兩種情況下

2

由於創建在每次迭代還是編輯的問題話題發生了很大變化。我更新:

如果你真的想要重用曾經創建的對象,你將不得不自己編寫代碼。它可以遵循這樣的原則:

SomeClass a = new SomeClass(); 

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

SomeClass.reset()方法處理所有的細節(這依賴於對象的實際使用情況)。

+0

'a =「foo」= \ = new String(「foo」)' – Kent

+0

'a =「foo」'分配預先創建的,將「foo」的JVM-global String實例添加到引用。所以沒有創建。 –

+0

那有什麼區別? – SebastianH

4

注意不要混淆「對象」本身就是一個「參考」到「對象」:

例如,下面的代碼創建一個(空)參考,但沒有創建對象。

Object a = null; 

下面的代碼創建boths一個對象,並對該對象的引用(參考在名爲「A」的變量持有):

Object a = new Object(); 

下面的代碼創建新對象和「重新指向'一個存在的(引用)變量指向新的對象:如果變量'a'已經擁有另一個引用,'a'會將其放大。 [但這並不意味着其他變量可能仍然指向由'a'引用的舊對象]。

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

每次你在你的循環中重新運行上述語句時,你的確在創造一個新的對象;而且你正在重新指向那個新對象。

以前的參考文獻(即'a'中的參考文獻)每次都會被遺忘;和(假設我們這裏有一個單線程程序),這意味着它指向的對象將具有零引用指向它:這意味着該對象符合垃圾收集條件。這個垃圾收集是否在這個時候發生 - 我不知道我害怕。

但我會說:在垃圾收集發生的時候,您的編碼示例沒有區別;不管'指針類型'是否已經在循環外部定義爲'對象',或者在循環內重複定義。

以下(無用)的例子也許有助於說明之間的區別「創建-AN-對象」和「點一個引用的行爲,代碼將一氣呵成:

// 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; 
} 
} 
} 
+0

更正:這些語句都不會創建新對象,因爲引用String文字不會創建新對象。 –

+0

更改爲一般對象而不是字符串... – monojohnny

3

據我所知 - 在更大的應用程序(在此),但更大的是更好地使用static block創建對象 - 因爲當類被加載到內存中的靜態塊的代碼只執行一次。從技術上講,你可以可以在一個類中的多個靜態塊,雖然它並沒有多大意義

記住:Static block can access only static variables and methods

+0

使用靜態任何東西而不仔細考慮它是非常不明智的。 –

+0

@熱舔 - 感謝您的意見。 – DRastislav

+0

由40年編程支持的意見。 –

2

它是所有關於範圍,

如果你做你的第二個辦法:

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

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


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

對象將在存儲器直到someFunction而對於第一方法的端部存在的,它的生命週期循環的單次迭代內