是否可以将对象作为函数参数传递并在函数中重新分配它以在 java 中的函数范围之外修改其值?

Could pass object as function parameter and reassign it in function to modify its value out of function scope in java?

提问人:Bowen Peng 提问时间:1/17/2022 更新时间:1/17/2022 访问量:2765

问:

我对 Java 中的按值传递机制感到困惑,尽管我已经阅读了一些关于它的问题,例如这样和这样

我认为基元类型是通过函数参数中的值传递的,因此即使它在函数范围内发生了变化,它也不会更改其值。

public class A {
    void function(int i) {
        i = 3;
    }

    public static void main(String[] args) {
        int i = 2;
        function(i);
        System.out.println(i);  // variable `i` won't change
    }
}

但是类对象是通过函数参数中引用的值传递的,因此如果在函数范围内更改了该值,它将更改其值。

public class Obj{
    public double calPrice;
    public boolean isTop;
    public boolean isCate;
    public List<Integer> cList;
    public RPCRecord(double c, boolean iT, boolean iC, List<Integer> cL) {
        calPrice = c;
        isTop = iT;
        isCate = iC;
        cList = cL;
    }
}

void f2(Obj o) {
    List<Integer> l1 = new ArrayList<Integer>(){{
                        add(1);
                        add(2);
                        add(3);
                          }};
    Obj o2 = new Obj(10.0, true, false, l1);
    o = o2;
}

void f3(Obj obj) {
    obj.calPrice = 123123.1;
    obj.isTop = false;
    obj.add(10);
}

public class A {
    public static void main(String[] args) {
        Obj ojb = new Obj();
        f2(ojb);
        System.out.println(ojb);  // Object `obj` will change
        f3(ojb);
        System.out.println(ojb);  // Object `obj` will change
    }
}

请原谅我对 Java pass 参数机制不够熟悉。
我是这么想的吗?

java 参数 引用传递 -值

评论

1赞 tgdavies 1/17/2022
运行代码并查看。

答:

1赞 Alexander Ivanchenko 1/17/2022 #1

在调用具有基元类型(byte、short、char、int、long、float、double、boolean)的方法时,会传递带有对象 - 引用的

换句话说,不可能通过在调用方法时将其作为参数传递来更改原始变量(如 int)的初始值。 但它对一个对象是可行的,但只有在它是可变对象的情况下。例如,您可以自定义类 Obj 的实例或 StringBuilder 的实例,但不能更改 BigIntegerString,这些类被设计为不可变的。

https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html

3赞 arcy 1/17/2022 #2

我认为这是 Java 中传递值的常见混淆。

如果要从规则的角度来考虑它:如果将对象(引用)传递给方法,则无法更改传入的对象。换句话说,您不能将该引用更改为另一个对象。

你能够做的是改变对象中的东西——你上面的 f3 方法应该可以很好地改变传递给它的对象中的东西。

但是你不能 - 正如你在 f2 中尝试的那样 - 将传入的对象(类 A 中的 ojb)更改为另一个对象。若要从方法返回对象,必须在方法的 return 语句中返回该对象,或者它必须是另一个对象中的字段,以便可以在另一个对象中更改它。

现在,如果你想要较低级别的解释,而不是规则:

当您在 Java 中将对象变量名称作为参数作为参数时,您正在传递指向该对象的“指针”。您可以将其视为由其在内存中的地址表示的对象,并且您正在传递一个保存该地址的变量。您可以将保存对象地址的变量视为按值传递,即使您通过引用传递 OBJECT。

该方法将参数作为特殊类型的变量获取,并且可以使用参数变量引用该对象。并且该方法可以改变变量;它不能做的是为调用者更改它。

从上面获取您的方法:

void f2(Obj o) {
    List<Integer> l1 = new ArrayList<Integer>(){{
                        add(1);
                        add(2);
                        add(3);
                          }};
    Obj o2 = new Obj(10.0, true, false, l1);
    o = o2;
}

调用方传入一个参数“变量”,其中包含指向对象的指针;该方法调用该参数变量 。 可以更改参数变量的值。但是,驻留在该地址的任何对象仍然驻留在该地址,并且持有该地址的调用方中的任何变量仍然保留该地址。f2of2

从另一个角度来看:假设调用方传入了一个调用到 f2 方法的变量:george

SomeObject george = new SomeObject();
f2(george);

假设它在地址 1234。然后,我们可以认为 in 持有 1234,即 的地址。 创建一个新对象,假设地址为 5678。f2 中的语句的作用是将 5678 分配给 ,替换过去存在的 1234。这不会影响调用方; 仍然在1234。 更改了变量 holding 的地址,但调用方无法知道。georgeof2georgef2Obj o2 = new Obj(10.0, true, false, l1);o2o = o2ogeorgef2george