之前在代码中刚好遇到过同样的问题, 现在我自己举个例子来大概描叙一下情况:
import java.util.*; public class StringTest { public static void main(String[] args) { ArrayList list1 = new ArrayList; list1.add("1"); ArrayList list2 = new ArrayList; list2.add("2"); System.out.println("list1:" + list1.get(0)); System.out.println("list2:" + list2.get(0)); System.out.println("----------------"); swap(list1, list2); System.out.println("After invoking swap"); System.out.println("list1:" + list1.get(0)); System.out.println("list2:" + list2.get(0)); } static void swap(List l1, List l2) { List temp = l1; l1 = l2; l2 = temp; System.out.println("------swap begin-----"); System.out.println("l1:" + l1.get(0)); System.out.println("l2:" + l2.get(0)); System.out.println("------swap end-----"); } }
上诉例子中, 代码的意图是想着把list1 和 list2交换一下, 看代码运行结果:
为了进行分析, 我直接在swap方法体中加了输出语句.
可以看出, 结果是list1 和 list2的引用并没有发生交换.
在我以前的知识中, 会讲到各种作用域阿, 局部参数等的问题, 其实对于当初新手的我来说要记住这些东西是很麻烦的....在我接触到 值传递和引用传递这两个概念以及了解到java语言中是值传递的, 我就瞬间明白了上述运行结果中没有发生交换的原因.
值传递概念:表示方法接收的是调用者提供的值.得到的是参数值的一个拷贝.(这里概念来自于Core Java 卷一 第九版 方法参数这章)
首先, 用基本数据类型来解释下这个 值传递的概念:
public class CopyTest { public static void main(String[] args) { int x = 10; System.out.println(x); add(x); System.out.println("After add"); System.out.println(x); } static void add(int x) { x += 10; } }
运行结果:
运行结果是:x没有被改变值, 然后我在add方法最后面增加x的输出:
用图例分析:
其实在add方法里面, 我们操作的是参数x的值的一个拷贝(注意这里是值的拷贝),即copy of x, 在方法里面操作的都是copy of x, 所以并不影响原来x的值.
对于引用类型参数的传递, 的引用的拷贝.下面用图例分析开头的代码:
先说明下:如果对栈, 堆, 指针有些了解, 那么理解起来就很容易
从图例来看, swap方法里面获取得其实是来自于list1和list2的拷贝, 拷贝的是list1(0x00)内存块里面的值(0x10), 并不是把(0x00)传过去(其实这种就是引用传递).list2和l2也是同理
因此当l1 和 l2互换的时候, 换的是0x02 和 0x03内存块里面的内容, 所以在swap方法里面是, l1 和 l2 是已经发生交换了, 但是外部的list1 和 list2 并没有发生任何影响.
这里额外提一点, 假设swap方法如下:
static void (List l1, List l2) { l1.add("a"); l2.add("b"); }
那么外部的list1 和 list2肯定各自增加了"a", "b", 因为这里的l1 和 list1 指向的实例都是一样的.即l1 和 list1 对应的内存块里面存的值都是0x10. l2 和 list2也是同理.
如果不明白的话可以手动敲一下代码, 然后画图理解, 最重要的是稍微理解堆, 栈, 和java中关于指针的知识就行啦.
若有不对的地方, 请指正~thx
本文为头条号作者发布,不代表今日头条立场。