简体   繁体   English

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

[英]Passing object to method in java appears to be by reference (and Java is by val)

I thought when you passed objects to methods in Java, they were supposed to be by value. 我以为,当您将对象传递给Java中的方法时,应该认为它们是按值的。

Here is my code: 这是我的代码:

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

At this point, any changes to the mTiles object are reflected back to the tiles object. 此时,对mTiles对象的任何更改mTiles反映回tile对象。 Any ideas how to fix this? 任何想法如何解决这一问题?

Thanks all. 谢谢大家

It is by val, but when talking about objects, what gets passed is the value of the reference, so, if your object is mutable ( as in your example ) modifying the object through the reference copy, will modify the underlaying object. 这是通过val进行的,但是在谈论对象时,传递的是引用的值,因此,如果您的对象是可变的(如您的示例中所示),则通过引用副本修改对象,则会修改底层对象。

To solve it, you have to copy your object and pass that new reference value. 要解决此问题,您必须复制对象并传递该新参考值。

In your code, you are using the same reference value in "tiles" and in "mTiles" 在您的代码中,您在“ 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

You would have to create a new one like this: 您将必须创建一个新的像这样的:

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

Or 要么

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

Or 要么

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

Or something like that, so you can create actually a new one, instead of using the same ref. 或类似的东西,因此您实际上可以创建一个新的引用,而不用使用相同的引用。

I hope this helps. 我希望这有帮助。

EDIT 编辑

When you change the ref in pass-by-val, the original is not affected, ie: 当您在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"
}

After this, the original "hi" is still "hi". 在此之后,原始的“ hi”仍然是“ hi”。 In pass-by-ref it would be "bye" 在旁审中将是“再见”

Here some links: 这里有一些链接:

http://www.javaranch.com/campfire/StoryPassBy.jsp 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? 有人可以向我解释Java中“值”而不是“引用”传递的背后原因是什么?

Pass by reference or pass by value? 通过引用还是通过值?

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

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

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

An ultimately: 最终:

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

Here are some diagnostic examples for Java's argument passing semantics: 以下是Java参数传递语义的一些诊断示例:

For an object type: 对于对象类型:

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"

For a primitive type: 对于原始类型:

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"

In fact, in both of those examples, the assignments within the changeIt methods only affect the respective method's local variable, and the actual values printed will be "hi" and "0". 实际上,在这两个示例中, changeIt方法中的赋值仅影响相应方法的局部变量,并且打印的实际值将为“ hi”和“ 0”。

EDIT 编辑

And since the OP still doesn't believe me ... here's a diagnostic example to show that Java is call-by-value for mutable objects as well. 而且由于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"

By contrast, this example will give the same answer for both call by reference and call by value semantics. 相比之下,此示例将为按引用调用和按值调用语义提供相同的答案 It doesn't prove anything about argument passing semantics. 它并没有证明有关参数传递语义的任何信息。

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

Trust me, I've been programming Java for > 10 years, and I've taught comparative programming language courses at university level. 相信我,我从事Java编程已有10年以上的时间,并且我在大学阶段教授过比较编程语言课程。

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

As a matter of fact, Java is pass-by-value. 实际上,Java是按值传递的。 But it also has "arrays-by-reference"! 但是它也有“按引用排列”! That's why many people think Java is pass-by-reference for objects (at least for arrays) and only pass-by-values for primitives. 这就是为什么许多人认为Java是对象的传递引用(至少是数组),而基元仅传递值。

Here is a short test: 这是一个简短的测试:

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

No matter if you clone or use =, the System.out.print will always look like this: 无论您克隆还是使用=,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

This proves that cloning and arrays are a harmful combination, because arrays only store pointers! 这证明了克隆和数组是有害的组合,因为数组仅存储指针! I still need to test if this is also true for no-array objects...because this would mean that Java is always "storage-by-reference" (and the "clone"-function would be only a bad joke for any objects containing arrays), while only primitives are real values and no references! 我仍然需要测试是否对无数组对象也是如此...因为这将意味着Java始终是“按引用存储”(并且“克隆”功能对于任何对象来说都是一个恶作剧)包含数组),而只有基元是实数值,没有引用!

And since we know about logic: storage-by-reference x pass-by-value == "storage by value x pass-by-reference" (for objects!), 而且由于我们了解逻辑:按引用存储x传递值==“按值存储x引用传递”(对于对象!),

while we already knew since school: storage-by-value x pass-by-value (for primitives) 虽然我们从学校开始就已经知道:按值存储x按值传递(对于基元)

So, were we all lied to by our programming teachers (even at university)? 那么,我们所有人都被编程老师(甚​​至在大学里)骗了吗? Maybe, but they didn't make any logical errors at least...so it wasn't a lie, it was just wrong. 也许吧,但是他们至少没有犯任何逻辑错误...所以这不是一个谎言,那是错误的。

EDIT 编辑

I wrote the same code as above with a class, first the data structure: 我用一个类编写了与上面相同的代码,首先是数据结构:

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;
        }
    }
}

Now the controller: 现在控制器:

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

The test results will always look like that - no matter if I use = or clone(): 测试结果将始终像这样-无论我使用=还是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

Now I've got the "master array" in the pocket, with whom I can rule all objects right away! 现在,我已经有了“主阵列”,可以立即使用它来统治所有对象! (which isn't really a good thing) (这不是一件好事)

I always felt uneasy about Java arrays, but I couldn't say what it was. 我总是对Java数组感到不安,但是我不能说是什么。 Now I know it, and I feel good since I only used arrays as container for objects ever since...only to find myself being quite surprised how important they are in script languages like PHP! 现在我知道了,自从我从那时起就只使用数组作为对象的容器,我感觉很好……才发现我很惊讶它们在像PHP这样的脚本语言中的重要性!

Still, Java arrays are great for synchronisation between threads, as you can pass them easily and still access shared values. Java数组仍然非常适合线程之间的同步,因为您可以轻松地传递它们并仍然访问共享值。 But programmers coming from PHP or C++ or somewhere else may indeed experience some problems with Java arrays. 但是来自PHP或C ++或其他地方的程序员确实可能会遇到Java数组的一些问题。 ;D ; D

Oh, I like this article: http://javadude.com/articles/passbyvalue.htm 哦,我喜欢这篇文章: http : //javadude.com/articles/passbyvalue.htm

UPDATE: I've found a great solution to copy any object containing arrays, see my commentary here: Bug in using Object.clone() 更新:我找到了一个很好的解决方案,可以复制任何包含数组的对象,请参见我的评论: 使用Object.clone()的错误

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM