最近在android项目中遇到了一个奇怪的问题,最终发现导致这个问题的原因不是androi机制问题,而是java基础行中的值传递问题,项目结束了来总结分享一下:
先说结论:
java中通过方法掉用只有值传递。
结论分析:
java中变量分为基本数据类型变量和引用类型变量,基本数据类型包括int、float这些,引用类型包括类(String/JavaBean等)、接口(List/ArrayList等)和数组。基本数据类型当做参数传递时候,实际是把实际参数的值拷贝了一份给形参,所以对形参的任何操作都不影响方法外部的实际参数值;而引用类型作为参数的实际是把应用类型变量的引用(即变量地址入口)拷贝了一个副本,用这个引用的副本作为形参,所以形参指向的地址和外部实际引用指向的地址相同,对形参指向的内容的修改就等于对外部实参的修改。
按值传递不再解释,大家都很清楚作为实际参数的外部变量是不会变的,下面两个测试程序说明一下引用传递:
验证程序1:
List<String> list1 = new ArrayList<String>();
list1.add("yang");
System.out.println("list1----original" + list1);
List<String> list2 = list1;
System.out.println("list1----before" + list1);
System.out.println("list2----before" + list2);
list2.add("chao");
System.out.println("list1----after" + list1);
System.out.println("list2----after" + list2);
输出结果1:
list1—-original[yang]
list1—-before[yang]
list2—-before[yang]
list1—-after[yang, chao]
list2—-after[yang, chao]
结果分析1:说明引用类型赋值本身就是使变量指向了同一个地址,对各自引用的参数都会影响到指向同一个地址的其它引用。
验证程序2:
import java.util.ArrayList;
import java.util.List;
public class TestClass {
public static void main(String[] args) throws Exception {
/* java中值传递和引用传递的问题 */
final List<String> list = new ArrayList<String>();
list.add("yang");
list.add("chao");
new Thread(new Runnable() {
public void run() {
/* 线程A,调用一次testValue方法,也就是只给temp_list付一次值,把list赋值给temp_list */
testValue(list);
}
}, "A").start();
/* 休息1秒 */
Thread.sleep(1000);
new Thread(new Runnable() {
public void run() {
/* 线程B,只是在主线程改变了list的值而已,并没有再次调用testValue方法,也没有再次赋值给temp_list */
list.clear(); list.add("XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
}
}, "B").start();
}
private static void testValue(List<String> list) {
List<String> temp_list = new ArrayList<String>();
temp_list = list;
while (true) {
for (int i = 0; i < temp_list.size(); i++) {
System.out.println("temp_list----" + temp_list.get(i));
}
}
}
}
输出结果2(截取log中间部分):
temp_list—-yang
temp_list—-chao
temp_list—-yang
temp_list—-chao
temp_list—-yang
temp_list—-chao
temp_list—-yang
temp_list—-chao
temp_list—-yang
temp_list—-chao
temp_list—-yang
temp_list—-chao
temp_list—-yang
temp_list—-chao
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
temp_list—-XXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
结果分析2:
从输出结果我们可以看出,当外部实参发生变化时,方法内部的变量也随即发生变化。说明我们通过方法参数传递的就是对象引用的副本,这个引用副本中的信息就是对象的内存地址,当赋值给方法内部的变量时就等于让方法内部变量也指向了同一个内存地址。