当前位置: 首页 > 科技观察

Java深度学习系列之值传递还是引用传递?

时间:2023-03-12 18:38:04 科技观察

先来看一个新手,甚至是写了多年Java的朋友可能不太确定的问题:在Java方法中传递参数时,是按引用传递还是按值传递?为了说明这个问题,我给出了一个非常简单的类定义:}下面在明确观点的时候可能会重复多次使用这个类。关于Java中按值传递还是按引用传递,至少从表达的角度来看,两种观点都有支持的论点。我来一一分析:观点一:传递引用的原因如下:先看一段代码[]args){FoofooRef=newFoo("a");//lineAAAmodifyReference(fooRef);//lineBBBSystem.out.println(fooRef.getAttribute());//输出c}}上面的例子,输出是"c”,而不是“c”。我们在AAA行创建了一个新的对象Foo,并在BBB行将其引用fooRef传递给方法modifyReference()的参数cRef。经过这个方法的内部处理,fooRef指向的Object中的值从“a”变成了“c”,但是对fooRef的引用还是同一个引用,那么,我们是否可以认为引用传递发生在第BB?我们先保留疑惑,继续往下看。观点二:值传递继续看一段代码A”);//lineAAAchangeReference(fooRef);//lineBBBSystem.out.println(fooRef.getAttribute());//输出a}}上面的例子,输出的是“a”,不是“b”。我们在AAA行创建了一个新的对象Foo,并在EEE行将其引用fooRef传递给方法changeReference()的参数aRef,并且在DDD行重新分配了该方法的内部引用aRef。如果是引用传递,那么引用aRef已经指向了EEE行的一个新对象,输出应该是“b”,它到底是什么?实际上,输出的是“b”,也就是说,changeReference()方法改变了传入的引用所引用的对象的值。视点一和视点二的输出结果会有些混乱,别着急,我们继续往下看。深入分析为了详细分析这个问题,结合上面两段代码:“b”);//lineFFFaRef=bRef;//lineEEE}publicstaticvoidmain(String[]args){FoofooRef=newFoo("a");//lineAAAAchangeReference(fooRef);//lineBBBSystem.out.println(fooRef.getAttribute());//OutputamodifyReference(fooRef);//lineCCCSystem.out.println(fooRef.getAttribute());//Outputc}}下面我们深入到里面详细分析一下reference和Object内部的变化。看下图:①AAA行,声明一个名为fooRef的引用,类型为Foo,可以看到它被赋值给了一个新的对象,该对象的属性值为“f”,对象类型为Foo。FoofooRef=newFoo("a");//lineAAA②LineDDD,方法内部,声明了一个名为aRef的Foo类型的引用,aRef初始化为null。voidchangeReference(Fooa);③CCC行,调用changeReference()方法后,将引用aRef赋值给fooRef指向的对象。changeReference(fooRef);④FFF行,声明一个名为bRef、类型为Foo的引用,并将其赋值给一个属性值为“b”、类型为Foo的新对象。FoobRef=newFoo("b");⑤EEE行,将引用aRef重新分配给包含属性“b”的对象。注意这里不是重新赋值fooRef,而是aRef。aRef=bRef;⑥CCC行,调用方法modifyReference(FoocRef)后,新建一个引用cRef,赋值给包含属性“f”的对象,同时被两个引用fooRef和cRef指向.modifyReference(fooRef);⑦LineDDD,cRef.setAttribute("c");会将cRef引用更改为包含属性“f”的对象,并且该对象也由引用fooRef指向。cRef.setAttribute("c");此时,引用fooRef指向的对象的内部属性值“f”也被重置为“c”。总结一下,Java内部方法参数传递不是引用传递,而是传递引用本身的“值”。说到底,还是传值。将一个对象的引用fooRef传递给方法的形参newRef,会为该对象添加一个新的引用,相当于添加了一个别名。我们可以通过原始引用fooRef,或者方法参数中的新引用newRef来访问和操作原始对象,也可以在参数中改变引用newRef本身的值,但是不能改变原始引用的值fooRef.