将对象传递给java中的方法似乎是通过引用(而Java是由val)

时间:2010-09-29 23:01:20

标签: java android eclipse pass-by-reference pass-by-value

我认为当你将对象传递给Java中的方法时,它们应该是有价值的。

这是我的代码:

public class MyClass{
    int mRows;
    int mCols;
    Tile mTiles[][];     //Custom class

    //Constructor
    public MyClass(Tile[][] tiles, int rows, int cols) {
        mRows = rows;
        mCols = cols;

        mTiles = new Tile[mRows][mCols];
        for (int i=0; i < mRows; i++) {
            for (int j=0; j < mCols; j++) {
                mTiles[i][j] = new Tile();
                mTiles[i][j] = tiles[i][j];
            }
        }
    }

此时,对mTiles对象的任何更改都会反映回tiles对象。任何想法如何解决这个问题?

谢谢大家。

4 个答案:

答案 0 :(得分:7)

它是由val,但在谈论对象时,传递的是引用的值,因此,如果您的对象是可变的(如在您的示例中)通过引用副本修改对象,将修改底层对象

要解决此问题,您必须复制对象并传递新的参考值。

在您的代码中,您在“tiles”和“mTiles”中使用相同的参考值

mTiles[i][j] = new Tile(); // <---this line is useless by the way
mTiles[i][j] = tiles[i][j] // because you then assign the same value here

你必须像这样创建一个新的:

mTiles[i][j] = new Tile(tiles[i][j]);

或者

mTiles[i][j] = tiles[i][j].clone();

mTiles[i][j] = Tile.newFrom( tiles[i][j] );

或类似的东西,所以你可以创建一个新的,而不是使用相同的参考。

我希望这会有所帮助。

修改

当您更改pass-by-val中的ref时,原始文件不会受到影响,即:

String s = "hi"; 
changeIt(s);
....
void changeIt(String s){ 
    s = "bye" // assigning to the copy a new ref value of "bye"
}

在此之后,原来的“hi”仍然是“hi”。在pass-by-ref中它将是“bye”

这里有一些链接:

http://www.javaranch.com/campfire/StoryPassBy.jsp

Can someone explain to me what the reasoning behind passing by "value" and not by "reference" in Java is?

Pass by reference or pass by value?

http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

http://academic.regis.edu/dbahr/GeneralPages/IntroToProgramming/JavaPassByValue.htm

http://www.jguru.com/faq/view.jsp?EID=430996

最终:

http://www.google.com.mx/search?sourceid=chrome&ie=UTF-8&q=java+is+pass+by+value

答案 1 :(得分:1)

以下是Java参数传递语义的一些诊断示例:

对象类型:

void changeIt(String s) {
    s = "bye";
}

String s = "hi"; 
changeIt(s);
System.out.println(s);  // would print "bye" for call by reference
                        // but actually prints "hi"

对于基本类型:

void changeIt(int i) {
    i = 42;
}

int i = 0; 
changeIt(i);
System.out.println(i);  // would print "42" for call by reference
                        // but actually prints "0"

实际上,在这两个示例中,changeIt方法中的赋值仅影响相应方法的局部变量,打印的实际值将为“hi”和“0”。

修改

由于OP 仍然不相信我...这是一个诊断示例,表明Java也是可变对象的值调用。

public class Mutable {
    int field;
    public Mutable(int field) { this.field = field; }
    public void setField(int field) { this.field = field; }
    public int getField() { return field; }
}

void changeIt(Mutable m, Mutable m2) {
    m = m2;  // or 'm = new Mutable(42);' or 'm = null;'
}

Mutable m = new Mutable(0); 
Mutable m2 = new Mutable(42); 
changeIt(m, m2);
System.out.println(m.getField());  
                        // would print "42" for call by reference
                        // but actually prints "0"

相比之下,这个示例将为引用调用和按值语义调用提供相同的答案。它没有证明任何关于参数传递语义的东西。

void changeIt2(Mutable m) {
    m.setField(42);
}

Mutable m = new Mutable(); 
changeIt2(m);
System.out.println(m.getField());  
                        // prints "42" for both call-by reference
                        // and call-by-value

相信我,我一直在编写Java for gt; 10年,我在大学阶段教授比较编程语言课程。

答案 2 :(得分:1)

您不传递对象,传递对象的引用,该引用按值复制。

答案 3 :(得分:0)

事实上,Java是按值传递的。但它也有“引用数组”!这就是为什么许多人认为Java是对象的传递(至少对于数组)而且只是基元的值传递。

这是一个简短的测试:

String[] array = new String[10];
array[0] = "111";
ArrayList one = new ArrayList(); 
one.add(array);
ArrayList two = (ArrayList) one.clone(); //Alternate with: ArrayList two = one;
String[] stringarray1 = (String[]) one.get(0);
String[] stringarray2 = (String[]) two.get(0);
System.out.println("Array: "+one+" with value: "+stringarray1[0]);
System.out.println("Array: "+one+" with value: "+stringarray2[0]);
array[0] = "999";
String[] stringarray3 = (String[]) one.get(0);
String[] stringarray4 = (String[]) two.get(0);
System.out.println("Array: "+one+" with value: "+stringarray3[0]);
System.out.println("Array: "+two+" with value: "+stringarray4[0]);

无论您是克隆还是使用=,System.out.print将始终如下所示:

Array: [[Ljava.lang.String;@addbf1] with value: 111
Array: [[Ljava.lang.String;@addbf1] with value: 111
Array: [[Ljava.lang.String;@addbf1] with value: 999
Array: [[Ljava.lang.String;@addbf1] with value: 999

这证明克隆和数组是有害的组合,因为数组只存储指针!我仍然需要测试对于无数组对象是否也是如此...因为这意味着Java总是“按引用存储”(并且“克隆”函数对任何对象都只是一个坏笑话包含数组),而只有基元是实数值而没有引用!

因为我们知道逻辑:按引用存储x按值传递==“存储按值x传递引用”(对于对象!),

虽然我们从学校就已经知道了:按值存储x传递值(对于基元)

那么,我们是否都被我们的编程老师(甚​​至大学)欺骗了?也许,但他们至少没有犯任何逻辑错误......所以这不是谎言,这是错误的。

修改

我用类编写了与上面相同的代码,首先是数据结构:

public class Foobar implements Cloneable {
    String[] array;

    public Foobar() {
        this.array = new String[10];
    }

    public String getValue(){
        return array[0];
    }

    public String[] getArray(){
        return array;
    }

    public void setArray(String[] array){
        this.array = array;
    }

    @Override
    public Object clone(){
        try{
            Foobar foobar = (Foobar) super.clone();
            foobar.setArray(array);
            return foobar;
        }
        catch(Exception e){
            return null;
        }
    }
}

现在是控制器:

String[] array = new String[10];
array[0] = "111";
Foobar foo1 = new Foobar();  
foo1.setArray(array);
Foobar foo2 = foo1; //Alternation: Foobar foo2 = (Foobar) foo1.clone();  
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
array[0] = "999";
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());

测试结果将始终如此 - 无论我使用=还是clone():

Instance: [Ljava.lang.String;@42e816 with value: 111
Instance: [Ljava.lang.String;@42e816 with value: 111
Instance: [Ljava.lang.String;@42e816 with value: 999
Instance: [Ljava.lang.String;@42e816 with value: 999

现在我在口袋里有了“主阵列”,我可以立即统治所有物品! (这不是一件好事)

我总是对Java数组感到不安,但我不知道它是什么。现在我知道了,我感觉很好,因为我从那时起只使用数组作为对象的容器......只是发现自己很惊讶它们在像PHP这样的脚本语言中有多重要!

尽管如此,Java数组非常适合线程之间的同步,因为您可以轻松地传递它们并仍然可以访问共享值。但是来自PHP或C ++或其他地方的程序员可能确实遇到了Java阵列的一些问题。 ; d

哦,我喜欢这篇文章:http://javadude.com/articles/passbyvalue.htm

更新:我找到了一个很好的解决方案来复制包含数组的任何对象,请参阅我的评论:Bug in using Object.clone()