一直认为自己对对象传递理解的颇为深刻,没想到最近一次的编码中,就犯下了这样的错误,令自己排查了很久才找到问题的根源, 辅以小case记录以自省。

代码如下:

public class ObjReference {
String name = "ObjectReference";
String id = UUID.randomUUID().toString(); public ObjReference(){} public ObjReference(String name, String id){
this.name = name;
this.id = id;
} public String toSelfAttr(){
return "name = " + name + ", id = " + id;
} public void fillSelf(ObjReference obj){
/*System.out.println("old address: " + obj);*/
obj = cloneSelf();
/*System.out.println("after clone,it's address: " + obj);*/
} public ObjReference cloneSelf(){
ObjReference obj = new ObjReference(
"cloneSelf",UUID.randomUUID().toString());
/*System.out.println("clone ObjReference's address: " + obj.toString()
+ ", and its selfAttr: " + obj.toSelfAttr());*/
return obj;
} public static void main(String[] args){
ObjReference obj = new ObjReference();
System.out.println("old ObjReference's address: " + obj.toString()
+ ", and its selfAttr: " + obj.toSelfAttr());
obj.fillSelf(obj);
System.out.println("after filled, ObjReference's address: " + obj.toString()
+ ", and its selfAttr: " + obj.toSelfAttr());
} }

各位看官,运行结果会是如何? fillSelf()之后,对象本身属性改变是否会生效?  来看运行结果:

old ObjReference's address: com.chq.study.ObjReference@bb494b, and its selfAttr: name = ObjectReference, id = 91f17723-9227-461e-878e-51f7a3eedb0f
after filled, ObjReference's address: com.chq.study.ObjReference@bb494b, and its selfAttr: name = ObjectReference, id = 91f17723-9227-461e-878e-51f7a3eedb0f

我们会发现,对象地址没有改变(这个好理解,对象是按引用传递的),但出乎我预料的,对象属性也没有任何变化.... why?

放开fillSelf() & cloneSelf()的注释, 再次运行下,看看之间发生了什么。

old ObjReference's address: com.chq.study.ObjReference@1636e4e, and its selfAttr: name = ObjectReference, id = c10f9c98-8f15-4343-85db-7a85e21b22d7
old address: com.chq.study.ObjReference@1636e4e
clone ObjReference's address: com.chq.study.ObjReference@df0438, and its selfAttr: name = cloneSelf, id = eb117f7a-3463-4371-b723-4f43a041018d
after clone,it's address: com.chq.study.ObjReference@df0438
after filled, ObjReference's address: com.chq.study.ObjReference@1636e4e, and its selfAttr: name = ObjectReference, id = c10f9c98-8f15-4343-85db-7a85e21b22d7

橘黄色背景的,说明了最终结果没有变化。 青色背景的,说明对象在fill过程中,实际是有变化的,不仅是对象属性,其address也是发生了变化的。

既然address都已经变化了,那为何最终结果并没有体现出这种变化呢?这个说明了什么?

大家都知道的:对象传参时,是按引用传的,这个引用,指的是指向内存堆heap中实际对象的地址,所有对此对象的改变,实际是发生在heap中的那个实际对象体块上。

可这个解释不了示例中的现象,因为对象地址也是改变了的,虽然new了新对象,但我们确实将新对象的address返回并覆盖原对象地址了,那为何没有得到预期的结果?

大家未必知道的:对象引用传递时,对象引用本身是按值(by-value)传递的,是保存在thread stack上的,即copy了一份出来进行传递的,如同基本类型的传递。

所以虽然我们明确改变了对象引用指向的heap地址,以及传递对象本身的地址(是对象本身地址的copy,如同指针),但实际对象本身地址并未改变,所以最终结果不会有变化。

这同时也是我所犯下的错误。所以如果想使用类似此种实现,有两种办法:

1、原对象不要先指向任何对象(无论new还是null),仅声明并直接指向待构造新对象的方法即可(如: ObjReference obj2 = test.cloneSelf())

2、改变对象的方法中,还使用原来对象,不要new新的对象出来(确保对象引用本身没有变化,变化的仅是heap中的)

我们可以在main中屏蔽掉之前的代码,增加如下代码,进行方式1的验证:

    public static void main(String[]  args){
/*ObjReference obj = new ObjReference();
System.out.println("old ObjReference's address: " + obj.toString()
+ ", and its selfAttr: " + obj.toSelfAttr());
obj.fillSelf(obj);
System.out.println("after filled, ObjReference's address: " + obj.toString()
+ ", and its selfAttr: " + obj.toSelfAttr());*/
ObjReference test = new ObjReference();
ObjReference obj1 = null;
test.fillSelf(obj1);
System.out.println(null == obj1 ? "obj1 is null." :
"obj1 is : " + obj1.toSelfAttr());
ObjReference obj2 = test.cloneSelf();
System.out.println("obj2 is : " + obj2.toSelfAttr());
}

运行结果:

