2

考虑以下情况。

    List<Integer> listOne = new ArrayList<>();
    List<Integer> listTwo = new ArrayList<>();
    listOne.add(1);I think this happens due to 
    listOne.add(2);
    listOne.add(3);
    Collections.reverse(listOne);
    listTwo = listOne;  //listTwo has same reference 
    Collections.reverse(listOne);
    System.out.println(listOne);  //out put [1, 2, 3] 
    System.out.println(listTwo);  // same out put

Java is pass by value, where values (for non primitive types) happen to be references.我认为这为这种情况下的 java 提供了生存。老实说,为什么要java尽量避免pass by reference和尝试不同some of other languages?而java仍然遭受引用传递行为的困扰?

编辑:另外请有人解释上面代码中发生的事情

4

4 回答 4

3

Java 不受引用传递行为的影响,它喜欢它们 :)

当你写

列表 listOne = new ArrayList<>();

您需要考虑件事:

1)一个变量,它是一块内存,命名为listOne

2)堆上的一个对象,with是ArrayList的一个实例,是一块更大的内存,没有名字

3)listOne变量的值,它不是一个内存块,而是一组0和1放在变量listOne的内存中,这个值也没有名字。

现在,当我们谈论 listOne 是按值传递还是通过引用传递时,我们使用了不精确的术语,这会导致误解。listOne(事物 1)根本没有通过值或引用传递。listOne (事物 3)的值被传递,这提供了对 ArrayList 对象(事物 2)的访问。因此,如果我们使用名称“listOne”但表示事物 3,它是按值传递的,如果我们指的是事物 2,它是按引用传递的。在这两种情况下,名称“listOne”都不是事物 2 或事物 3 的正确名称,但使用它是因为它简短且方便。

于 2013-08-15T09:52:46.533 回答
1

Java是按值传递的。实际参数的副本被传递给参数。在原始数据类型的情况下,形式参数的变化没有显示在实际参数中,这一点很明显。

 static void incre(int a)
      {
        a++;
      }
public static void main (String a[])
{ 
  int c=3;
  incre(c);
  System.out.println(c);  //still prints 3
}

在引用的情况下会发生确切的事情,但是制作引用的副本不会创建新对象,它们现在都指向同一个对象。因此引用所做的更改会反映在这里。

class Demo { 
  int c =2; 

  Demo(int c)
    {
       this.c=c;
    } 

  void incObject (Demo x)    
    {
       (x.c)++;
    }

  int show()
   {
      return c;
   }
  public static void main (String []args)    
   {
    Demo o = new Demo(1);
    o.incObject(o);
   System.out.print(o.show()); //prints 2

 }

}
于 2013-08-15T10:03:45.270 回答
0
 Collections.reverse();

修改后备数组。从实现中可以清楚地看到:

 public static void reverse(List<?> list) {
        int size = list.size();
        if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
                swap(list, i, j);
        } else {
            ListIterator fwd = list.listIterator();
            ListIterator rev = list.listIterator(size);
            for (int i=0, mid=list.size()>>1; i<mid; i++) {
                Object tmp = fwd.next();
                fwd.set(rev.previous());
                rev.set(tmp);
            }
        }
    }

现在,listOne并且listTwo具有指向相同后备数组的相同引用。因此,无论哪个句柄(listOne 或 listTwo)修改了后备数组,另一个将反映相同的更改。在你的情况下:

    Collections.reverse(listOne);  // backing array has [3,2,1]
    listTwo = listOne;  //listTwo has same reference 
    Collections.reverse(listOne);  // backing array has [1,2,3]
    System.out.println(listOne);  //out put [1, 2, 3] 
    System.out.println(listTwo);  // same out put

就按值/引用传递而言。你自己说的:

Java 是按值传递的,其中值恰好是引用。

为什么 java 尽量避免通过引用传递并尝试与其他一些语言不同?

主要原因之一是Java(JVM)管理自己的内存。

于 2013-08-15T09:26:57.580 回答
-2

Collections.reverse(listOne); passes the reference to listOne(the object) by value, which is how one defines "pass by reference". Everything other than primitives is passed this way: by reference. It does not try to avoid it, it is only different from C++ in that it doesn't explicitly use pointers.

EDIT: Okay, I think I see where you're coming from.

private static void changelist(List<Integer> list) {
    list.add(4);//This modifies the list object
    list = new ArrayList<Integer>();//This modifies the local copy of the reference to the list object
    list.add(5);
}
public static void main(String[] args) {
    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
    list.add(2);
    list.add(3);
    System.out.println(list);//output is [1,2,3]
    //This copies the value of the reference. 
    //If you modify the object in the underlying 
    //function, changes will be preserved when you return
    //However if you modify what the reference points to,
    //the function will only modify the local copy
    changelist(list);
    System.out.println(list);//output is [1,2,3,4]

}
于 2013-08-15T09:22:04.787 回答