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

发布于 2024-09-25 19:26:22 字数 628 浏览 6 评论 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 对象的任何更改都会反映回tiles 对象。有什么想法如何解决这个问题吗?

谢谢大家。

I thought when you passed objects to methods in Java, they were supposed to be by value.

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. Any ideas how to fix this?

Thanks all.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

风情万种。 2024-10-02 19:26:22

它是通过 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]);

Or

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

Or

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

这里有一些链接:

http://www.javaranch.com/campfire/StoryPassBy.jsp" 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 +值

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.

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"

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:

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". In pass-by-ref it would be "bye"

Here some links:

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

An ultimately:

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

双手揣兜 2024-10-02 19:26:22

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

You don't pass the object, you pass a references to the object, which is copied by value.

韶华倾负 2024-10-02 19:26:22

以下是 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 编程已经超过 1 年了。十年来,我教授大学水平的比较编程语言课程。

Here are some diagnostic examples for Java's argument passing semantics:

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".

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.

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.

瀟灑尐姊 2024-10-02 19:26:22

事实上,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() 时出现错误

As a matter of fact, Java is pass-by-value. 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.

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:

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!

And since we know about logic: storage-by-reference x pass-by-value == "storage by value x pass-by-reference" (for objects!),

while we already knew since school: storage-by-value x pass-by-value (for primitives)

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

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. 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!

Still, Java arrays are great for synchronisation between threads, as you can pass them easily and still access shared values. But programmers coming from PHP or C++ or somewhere else may indeed experience some problems with Java arrays. ;D

Oh, I like this article: 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()

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文