为什么原始包装类在作为参数传递后不会改变?

时间:2014-09-16 10:03:30

标签: java

确定。我完全清楚Java中的所有值都是按值传递的。但是这个例子并没有像我预期的那样:

public class Test {

private static void changeInteger(Integer x) {
    x = 5;
}

public static void main(String[] args) {
    Integer x = 0;
    changeInteger(x);
    System.out.println(x);
}

}

因为我将包装类传递给changeInteger方法,所以我传递了它的地址,因此,在执行了应该影响我的x变量的函数并将其设置为5.但是eclipse说输出仍然是0。我明白错了?

6 个答案:

答案 0 :(得分:6)

考虑这个例子:

class Wrapper {
    int n;
    public Wrapper(int k) { n = k; }
    public String toString() { return ""+n;}
    public static Wrapper valueOf(int k) { return new Wrapper(k); }
}

现在让我们使用上面的Integer类替换代码中的Wrapper

private static void changeInteger(Wrapper x) {
    x = Wapper.valueOf(5);
}

public static void main(String[] args) {
    Wrapper x = Wrapper.valueOf(0);
    changeInteger(x);
    System.out.println(x);
}

既然你提到你知道按值传递,我希望很明显为什么这段代码会做它的作用。

现在让我们回到您的代码。在引擎盖下,它是完全相同的代码。唯一的区别是你没有调用Wrapper.valueOf:编译器通过 autoboxing 为你做。一旦你意识到这是正在发生的事情,你应该清楚这个问题。

changeInteger()

ByteCode 以显示Integer.valueOf()被调用:

private static void changeInteger(java.lang.Integer);
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   iconst_5
   1:   invokestatic    #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
  teger;
  .... // some other code

答案 1 :(得分:4)

使用x = 5;x内的changeInteger()分配新值。您没有更改当前Integer对象的值。

方法外的x值不受影响。

答案 2 :(得分:2)

你的问题是Java是按值传递而不是引用,因此方法中的x与main x不同。 Integer是一个不可变类的事实,这里不会改变任何东西。

答案 3 :(得分:2)

你对java的自动装箱功能感到困惑。您无法将原始值分配给对象。当您致电x=5时,它会创建一个包含5个值的新Integer对象,并指定其对x的引用。但这仅影响changeIngeger范围内的参数,原始对象为0,主范围内的x引用未受影响。

答案 4 :(得分:1)

所有Java参数都按值传递。对于所有非基本类型,该值包含对传递的对象的引用。

对于您的代码,Integer对象存储在内存中的A位置。内存中的另一个位置B代表main的变量x,并存储值A

对于changeInteger来电,会创建一个新位置C,并将B中的值(A)复制到该位置。这是x函数的本地changeInteger

通过分配,您可以创建一个存储在D的新变量,并将其位置分配给C。然后你从方法返回。

您可以看到AB未在任何地方进行修改,因此值保持不变。

答案 5 :(得分:0)

保持简单,所有Java Wrapper类都是不可变的。所以你无法看到变化。

如果您想查看更改,只需从方法(不是)返回并重新分配。