课时5:对象引用分析
摘要:我们来进行引用传递分析。大家都知道,类本身属于引用数据类型,既然是引用数据类型,那就涉及到内存的引用传递。
内存引用传递其本质可以用一句话概括:同一块堆内存空间能够被不同的栈内存所指向。
下面来看这样一个程序。这是一个用于引用传递分析的程序。
我们来看代码,首先是“person per1=new person;”,相信大家对这句代码已经有了共识,有“new”关键字就是开辟空间,而且由于没设置内容,其内容都是默认值,这个过程跟相关代码是一样的,也就是开辟了名为“per1”的空间,大家应该能理解。之后再为其设置内容,最终的结果大家对照着应该也能清楚,就是这样一步步操作的。
准备部分完成后,我们开始后续部分。接下来这句话是最为关键的,那就是“person per2=per1;”,这就是引用传递。“per1”是“person”类型的,“per2”也是“person”类型的,同类型接收是可行的。接着,我们写“per2.h=80;”,代码至此完成,最终的结果就是“张三”和“80”,这里体现的就是引用传递。
下面我们再来对其做进一步的内存分析,大家认真看代码,代码会一行行往下走,我们按顺序来分析,整个流程和之前分析的形式基本一致,没什么差别。
接着Person per2=per1,这里要明确几点。首先,就像“int x=10;int y=x;”,意味着y的值就是10。同样,per1只是程序里的名字,在底层是通过地址来体现的,per1赋值给per2,那就意味着per2的地址和per1是相同的,也就是二者指向同一个空间。
当执行“per2.h=80;”时,是per2对这块共享空间进行了修改。这就好比一个人有大名和小名,不管用哪个称呼,指向的都是同一个人,一处改变另一处也受影响,所以最终结果就是“张三”和“80”,这体现的就是引用传递。
而且,这种引用传递不仅能直接在主方法中定义,也可以通过方法来实现引用传递,毕竟大家都知道方法是可以接收参数的。
我们来看利用方法实现引用传递处理的情况,还是以这个程序为例,代码做了一点改变,
比如给一个方法传入参数,在方法里进行像change(per)“temper.age=80;”这样的操作,这里与之前最大的差别在于,是将Person类的实例化对象传递到change()方法之中,而实例化对象的本质存的是内存地址。
因为传递的是Person类型,方法接收的也是Person类型,结果依然是“张三”和“80”,它等价于“Person temper=per;”,和之前情况一样。
下面通过内存图来分析,前面几步操作形成的图和之前基本是一样的,无非就是对象名字换了一下,没什么大区别。关键是从第三步开始用到了“change”这个方法,对应的就是处理方法即public static viod change(person temp),按照刚才分析的结果,现在就要开始具体的处理了。
在代码里有主方法和“change”方法这两个部分。主方法里有“per”,“change”方法里有“temper”,它们存的都是地址,这样整个代码的结构就清晰了。
后续进行调用时,相关操作在“change”方法里完成,比如在“change”方法里把对应的“age”(年龄)改成了80。
举个例子来说,程序是有执行单元的。当“temper”和“per”指向同一空间时,如果这个方法执行完毕了,“temper”会断开连接。
这其实就实现了引用传递,也就是说引用传递可以发生在方法上,这时一定要留意方法的参数类型,也要观察方法的执行过程,对于内存图得学会完整分析,大家要透彻理解才行。