繁体   English   中英

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

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

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

谢谢大家

这是通过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”。 在旁审中将是“再见”

这里有一些链接:

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

以下是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年以上的时间,并且我在大学阶段教授过比较编程语言课程。

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

实际上,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()的错误

暂无
暂无

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

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