问题

大家请看上面两张图,请问图1传入一个List,图2对这个List操作了,最后图1中的这个List会收到影响吗。

答案: 不会。

今天遇到这个代码的时候,发现在图2中对图1传递过来的List数据进行图2中的操作时,图1中的List并没有受到影响。

接下来,我们就谈一谈这个问题的原因,看看和你的想法是否一样?

解析

原因很简单: 当对象作为参数传递时,传递的是对象引用的值的拷贝意味着传递的是一个副本,而不是实际的对象引用本身。(值的拷贝)

这里我的描述很难懂,所以引用来自《On Java 》的描述。

  • Java传递任何事物时,都是在传递该事物的值,当你向方法传入基本类型时。得到的是该基本类型的一份单独的副本。而当你向方法传入一个引用时,得到的则是该引用的副本。

在Java中,对象是通过引用来访问和操作的,而不是直接通过对象本身。

这是啥意思呢?

意思就是: 在方法A中你需要一个参数叫 param1 的一个对象,实际传递的是这个 param1 对象的值的一个副本。

所以我们通过这个副本的值的引用来操作这个对象的值是可以的。(因为这个副本的值得引用实际就是指向了源对象的值的内存地址,所以操作这个副本时,就是操作的同一个内存地址。)

但是,如果我们在方法内部重新 new 了一个同类型的对象,并且对这个对象重新赋值,那么你实际上是对这个传递的副本的值的引用进行了重新赋值。那么并不会影响源对象的值的引用(因为你修改的是副本的值的引用地址)。

总结

当对象作为参数传递时,传递的是对象引用的值的拷贝。即传递的是引用的副本。这意味着在方法内部可以修改对象的属性,因为形式参数和实际参数引用的是同一个对象。但是无法通过方法内部改变实际参数引用的对象本身。

思考,为什么Java不选择传递真实对象,而是传递的对象引用的值的副本?该段落也可以叫做:为什么Java要使用值传递,而不是引用传递(在此说明,Java不存在真正的引用传递)

  1. 简单明确:值传递使得代码更加简洁和易于理解。我们可以清楚地知道方法内部对形参的修改不会影响到实参。

  2. 一致性:Java语言设计者希望参数传递的方式在所有情况下都是一致的。通过使用按值传递,无论是基本类型还是对象引用,都可以以相同的方式进行参数传递。

  3. 安全性:按值传递可以避免意外修改原始对象。如果Java使用真正的引用传递,那么在方法内部对传递进来的对象进行修改可能会导致意外的副作用,因为这样的修改会影响到原始对象本身。通过按值传递,可以避免这种意外的副作用。

  4. 性能:按值传递可以提高性能。如果Java使用真正的引用传递,那么在方法调用时需要传递对象的引用,这可能会涉及到更多的内存操作。通过按值传递,可以避免不必要的内存操作,从而提高性能。

参考文章

Java为什么不存在引用传递