[英]java immutable object question
String abc[]={"abc"};
String def[]={};
def=abc;
def[0]=def[0]+"changed";
System.out.println(abc[0]);
通過更改“def”對象,我的abc對象也會被更改。 String []數組旁邊有哪些其他java對象具有相似特性的特性? 可以解釋一下嗎? 為了防止在我改變def時改變abc,我將不得不做def = abc.clone();
您將對象可變性/不可變性與復制參考值混淆。
在這些圖中, [var/index]
是一個引用變量, {{an Object}}
是一個對象。
String abc[]={"abc"};
String def[]={};
[abc] ------> {{a String[1]}}
[0] --------------> {{a String "abc"}}
[def] ------> {{a String[0]}}
現在,您將def
引用變量指向與abc
引用變量相同的對象:
def=abc;
[abc] ------> {{a String[1]}}
/ [0] --------------> {{a String "abc"}}
/
[def] ---/ {{a String[0]}}
此時,長度為零的數組未被引用,並且應該是可垃圾收集的。 我們可以將討論范圍縮小到長度為一的數組。 請注意, String[]
是一個引用數組。 在下一行中,您更改了一個數組指向的長度中唯一的元素。
def[0]=def[0]+"changed";
[abc] ------> {{a String[1]}}
/ [0] ---------\ {{a String "abc"}}
/ \
[def] ---/ \--> {{a String "abcchanged"}}
請注意{{a String "abc"}}
本身未發生變異。 [abc]
和[def]
現在指向相同的{{a String[1]}}
,這是可變的(即你可以使數組的元素,即String
對象的引用,指向任何東西)。
為了防止在我改變
def
時改變abc
,我將不得不做def = abc.clone()
;
實際上,這不太准確。 讓我們看看如果clone()
一個對可變類型StringBuilder
的引用數組會發生什么。
StringBuilder[] abc = new StringBuilder[] { new StringBuilder("Hello") };
StringBuilder[] def = abc.clone();
def[0].append(" world!");
System.out.println(abc[0]); // prints "Hello world!"
這次我不會為你制作圖表,但你可以很容易地在紙上畫出來。 這里發生的事情是,即使clone()
使用自己的元素(即def != abc
)生成第二個{{a StringBuilder[1]}}
對象,該元素也指向同一個{{a StringBuilder}}
對象(即def[0] == abc[0]
)。
簡而言之:
Integer
, String
等是不可變的 如果您想更深入地了解這些問題,我建議如下:
不可變對象是一旦創建就無法更改的對象。 String
是一個明顯的例子。 數組是可變的。 如果您想要一個不可變的集合,請改用List
:
List<String> abc = Collections.unmodifiableList(
Arrays.asList("abc")
);
可變對象有變異器 。 mutator是修改對象狀態的任何方法。 塞特斯是一個明顯的例子。 典型的不可變對象將如下所示:
public class Person {
private final String firstName;
private final String lastName;
private final Date dateOfBirth;
public Person(String firstName, String lastName, Date dateOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
this.dateOfBirth = new Date(dateOfBirth.getTime());
}
public String getFirstName() { return firstName; }
public String getLastname() { return lastName; }
public Date getDateOfBirth() { return new Date(dateOfBirth.getTime()); }
}
一般來說,對於不可變對象,所有成員都是final
和immutable。 Date
是上述問題的一個很好的例子。 Date
不是一成不變的,許多人(包括我自己)認為這是設計錯誤。 由於它是可變的,你必須進行大量的防御性復制。
只是為了迂腐,沒有“abc”對象或“def”對象。 有單個String [] abc,然后def碰巧引用。 這就是為什么“兩個對象”都改變了。 事實上,他們指的是同一個對象。
簡單來說就是這樣: - 假設Sample是一個類,那么,
Sample sam1 = new Sample();
將清楚地解釋為sam1是對創建的對象的引用。 但
Sample sam2;
只是聲明sam2是Sample類型的引用變量,並且它沒有指向Sample類的對象。 現在如果我們做這個操作
sam2 = sam1;
那么這意味着兩個引用變量都指向同一個對象,現在可以使用兩個引用中的任何一個來引用該對象。 顯然,可以使用任一參考文獻來使用有效方法來操縱字段。 這也是這里所做的。
String abc[]={"abc"};
String def[]={};
def=abc;
def[0]=def[0]+"changed";
所以改變def [0]也會改變abc [0]。
Now when you clone you are creating a clone of the existent object.
The clone and the cloned objects independently exist
as 2 different objects and so the result of manipulations on one
is not reflected as you stated.
在java中,無論數組的類型如何,您都可以隨時更改數組中的元素。 如果要將數據保存在數組結構中,請考慮單獨創建數據副本以保護abc的初始值:
String abc[]={"abc"};
String def[];
def = Arrays.copyOf(abc, abc.length);
或者,使用cletus解決方案:
List abc = Collections.unmodifiableList(
Arrays.asList("abc")
);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.