java对象引用在方法中更改,并理解结果
跟踪程序输出java对象引用在方法中更改,并理解结果,java,object,Java,Object,跟踪程序输出 In second v.i:15 In first v.i:20 为什么在这两种情况下都不是15。传递值的对象,然后在第二个方法中更改对象引用。第二个方法应该是15,在第一个方法中看起来也应该是15 public class Test { /** * @param args */ class Value{ public int i = 15; } public static void main(String[]
In second v.i:15
In first v.i:20
为什么在这两种情况下都不是15。传递值的对象,然后在第二个方法中更改对象引用。第二个方法应该是15,在第一个方法中看起来也应该是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();
v.i = 25;
second(v);
System.out.println("In First v.i:" + v.i);
}
public void second(Value v){
v.i = 20;
Value val = new Value();
v = val;
System.out.println("In second v.i:" + v.i);
}
}
当您将
v
传递到second
时,通过值传递的是存储在v
中的引用。回想一下java只具有引用类型,而不是C++之类的对象类型。在second
内,当您执行v.i=20时
,它会更改本地变量v
在first
中引用的同一对象。即使参数v
在second
内重新分配,该更改仍然存在。当您将v
传递到second
时,通过值传递的是存储在v
中的引用。回想一下java只具有引用类型,而不是C++之类的对象类型。在second
内,当您执行v.i=20时
,它会更改本地变量v
在first
中引用的同一对象。即使参数v
在second
内重新分配,这种变化仍然存在。让我试着用一个类比来解释一下
假设你的价值对象是一个真实的对象——一张写有数字15的纸。你把那张纸给了一个叫“第一”的朋友。
首先把那张纸放在一边,得到一张新的纸,上面写着15,但是划掉15,在上面写着25
他把这第二张纸给了另一个叫“第二”的朋友。第二个拿着那张纸,划掉第一个写的25,改为写20。然后,他拿起另一张纸,上面写着数字“15”,向你展示——你看到了数字15。然后你让第一个给你看他给第二个的那张纸。你看,上面写着“20”让我试着用一个类比来解释 假设你的价值对象是一个真实的对象——一张写有数字15的纸。你把那张纸给了一个叫“第一”的朋友。 首先把那张纸放在一边,得到一张新的纸,上面写着15,但是划掉15,在上面写着25
他把这第二张纸给了另一个叫“第二”的朋友。第二个拿着那张纸,划掉第一个写的25,改为写20。然后,他拿起另一张纸,上面写着数字“15”,向你展示——你看到了数字15。然后你让第一个给你看他给第二个的那张纸。您可以看到,它说“20”Java方法实现是
通过调用[在对象的情况下,引用]
值
,但不完全是通过引用调用
您正在传递一个对象值v
意味着一个内嵌的方法范围变量v
引用在方法first()中创建的对象v
。这意味着v
引用的对同一对象的任何修改也将反映在调用端。但是,在您的第二个
方法中,您正在为值
创建一个新对象,但指向方法范围变量v
。此新对象的内存位置与传入的方法参数的内存位置不同。要识别差异,请检查使用引用变量创建的对象的hashCode
因此,在方法second
中更改v
的实例变量不会返回给方法的调用者,除非该方法返回更改的对象。您的方法在此处返回一个void
大多数情况下,程序员会对调用方和被调用方法中使用的相同引用名感到困惑
请看下面的示例以了解差异。为了进一步解释,我加入了一个third'和一个4th`方法
public class Test {
class Value {
int i = 15;
}
public void second( Value v ) {
System.out.println( " 2.1.1: entered: v.i = " + v.i ); // 25
System.out.println( " 2.1.2: v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
v = new Value();
v.i = 9;
System.out.println( " 2.2.1: new V: v.i = " + v.i ); // 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: v.i = " + v.i ); // 25
System.out.println( " 3.1.2: v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
v = new Value();
v.i = 9;
System.out.println( " 3.2.1: created: v.i = " + v.i ); // 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: v.i = " + v.i ); // 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();
//**********************************/
v.i = 45;
System.out.println( " 4.2.1:changed: v.i = " + v.i ); // 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; v.i = " + v.i ); // 15
v.i = 25;
System.out.println( "1.2.2: changed: v.i = " + v.i ); // 25
System.out.println();
System.out.println( "1.3.1: before calling second(v) ..." );
System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
second( v );
System.out.println( "1.3.2: returning from second(v) ..." );
System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
System.out.println();
System.out.println( "1.4.1: before calling third(v) ..." );
System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
v = third( v );
System.out.println( "1.4.2: returning from third(v) ..." );
System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
System.out.println();
System.out.println( "1.5.1: before calling fourth(v) ..." );
System.out.println( " v.i = " + v.i + ", v.hashCode() = " + v.hashCode() + "; v = " + v.toString() );
v = fourth( v );
System.out.println( "1.5.2: returning from fourth(v) ..." );
System.out.println( " v.i = " + v.i + ", 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; v.i = 15
1.2.2: changed: v.i = 25
1.3.1: before calling second(v) ...
v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f
2.1.1: entered: v.i = 25
2.1.2: v.hashCode() = 1671711; v = Test$Value@19821f
2.2.1: new V: v.i = 9
2.2.2: v.hashCode() = 11394033; v = Test$Value@addbf1
1.3.2: returning from second(v) ...
v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f
1.4.1: before calling third(v) ...
v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f
3.1.1: entered: v.i = 25
3.1.2: v.hashCode() = 1671711; v = Test$Value@19821f
3.2.1: created: v.i = 9
3.2.2: v.hashCode() = 4384790; v = Test$Value@42e816
1.4.2: returning from third(v) ...
v.i = 9, v.hashCode() = 4384790; v = Test$Value@42e816
1.5.1: before calling fourth(v) ...
v.i = 9, v.hashCode() = 4384790; v = Test$Value@42e816
4.1.1:entered: v.i = 9
4.1.2:v.hashCode() = 4384790; v = Test$Value@42e816
4.2.1:changed: v.i = 45
4.2.2:v.hashCode() = 4384790; v = Test$Value@42e816
1.5.2: returning from fourth(v) ...
v.i = 45, v.hashCode() = 4384790; v = Test$Value@42e816
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
如果您确实希望在调用的方法中保存对对象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.1.1: entered: ...
1.2.1: created; v.i = 15
1.2.2: changed: v.i = 25
1.3.1: before calling second(v) ...
v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f
2.1.1: entered: v.i = 25
2.1.2: v.hashCode() = 1671711; v = Test$Value@19821f
2.2.1: new V: v.i = 9
2.2.2: v.hashCode() = 11394033; v = Test$Value@addbf1
1.3.2: returning from second(v) ...
v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f
1.4.1: before calling third(v) ...
v.i = 25, v.hashCode() = 1671711; v = Test$Value@19821f
3.1.1: entered: v.i = 25
3.1.2: v.hashCode() = 1671711; v = Test$Value@19821f
3.2.1: created: v.i = 9
3.2.2: v.hashCode() = 4384790; v = Test$Value@42e816
1.4.2: returning from third(v) ...
v.i = 9, v.hashCode() = 4384790; v = Test$Value@42e816
1.5.1: before calling fourth(v) ...
v.i = 9, v.hashCode() = 4384790; v = Test$Value@42e816
4.1.1:entered: v.i = 9
4.1.2:v.hashCode() = 4384790; v = Test$Value@42e816
4.2.1:changed: v.i = 45
4.2.2:v.hashCode() = 4384790; v = Test$Value@42e816
1.5.2: returning from fourth(v) ...
v.i = 45, v.hashCode() = 4384790; v = Test$Value@42e816
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方法实现是callby
[reference to,如果是对象,]
value
,但不完全是callby reference
您正在传递一个对象值v
意味着一个内嵌的方法范围变量v
引用在方法first()中创建的对象v
。这意味着v
引用的对同一对象的任何修改也将反映在调用端。但是,在您的第二个
方法中,您正在为值
创建一个新对象,但指向方法范围变量v
。此新对象的内存位置与传入的方法参数的内存位置不同。要识别差异,请检查使用引用变量创建的对象的hashCode
因此,在方法second
中更改v
的实例变量不会返回给方法的调用者,除非该方法返回更改的对象。您的方法在此处返回一个void
大多数情况下,程序员会对调用方和被调用方法中使用的相同引用名感到困惑
请看下面的示例以了解差异。我包括了一个third'和一个4th`方法来解释