0

我认为当您将对象传递给 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对象的任何更改都会反映回瓦片对象。任何想法如何解决这一问题?

谢谢大家。

4

4 回答 4

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] );

或类似的东西,因此您实际上可以创建一个新的,而不是使用相同的 ref。

我希望这有帮助。

编辑

当你在 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 中它将是“再见”

这里有一些链接:

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

有人可以向我解释在 Java 中通过“值”而不是“引用”传递的原因是什么?

通过引用传递还是通过值传递?

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

于 2010-09-29T23:03:28.763 回答
1

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

于 2010-09-30T00:23:51.900 回答
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 编程超过 10 年,并且我在大学教授过比较编程语言课程。

于 2010-09-29T23:30:48.133 回答
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

更新:我找到了一个很好的解决方案来复制任何包含数组的对象,请在此处查看我的评论:使用 Object.clone() 中的错误

于 2012-10-20T16:46:06.397 回答