提问人:Bowen Peng 提问时间:1/17/2022 更新时间:1/17/2022 访问量:2765
是否可以将对象作为函数参数传递并在函数中重新分配它以在 java 中的函数范围之外修改其值?
Could pass object as function parameter and reassign it in function to modify its value out of function scope in java?
问:
我对 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 参数机制不够熟悉。
我是这么想的吗?
答:
在调用具有基元类型(byte、short、char、int、long、float、double、boolean)的方法时,会传递带有对象 - 引用的值。
换句话说,不可能通过在调用方法时将其作为参数传递来更改原始变量(如 int)的初始值。 但它对一个对象是可行的,但只有在它是可变对象的情况下。例如,您可以自定义类 Obj 的实例或 StringBuilder 的实例,但不能更改 BigInteger 或 String,这些类被设计为不可变的。
https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
我认为这是 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;
}
调用方传入一个参数“变量”,其中包含指向对象的指针;该方法调用该参数变量 。 可以更改参数变量的值。但是,驻留在该地址的任何对象仍然驻留在该地址,并且持有该地址的调用方中的任何变量仍然保留该地址。f2
o
f2
从另一个角度来看:假设调用方传入了一个调用到 f2 方法的变量:george
SomeObject george = new SomeObject();
f2(george);
假设它在地址 1234。然后,我们可以认为 in 持有 1234,即 的地址。 创建一个新对象,假设地址为 5678。f2 中的语句的作用是将 5678 分配给 ,替换过去存在的 1234。这不会影响调用方; 仍然在1234。 更改了变量 holding 的地址,但调用方无法知道。george
o
f2
george
f2
Obj o2 = new Obj(10.0, true, false, l1);
o2
o = o2
o
george
f2
george
评论