繁体   English   中英

Java传递值混淆

[英]Java Pass-by-Value Confusion

好的一个奇怪的问题。 我有以下代码,该代码仅创建一个简单的java对象DumObj并使用setter方法设置字符串值。 然后使用DumObj作为参数从TestBed类中调用一些方法。

最初,我认为调用TestBed.updateId(DumObj)不会影响我的DumObj,并且设置为“ apple”的ID的初始值将保持不变。 (因为整个价值传递的事情)

但是,ID的值被设置为“橙色”的更新值。 好的,我认为那很奇怪,所以我编写了另一种方法TestBed.setToNull(DumObj)。 此方法只是将DumObj设置为null,因此当我调用getId()方法时,我期望得到一个null指针异常。

但是我得到的输出是ID的值仍然设置为“橙色”。

代码如下:

    public static void main(String[] args) 
    {   
            TestBed test = new TestBed();
            DumObj one = new DumObj();

            one.setId("apple");
            System.out.println("Id : " + one.getId());

            test.updateId(one);
            System.out.println("Id : " + one.getId());

            test.setToNull(one);
            System.out.println("Id : " + one.getId());
    }

    public void updateId(DumObj two)
    {
            two.setId("orange");
    }

    public void setToNull(DumObj two)
    {
            two = null;
    }

输出如下:

    Id : apple
    Id : orange
    Id : orange

我可能忽略了很简单的事情,但是有人可以向我解释这种行为吗? Java不是按值传递的吗?

当你写

DumObj one = new DumObj();

重要的是要意识到one不是DumObj ,而是对DumObj引用 ,并且引用是通过value传递的

因此,您始终按值传递,并且可以更改传递的引用(因此,传递的引用现在指向另一个对象)。 但是,您的对象本身可能是可变的,因此:

   one.setValue(123);

将更改引用的对象。 当您致电:

public void setToNull(DumObj two)
{
        two = null;
}

您正在更改传递的引用(请记住-它已通过传递并且在方法中是本地的!),因此您的原始对象和原始引用不受影响。

当您这样做时:

two = null;

您仅将two变量引用设置为null。 它指向的对象仍然存在,并被one引用。

另一方面,当您这样做时:

two.setId("orange");

您正在修改onetwo都引用的对象。

Java是对象的“按值传递引用”。 因此,在setToNull(DumObj two) ,两个是对对象的引用。 如果说two = null; 现在,这两个引用不是对象。 它不会改变对象。 另一方面,如果您执行诸如two.setId("blue") ,则您正在更改two引用的对象。

是的,Java是按值传递的。 但是您的变量实际上是指向在堆上分配的对象的指针。 因此,它所传递的值是指针,而不是对象。

在您的示例中:

public void updateId(DumObj two)
{
        two.setId("orange");
}

第一个按值传递变量(指针),即updateId()获得指针的副本。 但是您在这里所做的是修改指针所指向的对象 因此,当您返回调用方函数时,该对象已被修改。

public void setToNull(DumObj two)
{
        two = null;
}

在第二种情况下,您将null分配给原始指针的副本,而不是原始指针本身 ,因此该函数调用对origial变量完全无效。

当您调用updateId时,新引用变量2和旧引用变量1都引用堆中的同一对象,因此更改一个引用将反映在其他引用变量中。

现在,当您再次调用setToNull时,新的参考变量2和旧的参考变量1都引用同一对象。但是在这里,当您执行两个= null时,仅参考变量2指向空对象。 但是引用变量one仍然指向同一对象。当您执行two == null时 ,您没有更改它引用的对象中的任何值,而是将引用变量引用为null。

如果使用setToNull方法,则编写两个= new DumObj();。 然后将在堆中创建一个新对象,并且两个对象将指向该新对象。然后,例如,如果您编写两个,则为.setId(“ banana”);

并且在您的主代码中,如果您在syso中编写one.getId(),它将显示橙色而不是香蕉。

希望我能帮上忙。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM