for循環內外創建對象

參考:https://www.cnblogs.com/qlqwjy/p/7598773.html

有時候奇怪的發現往list添加數據的時候,一直被最後一個元素覆蓋,首先 ,我們得明白原理:

  •  在new 一個對象的時候,對象的ID是唯一確定的;將對象add入list中時,放入list中的其實是對象的引用 ;而每次循環只是簡單  的set 對象的屬性,set新的屬性值,而add進list中的對象還是同一個對象id,也就是同一個對象;
  • 所以每次add之後,list發現對象引用和之前元素一樣,就覆蓋掉了之前add的對象。所以循環之後list中的對象是重複的對象。
  • 想要避免這個問題只要每次add時保證對象引用都是不同的即可,即每循環一次重新new一個對象。
  • new的對象應該放在for循環內,每循環一次重新new一個新對象
複製代碼
public class Test
{
public static void main(String[] args)
{
for(int i=0;i<10;i++)
{
Object obj = new Object();
}
}
}
複製代碼

它的確是在main方法棧中先後創建了10個引用叫obj,然後每個obj指向不同的new出來的對象。

關鍵是:每次循環體執行完後,循環體內定義的代碼塊局部變量、對象如果沒有被繼續引用,就立即被銷燬了;即obj變量、new出來的對象都被銷燬了。

 一般是循環一次一個新對象,所以如非必要,不要在循環裏面創建對象。(有其他的方法嘛???)

 

   用內存角度來解釋的話,在JVM的方法棧和堆內存這兩個內存中,當運行Object obj = new Object();時,在方法棧的棧頂中放入Object obj,然後在堆中生成一個Object對象,最後方法棧中的obj指向Object對象,這時完成一次循環的內存動作。接着第二次循環, new Object();又產生一個新的Object對象,然後方法棧中的obj指向新的Object對象,第一次循環的Object對象沒有被任務變量引用, 成爲了垃圾,等JVM垃圾回收器回收。其它循環以此類推了。
  在這裏我提一下題外話,JVM有個優秀的算法是,JVM的方法棧,一個方法的調用產生一個棧幀,這個棧幀在方法調用時計算出你有幾個局部變量,這個計算會 過濾作用域的,如你的循環後面再建立一個局部變量,那JVM認爲只有一個局部變量,因爲你的Object obj = new Object();在大括號內,出了大括號就沒有了,所以只需要一個位置來存放局部變量即可,也就是說運行到大括號時用這個位置來執行代碼,出了大括號後 下一個局部變量就可以接着使用這個棧的這個位置來執行下面的代碼了

 

 

再看一個例子:

複製代碼
import java.util.ArrayList;
import java.util.List;

public class WWWW {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List<Integer> nums_1 =new ArrayList<Integer>();
        List<Integer> nums_2 =new ArrayList<Integer>();
        long start_1 = System.currentTimeMillis();
        System.out.println("第一種方法開始:");
        Integer num = null;
        for(int i=0;i<10;i++){
       //十個引用十個對象 num = new Integer(i); nums_1.add(num); } long end_1 = System.currentTimeMillis(); System.out.println("程序結束,用時:"+(end_1-start_1)); long start_2 = System.currentTimeMillis(); System.out.println("第二種方法開始:"); for(int i=0;i<10;i++){
       //一個引用是個對象 Integer num1 = new Integer(i); nums_2.add(num1); } long end_2 = System.currentTimeMillis(); System.out.println("程序結束,用時:"+(end_2-start_2)); } }
複製代碼

 

結果:

第一種方法開始:
程序結束,用時:1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
第二種方法開始:
程序結束,用時:0
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

 

解釋:

 在for循環內部創建的話,每次執行循環都會創建對象,沒什麼特別明顯壞處,只是會消耗內存。所以我們通常在for循環外部實例化對象,因爲它執行一次

 Object obj是創建對象引用,引用的實例地址。 new Object();是創建對象實例
兩者都會佔用系統資源。
改進之前for循環中創建了10次引用和10實例,改進後是創建了1次引用,10實例。
在方法執行完後內存資源會被回收

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章