繁体   English   中英

对Java的传值和不变性的困惑

[英]Confusion over Java's pass-by-value and immutability

为了准备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");
    }
}

问题 :只有不可变对象以这种方式运行,并且可变对象可以通过值传递引用进行修改吗? 我的理解是正确的还是在这种行为中有其他好处?

在语言级别上,可变对象和可变对象之间没有区别 - 不变性纯粹是类API的属性。

这个事实只是被自动装箱所困扰,它允许++在包装器类型上使用,使它看起来像对象的操作 - 但它并不是真的,因为你已经注意到了自己。 相反,它是用于将值转换为基元的语法糖,将其递增,将结果转换回包装类型并将该引用分配给变量。

因此区别在于++运算符在基元和包装器上使用时的作用之间的区别,它与参数传递没有任何关系。

Java本身不知道对象是否是不可变的。 在每种情况下,都传递参数的 ,该是引用值或原始值。 更改参数的值永远不会产生任何影响。

现在,为了澄清,此代码不会更改参数的值:

localSb.append(" world");

这会更改参数值引用的对象内的数据,这是非常不同的。 请注意,您没有为localSb分配新值。

从根本上说,你需要了解:

  • 表达式(变量,参数,参数等)的值始终是引用值或原始值。 永远不是一个对象。
  • Java 总是使用按值传递语义。 参数的值成为参数的初始值。

一旦仔细思考这些事情,并在脑海中分离出“变量”,“价值”和“对象”的概念,事情就会变得更加清晰。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM