java对象引用在方法中改变并理解结果 [英] java object reference is changed in a method and understanding the result

查看:44
本文介绍了java对象引用在方法中改变并理解结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下程序输出

In second v.i:15
In first v.i:20

为什么在这两种情况下都不是 15.传递值的对象,然后在第二个方法中更改对象引用.第二个方法应该是 15,看起来在第一个方法中它也应该是 15

why its not 15 in both cases.Object of Value is passed and then object reference is changed in the Second method.Second method its 15 as it should be and seems like in First method it should also be 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);
    }
}

推荐答案

Java 方法的实现是 call by[reference to, in case of objects,]value 但不完全是 call by reference.

Java method implementations are call by[reference to, in case of objects,]value but not exactly a call by reference.

您正在传递一个对象 Value v 意味着一个内嵌的方法范围变量 v 指的是在方法中创建的对象 vfirst().这意味着对 v 引用的同一对象的任何修改也将反映在调用端.但是,在您的 second 方法中,您正在为 Value 创建一个新对象,但指向方法范围变量 v.这个新对象的内存位置与传入的方法参数不同.要识别差异,请检查使用其引用变量创建的对象的 hashCode.

You are passing an object Value v means an in-line, method scope variable v is referring to the object v created in method first(). That means any modifications to the same object, referred by v, will also reflect at calling end. But, in your second method, you are creating a fresh object for Value but pointing to the method scope variable v. This new objects memory location is not the same as that of passed in method parameter. To identify the difference, check the hashCode of the objects created using their reference variables.

因此在方法 second 中更改 v 的实例变量将不会返回给方法的调用者,除非该方法返回更改后的对象.您的方法在此处返回 void.

And hence changing the instance variables of v in method second will not be returned to the caller of the method, unless the method is returning the altered object. Your method returns a void here.

大多数时候,程序员对调用者和被调用方法中使用的相同引用名称感到困惑.

Programmers, most of the time, get confused with the same reference names used in caller and called methods.

查看以下示例以了解差异.我已经包含了一个 third' 和一个 fourth` 方法,以进一步解释它.

Look at the following example to understand the difference. I have included a third' and afourth` methods, to explain it further.

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

当你运行上面的例子时,你可能会看到如下输出:

When you run the above example, you may see an output as below:

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

<小时>

如果你真的想在被调用的方法中保存对对象instanceVariableV所做的更改,比如fifth(),另一种可能是声明v 作为实例变量.


If you really want to hold the changes made to an object instanceVariableV in a called method, say fifth(), the other possibility is to declare v as instance variable.

以下示例将解释差异.

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(...)

当您运行上述扩展示例时,您可能会看到如下输出:

When you run with the above extended example, you may see an output as below:

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

希望对你有帮助.

其他参考:

  1. Java 是按引用传递还是按值传递?
  2. java 是通过引用传递的吗?(SO 上的帖子)

这篇关于java对象引用在方法中改变并理解结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