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();
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()
;
StringBuilder
的引用数组进行 clone()
会发生什么。 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}}
对象(即def [0] == abc [0]
)。
简而言之:
Integer
、String
等是不可变的如果您想更深入地了解这些问题,我推荐以下内容:
不可变对象是一旦创建就无法更改的对象。一个明显的例子是 String
。而数组是可变的。如果你想要一个不可变的集合,可以使用 List
。
List<String> abc = Collections.unmodifiableList(
Arrays.asList("abc")
);
可变对象有改变器。改变器指的是任何修改对象状态的方法。Setter 是一个明显的例子。一个典型的不可变对象如下:
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
不是不可变的,这被许多人(包括我自己)认为是一个设计错误。由于它是可变的,你必须进行大量的防御性复制。
仅仅是一点小题外话,没有“abc”对象或“def”对象。有一个String[]数组,abc和def恰好引用它。这就是为什么“两个对象”都改变了。事实上,它们指向的是同一个对象。
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.
String abc[]={"abc"};
String def[];
def = Arrays.copyOf(abc, abc.length);
或者,使用 cletus 的解决方案:
List abc = Collections.unmodifiableList(
Arrays.asList("abc")
);