java不可变对象问题 [英] java immutable object question
问题描述
字符串abc [] = {"abc"};字符串def [] = {};def = abc;def [0] = def [0] +更改";System.out.println(abc [0]);
通过更改"def"对象,我的abc对象也被更改.在String []数组旁边有这个特性还有什么其他的Java对象有类似的特性?能解释更多吗?为了防止在我更改def时更改abc,我将必须执行def = abc.clone();
您将对象的可变性/不可变性与引用值的复制混淆了.
在这些图中, [var/index]
是参考变量,而 {{an Object}}
是对象.
字符串abc [] = {"abc"};字符串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]}}
在这一点上,长度为零的数组是未引用的,并且应该是可垃圾回收的.我们可以将讨论范围缩小到长度为1的数组.请注意, String []
是引用数组.在下一行中,您更改了一个数组指向的长度中唯一的元素.
def [0] = def [0] +已更改";[abc] ------>{{a String [1]}}/[0] --------- \ {{a String"abc"}}/\[def] ---/\->{{一个字符串"abcchanged"}}
请注意, {{一个字符串"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]);//打印"Hello world!"
这次我不会为您绘制图表,但是您可以轻松地将其绘制在纸上.这里发生的是即使 clone()
使用其自己的元素(即 def!= abc)创建了第二个
),则该元素指向相同的 {{a StringBuilder [1]}}
对象 {{a StringBuilder}}
对象(即 def [0] == abc [0]
).>
简而言之:
- 不可变性意味着某种类型的对象不能以任何有意义的方式改变给外部观察者
-
整数
,字符串
等是不可变的 - 通常所有值类型应为
-
- 数组对象是可变的
- 它可能是对不可变类型的引用的数组,但是该数组本身是可变的
- 这意味着您可以将这些引用设置为所需的任何内容
- 对于基元数组也是如此
- 不可变数组不可行
- 它可能是对不可变类型的引用的数组,但是该数组本身是可变的
- 可以共享对对象的引用
- 如果对象是可变的,则通过所有这些引用都可以看到突变
如果您想更深入地了解这些问题,建议您采取以下措施:
- Java是否通过引用传递?-不!
- Java函数参数是否总是按值传递?-是的!
String abc[]={"abc"};
String def[]={};
def=abc;
def[0]=def[0]+"changed";
System.out.println(abc[0]);
by changing "def" object, my abc object is changed as well. Beside String[] array has this characteristic what other java object has similar characteristic? can explain more? in order to prevent abc from changed when i changed def, i will have to do def = abc.clone();
You are confusing object mutability/immutability with copying of reference values.
In these diagrams, [var/index]
is a reference variable, and {{an Object}}
is an object.
String abc[]={"abc"};
String def[]={};
[abc] ------> {{a String[1]}}
[0] --------------> {{a String "abc"}}
[def] ------> {{a String[0]}}
Now you make def
reference variable points to the same object as abc
reference variable:
def=abc;
[abc] ------> {{a String[1]}}
/ [0] --------------> {{a String "abc"}}
/
[def] ---/ {{a String[0]}}
At this point, the array of length zero is unreferenced, and should be garbage-collectable. We can narrow our discussion to the array of length one. Note that a String[]
is an array of references. With this next line, you changed what the only element in the length one array points to.
def[0]=def[0]+"changed";
[abc] ------> {{a String[1]}}
/ [0] ---------\ {{a String "abc"}}
/ \
[def] ---/ \--> {{a String "abcchanged"}}
Note that {{a String "abc"}}
itself was not mutated. [abc]
and [def]
now points to the same {{a String[1]}}
, which is mutable (i.e. you can make the elements of the array, which are references to String
objects, to point to anything).
in order to prevent
abc
from changed when i changeddef
, i will have to dodef = abc.clone()
;
Actually, that's not quite accurate. Let's see what happens if you clone()
an array of references to a mutable type StringBuilder
.
StringBuilder[] abc = new StringBuilder[] { new StringBuilder("Hello") };
StringBuilder[] def = abc.clone();
def[0].append(" world!");
System.out.println(abc[0]); // prints "Hello world!"
I won't make the diagrams for you this time, but you can easily draw it out on paper. What's happening here is that even though clone()
makes a second {{a StringBuilder[1]}}
object with its own element (i.e. def != abc
), that element is pointing to the same {{a StringBuilder}}
object (i.e. def[0] == abc[0]
).
In short:
- Immutability means that objects of a certain type can not change in any meaningful way to outside observers
Integer
,String
, etc are immutable- Generally all value types should be
- Array objects are mutable
- It may be an array of references to immutable types, but the array itself is mutable
- Meaning you can set those references to anything you want
- Also true for array of primitives
- An immutable array will not be practical
- It may be an array of references to immutable types, but the array itself is mutable
- References to objects can be shared
- If the object is mutable, mutation will be seen through all these references
If you want more in-depth understanding of the issues, I recommend the following:
这篇关于java不可变对象问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!