【问题标题】:Java Pass By Value and referenceJava 按值传递和引用
【发布时间】:2015-11-26 06:36:52
【问题描述】:

我有以下代码。但是,我无法理解它关于按值传递和引用传递的行为。

class Dog{
    String name;
    int x=100;
    
    Dog(String name){
        this.name = name;
    }
    
    public String getName(){
        return this.name;
    }
}
class Demo{
    public static void main( String[] args ){
        Dog aDog = new Dog("Tom");
        foo(aDog);

        if (aDog.getName().equals("Tom")) { //true
            System.out.println( "Java passes by value."+ aDog.getName());
            System.out.println( aDog.x);

        } else if (aDog.getName().equals("Taz")) {
            System.out.println( "Java passes by reference." );
        }
    }

    public static void foo(Dog d) {
        ++d.x;
        d = new Dog("Taz");
        ++d.x;
    }
}

这将提供输出为

Java 按值传递.Tom

101

为什么输出101?我期待输出102

【问题讨论】:

标签: java pass-by-reference pass-by-value


【解决方案1】:

您将x 增加一次,在分配给该方法的狗(“Tom”)上。

然后你创建了一个新的狗,叫 Taz。

然后为第二只狗增加x。它不会影响原来的那只,两只狗都在 101 岁。

至于为什么调用方法仍然引用“Tom”,即使您将局部变量更改为指向“Taz”:那是因为局部变量就是这样:在使用它的地方是局部的。调用者并不关心你以后用它做什么,它自己的变量仍然会指向“Tom”。

由于 Java 不支持传递引用或“输出参数”,因此被调用函数无法更改调用函数中变量的值。

但请注意,对象不存储在变量中。只有一个指向它们的指针存储在那里。实际的对象实例本身位于共享位置(程序堆内存)。所以被调用的方法确实可以改变对象。但它不能将不同的对象分配给调用函数。


外卖:让你的局部变量final,尤其是方法参数。这样你就不能为两个不同的东西重用同一个变量,代码就不会那么混乱了。

【讨论】:

  • 谢谢.. 但问题是 d 引用指的是 Taz 对象,但输出提供的 Tom 对象的值是 101,并带有增量。
【解决方案2】:

您将 x 增加了两次,但在不同的狗上。看这段代码:

public static void foo(Dog d) {
    ++d.x;
    d = new Dog("Taz");
    ++d.x;
}

最初,d 指的是名字为Tom 的狗,x=100。这不是原始对象的副本 - 它是对同一对象的引用。 Java 通过值传递引用,这与通过值传递对象通过引用传递对象不同。重要的是要了解mainaDog 的值不是Dog 对象——它是对Dog 对象的引用。该引用的值按值传递给您的foo 方法...所以d 的初始值与aDog 的值相同。对d 变量本身(而不是其值所引用的对象)的进一步更改不会更改aDog 变量。

所以,看看foo 的其余部分:

  • ++d.x之后,d指的是名字为Tom的狗,后面是x=101
  • d = new Dog("Taz") 之后,d 指的是名字为Taz 的狗,后面是x=100
  • ++d.x之后,d指的是名字为Taz的狗,后面是x=101

调用代码只知道名称为 Tom 的狗,因此它会打印出 Tom 101。

【讨论】:

  • 谢谢@Jon 但接下来是为什么它打印 Tom 对象详细信息而不打印 Taz 对象详细信息。根据我的观点,我认为 java 将 Tom 对象的副本传递给 foo 方法。但是 t 不会按照这个传递副本。
  • @SaveendraSriEkanayake:不,它传递 reference 的副本,作为 d 的初始值。我已经编辑了答案以提供更多信息 - 看看是否有帮助。
【解决方案3】:

Java 总是按值传递

main():

Dog aDog = new Dog("Tom"); // {name="Tom", x=100}

foo():

++d.x;                     // {name="Tom", x=101}
d = new Dog("Taz");        // {name="Taz", x=100}
++d.x;                     // {name="Taz", x=101}

但是,您可以获得全新的副本,但您需要退回它。

在main()中:更新这一行

foo(aDog);

aDog = foo(aDog);

还将 foo() 更新为:

public static Dog foo(Dog d) {
  ...
  return d;
}

【讨论】:

    【解决方案4】:

    当您像这样使用new 关键字时d = new Dog("Taz");
    您创建了一个新的Dog,新的Dog 称为Taz 并拥有x=101,因此您不会为同一只狗增加d.x 2 次​​p>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-02
      • 2014-08-23
      • 2015-05-23
      • 2013-07-22
      • 2016-11-28
      相关资源
      最近更新 更多