代码之家  ›  专栏  ›  技术社区  ›  user432209

在java中,向方法传递对象似乎是通过引用(java是通过val)

  •  0
  • user432209  · 技术社区  · 14 年前

    我认为,当您在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 回复  |  直到 13 年前
        1
  •  7
  •   Community Fabien Hure    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

    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

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

        2
  •  1
  •   Steve Kuo    14 年前

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

        3
  •  1
  •   Stephen C    14 年前

    以下是一些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”。

    编辑

    仍然

    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
    

    相信我,我已经为>10年了,我已经

        4
  •  0
  •   Community Fabien Hure    7 年前

    下面是一个简短的测试:

    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按值传递(对于原语)

    那么,我们都被编程老师骗了吗(甚至在大学里)?也许吧,但他们至少没有犯任何逻辑错误……所以这不是谎言,只是错了。

    我用一个类编写了与上面相同的代码,首先是数据结构:

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