Java中对象传摘引与生命周期的结合

Java中对象传引用与生命周期的结合

Java中变量的传递, 是传值, 还是传引用?

之前我对这个"经典"问题, 认识很不深刻. 直到我在项目中遇到类似下面的问题:

示例A:

List<Person> perList = new ArrayList<Person>();

for (int i = 0; i < idList.length(); i++) {
	Person person = new Person();
	//设置属性
	person.setId(i+1);
	person.setName("Lin");
	person.setAge(10);
	//添加到List中
	perList.add(person);
}
示例B:

List<Person> perList = new ArrayList<Person>();

Person person = new Person();
for (int i = 0; i < idList.length(); i++) {	
	//设置属性
	person.setId(i+1);
	person.setName("Lin");
	person.setAge(10);
	//添加到List中
	perList.add(person);
}
极为相似的两段代码, 却有着极为不同的经历:

示例A中 person 对象在for循环中创建, 它的生命周期仅限于for循环, 一出for循环则销毁, 因此new了idList.length()个person对象, 并把每个person添加到perList中. 因此,perList中是idList.length()个,id分别为1~n的person.(想象:点名,从1到n)

而在示例B中,person对象在for循环外创建. 示例B的结果是perList中为idList.length()个id为n的person.

这是为什么呢?

java中对象类型(Object)的变量传的是引用, 第一次循环, person.setId(1),然后添加到perList中, 第二次循环, 还是同一个person对象, person.setId(2), 相当于把person的id修改为2, 然后添加到perList中. 而之前放到perList中的person, 存放的是指向person的一个引用, person对象已经被修改了,自然之前的"值"也就更新了.因此,一套循环跑下来,perList中放了idList.length()个id为n的person对象.(也就是同一个人叫了n次)

思索:Java中变量是如何传递的?传值,还是传引用?什么时候传值,又是什么时候传引用呢?

Java中,当向一个方法传递基本数据类型时,采用的是"传值".即传递的只是该数据内容的一个副本.因此无论方法针对该副本值做怎样的改变,都不会影响到被传入的数据本身; 传入对象数据类型时,采用的是"传引用".即传入的是对象的一个引用,而不是对象本身(对象内容), 方法的改变不会影响"引用关系", 但却有可能改变被传入引用变量所引用的对象的内容.

解析:

JAVA中基本数据类型是在系统的栈中创建的, 而对象型数据则是在堆中创建的. 位于栈中的基本数据类型简化了调用机制, 可以被直接调用而没有引用的概念, 同时也抛弃了作为对象可以带来复杂属性设置的好处, 属于轻装上阵, 因而运行效率高; 对象型数据正好相反, 尽管运行效率低于前者, 但可以向用户提供作为对象带来属性设置的好处, 不过, 用户必须也只能通过对象的引用变量来实现对对象内容的访问, 不能象基本数据类型那样直接访问对象内容.

总结:

基本数据类型, 传值, 方法的改变不会影响传入的变量值; 对象数据类型,传引用, 方法的改变有可能会修改对象内容. 我们如何结合对象的生命周期做到对对象变量的掌控自如.

2楼lb858585851小时前
基本类型的封装类型也是值传递。例如:Integer,Double等。nString也可以理解为值传递,其实它是按照地址传递,只是其内容不可被修改。有改变将产生新对象。n为了避免总是产生新对象,采用stringbuilder来拼接字符串。
1楼lfmilaoshi昨天 20:03
早就应该体会的,早晚要补课的n米老师