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();
答案 0 :(得分:13)
您将对象可变性/不可变性与复制参考值混淆。
在这些图表中,[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
个对象的引用)指向任何东西)。
为了防止在我更改
abc
时更改def
,我必须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()
使用自己的元素(即{{a StringBuilder[1]}}
)生成第二个def != abc
对象,该元素也指向同一个{{a StringBuilder}}
对象(即{ {1}})。
简而言之:
def[0] == abc[0]
,Integer
等是不可变的如果您想更深入地了解这些问题,我建议如下:
答案 1 :(得分:5)
不可变对象是一旦创建就无法更改的对象。 String
是一个明显的例子。数组是可变的。如果您想要一个不可变的集合,请使用List
代替:
List<String> abc = Collections.unmodifiableList(
Arrays.asList("abc")
);
可变对象有 mutators 。 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
且不可变的。 Date
是上述问题的一个很好的例子。 Date
不是一成不变的,许多人(包括我自己)认为这是设计错误。由于它是可变的,你必须进行大量的防御性复制。
答案 2 :(得分:5)
只是为了迂腐,没有“abc”对象或“def”对象。有单个String [] abc,然后def碰巧引用。这就是为什么“两个对象”都改变了。事实上,他们指的是同一个对象。
答案 3 :(得分:1)
简单来说就像这样: - 让我们假设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.
答案 4 :(得分:1)
在java中,无论数组的类型如何,您都可以随时更改数组中的元素。如果要将数据保存在数组结构中,请考虑单独创建数据副本以保护abc的初始值:
String abc[]={"abc"};
String def[];
def = Arrays.copyOf(abc, abc.length);
或者,使用cletus解决方案:
List abc = Collections.unmodifiableList(
Arrays.asList("abc")
);