为了准备SCJP(或现在已知的OCPJP)考试,我被一些关于传递(参考)价值和不变性的模拟问题所困扰。
我的理解是,当你将一个变量传递给一个方法时,你会传递一个代表如何获取该变量的位的副本,而不是实际的对象本身。
您发送的副本指向同一个对象,因此您可以修改该对象(如果它是可变的),例如附加到StringBuilder。但是,如果对不可变对象执行某些操作(例如递增整数),则本地引用变量现在指向新对象,并且原始引用变量仍然无视此。
考虑我的例子:
public class PassByValueExperiment
{
public static void main(String[] args)
{
StringBuilder sb = new StringBuilder();
sb.append("hello");
doSomething(sb);
System.out.println(sb);
Integer i = 0;
System.out.println("i before method call : " + i);
doSomethingAgain(i);
System.out.println("i after method call: " + i);
}
private static void doSomethingAgain(Integer localI)
{
// Integer is immutable, so by incrementing it, localI refers to newly created object, not the existing one
localI++;
}
private static void doSomething(StringBuilder localSb)
{
// localSb is a different reference variable, but points to the same object on heap
localSb.append(" world");
}
}
问题:是否只有不可变对象以这种方式运行,并且可以通过值传递引用来修改可变对象?我的理解是正确的还是在这种行为中有其他好处?
答案 0 :(得分:6)
语言级别的可变对象和可变对象之间没有区别 - 不变性纯粹是类API的属性。
这个事实只是被自动装箱弄糊涂了,这允许++
在包装类型上使用,使它看起来像是对象的操作 - 但它并不是真的,因为你已经注意到了自己。相反,它是用于将值转换为基元的语法糖,将其递增,将结果转换回包装类型并将该引用分配给变量。
因此,++
运算符在基元和包装器上使用时的区别实际上是区别的,这与参数传递没有任何关系。
答案 1 :(得分:5)
Java本身不知道对象是否是不可变的。在每种情况下,都传递参数的值,它是引用值或原始值。更改参数的值永远不会产生任何影响。
现在,澄清一下,此代码不会更改参数的值:
localSb.append(" world");
这会更改参数值引用的对象内的数据,这是非常不同的。请注意,您没有为localSb
分配新值。
从根本上说,你需要理解:
一旦仔细思考这些事情,并在脑海中分离出“变量”,“价值”和“对象”的概念,事情就会变得更加清晰。