我认为当你将对象传递给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对象。任何想法如何解决这个问题?
谢谢大家。
答案 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
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()