java对象引用在方法中更改并理解结果
以下程序输出
In second vi:15 In first vi:20
为什么它在两种情况下都不是15.在第二种方法中传递了Value的Object,然后在第二种方法中更改了对象引用。第二种方法应该是它应该是15并且看起来像在First方法中它应该也是15
public class Test { /** * @param args */ class Value{ public int i = 15; } public static void main(String[] args) { Test t = new Test(); t.first(); } public void first(){ Value v = new Value(); vi = 25; second(v); System.out.println("In First vi:" + vi); } public void second(Value v){ vi = 20; Value val = new Value(); v = val; System.out.println("In second vi:" + vi); } }
Java方法实现是call by
[reference to, in case of objects,]
value
call by reference
而不是call by reference
。
您正在传递对象Value v
表示内联,方法范围变量v
指的是在方法first()
创建的对象v
。 这意味着对v
引用的同一对象的任何修改也将反映在调用结束时。 但是,在second
方法中,您正在为Value
创建一个新对象,但指向方法范围变量v
。 此新对象的内存位置与方法参数中传递的内容位置不同。 要识别差异,请检查使用其引用变量创建的对象的hashCode
。
因此,在方法second
更改v
的实例变量将不会返回给方法的调用者,除非该方法返回更改的对象。 您的方法在此处返回void
。
大多数情况下,程序员会对调用者和被调用方法中使用的相同引用名称感到困惑。
请查看以下示例以了解其中的差异。 我已经包括了third' and a
第四种方法,以进一步解释它。
public class Test { class Value { int i = 15; } public void second( Value v ) { System.out.println( " 2.1.1: entered: vi = " + vi ); // 25 System.out.println( " 2.1.2: v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); v = new Value(); vi = 9; System.out.println( " 2.2.1: new V: vi = " + vi ); // 9 System.out.println( " 2.2.2: v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); } // second(v) public Value third( Value v ) { System.out.println( " 3.1.1: entered: vi = " + vi ); // 25 System.out.println( " 3.1.2: v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); v = new Value(); vi = 9; System.out.println( " 3.2.1: created: vi = " + vi ); // 9 System.out.println( " 3.2.2: v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); return v; } // third(v) public Value fourth( final Value v ) { System.out.println( " 4.1.1:entered: vi = " + vi ); // 9 System.out.println( " 4.1.2:v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); /********************************** // The final local v can't be assigned. It must be blank and not using a compound assignment. // meaning, you are not allowed to change its memory location, // but can alter its content, if permitted // v = new Value(); //**********************************/ vi = 45; System.out.println( " 4.2.1:changed: vi = " + vi ); // 45 System.out.println( " 4.2.2:v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); return v; } // fourth(v) public void first() { System.out.println( "1.1.1: entered: ..." ); Value v = new Value(); System.out.println( "1.2.1: created; vi = " + vi ); // 15 vi = 25; System.out.println( "1.2.2: changed: vi = " + vi ); // 25 System.out.println(); System.out.println( "1.3.1: before calling second(v) ..." ); System.out.println( " vi = " + vi + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); second( v ); System.out.println( "1.3.2: returning from second(v) ..." ); System.out.println( " vi = " + vi + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); System.out.println(); System.out.println( "1.4.1: before calling third(v) ..." ); System.out.println( " vi = " + vi + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); v = third( v ); System.out.println( "1.4.2: returning from third(v) ..." ); System.out.println( " vi = " + vi + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); System.out.println(); System.out.println( "1.5.1: before calling fourth(v) ..." ); System.out.println( " vi = " + vi + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); v = fourth( v ); System.out.println( "1.5.2: returning from fourth(v) ..." ); System.out.println( " vi = " + vi + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() ); } // first() public static void main( String ... a ) { Test _this = new Test(); _this.first(); } // psvm(...) } // class Test
运行上面的示例时,您可能会看到如下输出:
1.1.1: entered: ... 1.2.1: created; vi = 15 1.2.2: changed: vi = 25 1.3.1: before calling second(v) ... vi = 25, v.hashCode() = 1671711; v = Test$Value@19821f 2.1.1: entered: vi = 25 2.1.2: v.hashCode() = 1671711; v = Test$Value@19821f 2.2.1: new V: vi = 9 2.2.2: v.hashCode() = 11394033; v = Test$Value@addbf1 1.3.2: returning from second(v) ... vi = 25, v.hashCode() = 1671711; v = Test$Value@19821f 1.4.1: before calling third(v) ... vi = 25, v.hashCode() = 1671711; v = Test$Value@19821f 3.1.1: entered: vi = 25 3.1.2: v.hashCode() = 1671711; v = Test$Value@19821f 3.2.1: created: vi = 9 3.2.2: v.hashCode() = 4384790; v = Test$Value@42e816 1.4.2: returning from third(v) ... vi = 9, v.hashCode() = 4384790; v = Test$Value@42e816 1.5.1: before calling fourth(v) ... vi = 9, v.hashCode() = 4384790; v = Test$Value@42e816 4.1.1:entered: vi = 9 4.1.2:v.hashCode() = 4384790; v = Test$Value@42e816 4.2.1:changed: vi = 45 4.2.2:v.hashCode() = 4384790; v = Test$Value@42e816 1.5.2: returning from fourth(v) ... vi = 45, v.hashCode() = 4384790; v = Test$Value@42e816
如果你真的想要在被调用的方法中保存对象instanceVariableV
所做的更改,比如说fifth()
,另一种可能性就是将v
声明为实例变量 。
以下示例将解释差异。
public class Test { Value instanceVariableV = null; // v // rest of other variables and methods here // ... public void fifth() { System.out.println( " 5.1.1:entered: instanceVariableV = " + instanceVariableV ); // null // null, hence no hashCode(), and no toString() will work // let us create an instance of Value instanceVariableV = new Value(); System.out.println( " 5.2.1:created: instanceVariableV = " + instanceVariableV ); // Test$Value@9304b1 System.out.println( " 5.2.2: instanceVariableV.i = " + instanceVariableV.i ); // 15 System.out.println( " 5.2.3: hashCode = " + instanceVariableV.hashCode() ); // 9634993 instanceVariableV.i = 20; System.out.println( " 5.3.1:changed: instanceVariableV.i = " + instanceVariableV.i ); // 20 System.out.println( " 5.3.2: hashCode = " + instanceVariableV.hashCode() ); // 9634993 // not changed } // fifth() public void first() { // continuation of code System.out.println( "1.6.1: before calling fifth() ..." ); System.out.println( " instanceVariableV = " + instanceVariableV ); fifth(); System.out.println( "1.6.2: returning from fifth() ..." ); System.out.println( " instanceVariableV = " + instanceVariableV ); if ( instanceVariableV != null ) { // must be different from the one when created new System.out.println( " .i = " + instanceVariableV.i ); // this won't differ System.out.println( " .hashCode() = " + instanceVariableV.hashCode() ); } } // first() public static void main( String ... a ) { // ... System.out.println( "\r\nmain(...): vInstanceVariable = " + _this.instanceVariableV ); if ( _this.instanceVariableV != null ) { // must be different from the one when created new System.out.println( " .i = " + _this.instanceVariableV.i ); // this won't differ System.out.println( " .hashCode() = " + _this.instanceVariableV.hashCode() ); } } // psvm(...)
当您使用上面的扩展示例运行时,您可能会看到如下输出:
1.6.1: before calling fifth() ... instanceVariableV = null 5.1.1:entered: instanceVariableV = null 5.2.1:created: instanceVariableV = Test$Value@9304b1 5.2.2: instanceVariableV.i = 15 5.2.3: hashCode = 9634993 5.3.1:changed: instanceVariableV.i = 20 5.3.2: hashCode = 9634993 1.6.2: returning from fifth() ... instanceVariableV = Test$Value@9304b1 .i = 20, .hashCode() = 9634993 main(...): vInstanceVariable = Test$Value@9304b1 .i = 20 .hashCode() = 9634993
希望这对你有所帮助。
其他参考:
- Java是通过引用传递还是通过值传递?
- java是通过引用传递的吗? (关于SO的post)
将v
传递给second
,按值传递的是存储在v
的引用 。 回想一下,Java只有引用类型,而不是像C ++这样的对象类型。 在second
,当你执行vi = 20;
,它首先更改局部变量v
引用的同一对象。 即使参数v
在second
内部重新分配,该更改仍然存在。
让我试着用类比来解释
想象一下,你的价值对象是一个真实的对象 – 一张写有数字15的纸。 你把那张纸给了一个名叫“First”的朋友。 首先把那张纸放在一边然后拿一张新纸,上面写着15张纸,然后将15张纸翻过去,然后写上25张。
他把这张第二张纸给另一位名叫“Second”的朋友。 第二张拿出那张纸,翻出了First写的25,并在其上写了20。 然后他拿起又一张数字为“15”的纸,向你展示 – 你看到的是15号。然后你问First给你看他给Second的那张纸。 你看它说“20”
Java中的所有参数都是值参数。 当您调用方法second
:JVM将v
对象复制到v1
, v1
具有与v
相同的指针。 当你分配
1,当你设置vi = 20
, v
和v1
的值变为20(因为这些对象具有相同的指针)
2, v = new Value()
;
这意味着你分配v1 = new Value();
此时,v1和v有不同的指针。
在调用方法second
,v的值为20(步骤1)。
- 阻止所有者窗口Java FX
- 此语言级别不支持intellijfunction(…)。 我无法编译
- 如何使用selenium webdriver在chrome中下载pdf文件
- BeanUtils copyProperties API忽略null和特定属性
- 在容器tomcat服务器上更改已部署(Spring Boot)战争的上下文路径。 所以它不是demo-0.01-SNAPSHOT
- `public class`和`class`之间有什么区别?
- 将Set <Map.Entry >转换为HashMap
- 构建错误:缺少工件com.sun:tools:jar:1.6
- 如何获取Pinterest V3 API-KEY或access_token