我对数组的工作方式感到困惑。如果我将数组引用传递给某个方法,那么该方法可以更改先前存储在数组中的索引值。但是,如果对包装类对象执行相同操作,则该方法无法更改该值。这是代码:
public class TestArray {
public static void main(String[] args) {
ChangeValues ch=new ChangeValues();
int intArr[]={1,2,3};
Integer iWrapper=new Integer(123);
ch.changeArray(intArr);
for(int i:intArr){
System.out.print(i);// o/p: 789
}
System.out.println("\n-----------------");
ch.changeWrapper(iWrapper);
System.out.println(iWrapper);// o/p: 123
}
}
class ChangeValues{
void changeArray(int i[]){
i[0]=7;
i[1]=8;
i[2]=9;
}
void changeWrapper(Integer i){
i=789;
}
}
输出:
789
-----------------
123
为什么数组能够更改而不是包装对象。谁能清除我的怀疑?感谢。
答案 0 :(得分:5)
Java方法的所有参数都按值传递。当参数是引用类型(而不是基本类型)时,引用将按值传递。从本质上讲,这意味着该方法会收到调用者值的副本。
对可变对象的任何引用都可用于修改该对象,但这与修改保存引用的变量不同。您提供的两种更改方法与此不同:changeArray()
修改其参数引用的数组对象,但changeWrapper()
仅为包含其参数的局部变量(最初)赋予新值。 / p>
答案 1 :(得分:2)
因为包装器对象是不可变的。您必须创建一个新实例,并且由于无法修改调用者的引用,因此无法修改包装器实例。您可以(如果使用Java 8)使用Optional
,或者创建自己的POJO并传递它(只要您修改POJO的引用,然后调用者就可以从POJO访问它)。像,
class POJO<T> {
T v;
public POJO(T v) {
this.v = v;
}
public T getValue() {
return v;
}
public void setValue(T v) {
this.v = v;
}
@Override
public String toString() {
return String.valueOf(v);
}
}
public static void changeIt(POJO<Integer> a) {
a.setValue(123);
}
public static void main(String args[]) throws Exception {
POJO<Integer> p = new POJO<>(1);
System.out.println(p);
changeIt(p);
System.out.println(p);
}
输出
1
123
答案 2 :(得分:1)
changeArray
方法获取对数组对象的引用的副本。现在,来自i
的{{1}}和intArr
都指向同一个对象。数组访问分配可确保更新引用数组中的元素。只有一个数组,它会被修改。不会更新引用变量以引用其他对象。
main
方法获取对changeWrapper
对象的引用的副本。现在,来自Integer
的{{1}}和i
都指向同一个对象。但这不是数组访问。在此处说iWrapper
会更改对另一个引用的引用,即自动加框的main
i =
。 Integer
中的原始参考789
未更新,因此它仍然引用原始iWrapper
main
,解释输出。
答案 3 :(得分:1)
不使用Integer包装器,而是使用类似的东西(请注意,自动装箱将被破坏,因此必须手动完成):
public class MyInteger {
private int intValue;
public MyInteger(int val) {
intValue = val;
}
public void setValue(int val) {
intValue = val;
}
pubic int intValue() {
return intValue;
}
}
然后您的changeWrapper
方法可以是:
void changeWrapper(MyInteger i){
i.setValue(789);
}
并且
ch.changeWrapper(iWrapper);
System.out.println(iWrapper.intValue());
将打印&#34; 789&#34;。
或者,您可以将intValue
公开:
public int intValue;
然后你的changeWrapper方法可以成为:
void changeWrapper(MyInteger i){
i.intValue = 789;
}
这实际上是一个数组 - 一个包含大量公共字段的对象。
答案 4 :(得分:0)
因为当您将基元作为参数传递(第二种情况)时,您将使用该基元的 COPY 来用于该方法。但是,当您使用非基元或引用数据类型作为参数(您的数组)时,参数 SHARED 将用于您的方法,因此无论您对此对象执行的操作都将影响原始对象。
您可以在&#34;传递参数&#34;:http://pages.cs.wisc.edu/~bahls/cs302/PrimitiveVsReference.html
部分找到更好的解释 PD:对不起,我的英文很糟糕。