old address: null
clone ObjReference's address: com.chq.study.ObjReference@18e261d, and its selfAttr: name = cloneSelf, id = 37be891f-127c-4b70-a992-fa842d79ca2e
after clone,it's address: com.chq.study.ObjReference@18e261d
obj1 is null.
clone ObjReference's address: com.chq.study.ObjReference@1684706, and its selfAttr: name = cloneSelf, id = efc60431-d20a-4614-83ff-d3eaa018c41c
obj2 is : name = cloneSelf, id = efc60431-d20a-4614-83ff-d3eaa018c41c

我的一个疑问,盼高人指点: java中有可以查看对象引用本身地址(引用本身的指针)的方法或者工具么? 如有,可对此做更加强有力的支撑验证。

Java对象引用传递探索的更多相关文章

  1. java对象引用传递和值传递的一些总结

    1.对象作为函数的参数传递过去的时候,是以原对象的引用的方式传递的,更改参数对象的值,会影响原来的对象. 2.对象作为函数的返回值的时候,传递过来的也是一个引用传递,更改传递过来的对象的时候,会影响原 ...

  2. JAVA 对象引用,以及对象赋值

    注:引自http://zwmf.iteye.com/blog/1738574 关键字: java对象 引用 Java对象及其引用 关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里, ...

  3. JAVA 对象引用,以及对象赋值(转)

    原文链接:http://zwmf.iteye.com/blog/1738574 关键字: java对象 引用 Java对象及其引用 关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里 ...

  4. Java对象引用和对象赋值

    关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用,那实在没法很好 ...

  5. JAVA学习笔记之JAVA 对象引用以及赋值

      关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没 ...

  6. String 不变性以及 Java 值传递和引用传递

    String 不变性以及 Java 值传递和引用传递 public class Example { String str = new String("good"); char[] ...

  7. Java方法传递参数传值还是传址的问题

    这几天重构项目代码遇到一个疑问:可不可以在方法A中定义一个boolean变量b为false,然后A调用方法C把b传递到C方法中经过一些列业务判断后修改为true,C执行结束后A方法中b的值还是原来的f ...

  8. java对象与java对象引用的区别

    java对象与java对象引用的区别 对象与对象引用的区别 直接用例子说话吧 Person per = new Person("张三"); 这一条语句,其实包括了四个动作: 右边的 ...

  9. 老生常谈--Java值传递和引用传递

    起因 前两天面试被问到了这个问题,虽然之前老早就了解过这个问题,但是并没有深入了解,所以面试的时候一下子慌了,菜是原罪,今天菜鸡来补补基础知识. 其实这个问题一直是被讨论的,常见的三种说法就是,1,J ...

随机推荐

  1. java版云笔记(二)

    云笔记 基本的环境搭建好了,今天做些什么呢,第一是链接数据库(即搭建Spring-Batistas环境),第二是登录预注册. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下 ...

  2. ASP连接读写ACCESS数据库实例(转)

    (一)   数据库的选择:有许多的数据库你可以选择,SQL SERVER.ACCESS(*.mdb).EXCEL(*.xls).FOXPRO(*.dbf)甚至普通的文本文件(*.txt)都可以达到存储 ...

  3. IOS-优质应用推荐

    壁纸应用 cuto 免费 点击下载 shots 收费 点击下载 Cutisan 锁屏壁纸制作下载地址 待办事项 TodayMind - 提醒事项触手可及 点击下载 滴答清单 点击下载 Microsof ...

  4. python基础(7)--深浅拷贝、函数

    1.深浅拷贝 在Python中将一个变量的值传递给另外一个变量通常有三种:赋值.浅拷贝.深拷贝 Python数据类型可氛围基本数据类型包括整型.字符串.布尔及None等,还有一种由基本数据类型作为最基 ...

  5. 深度学习方法(十二):卷积神经网络结构变化——Spatial Transformer Networks

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.机器学习技术感兴趣的同学加入. 今天具体介绍一个Google ...

  6. MVC – 14.ajax异步请求

    14.1.配置文件 14.2.AjaxHelper – 异步链接按钮 14.3.AjaxHelper – 异步表单 AjaxOptions常见属性: 14.4.AjaxOptions对象生成[对应]触 ...

  7. 查看loadrunner代码行号

    运行前报错,如Syntax error on line 133 near ";"那么如何查看代码的行号呢?解决方法:看代码行号时,直接将鼠标在代码的某处单击,在窗体的最下方右侧能看 ...

  8. spring_150901_hibernate_transaction_xml

    实体类: package com.spring.model; import javax.persistence.Entity; import javax.persistence.Id; import ...

  9. Java 中(静态)变量、(静态)代码块的执行顺序

    Java 中(静态)变量.(静态)代码块的执行顺序 非原创 本文讨论 Java 中(静态)变量.(静态)代码块的执行顺序 首先创建 3 个类 1.Foo 类 public class Foo { pu ...

  10. 【记录】mybatis-generator如何使用(maven方式)

    1.首先在pom.xml中添加插件 <plugin> <groupId>org.mybatis.generator</groupId> <artifactId ...