0

跟随程序输出

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);
    }
}
4

4 回答 4

2

当你传递vsecond时,通过值传递的是存储在中的引用v。回想一下,Java 只有引用类型,没有像 C++ 这样的对象类型。在内部second,当您执行时,它会更改本地变量inv.i = 20;引用的同一对象。即使在内部重新分配参数,该更改仍然存在。vfirstvsecond

于 2012-05-25T05:45:35.863 回答
1

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

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

因此更改vin 方法的实例变量second不会返回给方法的调用者,除非该方法返回更改的对象。你的方法在这里返回一个void

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

查看以下示例以了解差异。我已经包含了third' and a第四种方法,以进一步解释它。

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

如果你真的想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

希望这对您有所帮助。

其他参考:

  1. Java 是按引用传递还是按值传递?
  2. java是通过引用传递的吗?(关于 SO 的帖子)
于 2012-05-25T09:19:56.317 回答
0

Java中的所有参数都是值参数。调用方法时second:JVM会将对象复制vv1v1具有相同的指向v。当你分配

1,当你设置时,和v.i = 20的值变成20(因为这些对象有相同的指针)vv1

2, v = new Value();

这意味着您v1 = new Value(); 此时分配, v1 和 v 有不同的指针。

调用 method 后second, v 的值为 20(步骤 1)。

于 2013-07-10T03:28:24.263 回答
0

让我试着用一个比喻来解释

想象一下,你的价值对象是一个真实的对象——一张上面写着数字 15 的纸。你把那张纸给一个叫“First”的朋友。首先将那张纸放在一边,得到一张新纸,上面写着 15,但划掉 15 并在上面写上 25。

他把这第二张纸给了另一个名叫“第二”的朋友。Second 拿了那张纸,把 First 写的 25 划掉,然后在上面写 20。然后他拿起另一张带有数字“15”的纸给你看——你看到了数字 15。然后你让 First 给你看他给 Second 的那张纸。你看到它说“20”

于 2012-05-25T06:43:27.297 回答