Array对象与其他对象有何不同

时间:2015-01-22 22:41:18

标签: java

我对数组的工作方式感到困惑。如果我将数组引用传递给某个方法,那么该方法可以更改先前存储在数组中的索引值。但是,如果对包装类对象执行相同操作,则该方法无法更改该值。这是代码:

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

为什么数组能够更改而不是包装对象。谁能清除我的怀疑?感谢。

5 个答案:

答案 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:对不起,我的英文很糟糕。