Java將一個List賦值給另一個List的問題

       最近在寫代碼的時候發現一個問題:我定義了兩個List集合A,B,先對第一個集合A add數據進去,接着直接將A的數據賦值給B,結果後面我將集合A給clear掉,然後使用B集合的數據,結果報了數組越界異常。

最後發現集合B的數據也不存在了。測試代碼如下:

List<String> A =new ArrayList<>();
List<String> B =new ArrayList<>();

 A.add("111");
 A.add("222");
 A.add("333");

 B=A;
 System.out.println("A:"+A);
 System.out.println("B:"+B);

 A.clear();
        
 System.out.println("A:"+A);
 System.out.println("B:"+B);

輸出結果爲:

A:[111, 222, 333]
B:[111, 222, 333]
A:[]
B:[]

 看到這個結果我納悶了好久,我明明沒有將集合B的數據給刪掉,只刪除了A的數據,爲什麼B的數據也沒了。於是我猜測:

在用B=A 這個方式對集合B進行復制時將集合A對應的地址賦給了集合B,並不是單純的將集合A的數據賦給集合B。在對A進行clear操作時將A對應的存儲空間也就是地址給刪除了,那麼存儲空間裏的數據也就隨之刪除了。而B指向的地址又是A對應的地址,那麼B裏面的數據也就沒有了。

爲了印證我的猜測,我查找相關資料後得知:

Java中 "="的作用有兩個:

1.賦值

2.指向地址

那麼這兩個作用具體什麼情況下起什麼作用呢?答案如下:

當對基本數據類型進行賦值時 "="的作用就是單純的賦值,例如:int i=1,int j=2;

而當對引用數據類型進行賦值時"="的作用就是將被賦值對象的地址指向賦值對象的地址,例如:

List<String> A =new ArrayList<>();
List<String> B =new ArrayList<>();
A=B;

這裏插入講一下Java堆、棧、常量池的區別:

棧:一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配,但對象本身不存放在棧中,而是存放在堆(new出來的對象)或者常量池中(對象可能在常量池裏)(字符串常量對象存放在常量池中。)
堆:存放new 出來的對象。
常量池:存放字符串常量和基本類型常量(public static final)。

對於棧和常量池中的對象可以共享,對於堆中的對象不可以共享。

注意看上面對棧的描述,當我們定義兩個List集合A,B的時候,集合A,B是引用數據類型,那麼他們的引用先是在棧內存中分配,而對象本身是在進行new操作的時候存放在堆內存中,由堆進行內存分配。所以我們用B=A這種方式對集合B進行賦值時其實是將A的引用賦值給B,也就是說B指向了A的地址。當對A或是對B進行數據clear,add等操作時相應的B或A中的數據也會發生對應的變化。

最後,如果要將一個List集合賦值給另一個List集合,並且操作其中一個集合不會影響另一個集合時,可以用以下幾種方法:

//方法一
ArrayList B = new ArrayList<> (A);

//方法二
B.addAll(A);

//方法三
B = A.clone();

//方法四
for(String s: A)
 B.add(s);

此次出現的問題糾結了我好久,其實也都是很基礎的問題,但平時不怎麼注意,導致浪費大量時間找尋bug。所以一定要注重基礎啊。

特在此記錄以下!

 

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