【问题标题】:Is Java pass by value Or pass by reference Or both? [duplicate]Java 是按值传递还是按引用传递或两者兼而有之? [复制]
【发布时间】:2013-08-17 10:58:58
【问题描述】:

考虑以下案例。

    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仍然遭受引用传递行为的困扰?

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

【问题讨论】:

  • Java 没有受到引用传递行为的困扰?
  • 嗯,你在问什么? Java 不会尝试做任何事情。它是一种语言,以一种方式设计/定义。但是,我要么不明白这个问题,要么在这里以有意义的方式回答。
  • @Ruchira 您应该更改问题的标题。
  • Java 是按值传递的,而且一直如此。令人困惑的是 List 这里是一个 reference 而不是一个对象,当您按值传递引用时,该引用被复制,而不是对象。

标签: java pass-by-reference pass-by-value


【解决方案1】:

Collections.reverse(listOne); 按值传递对listOne(对象)的引用,这就是定义“按引用传递”的方式。除了原语之外的所有东西都以这种方式传递:通过引用。它不会试图避免它,它与 C++ 的不同之处仅在于它不显式使用指针。

编辑:好的,我想我明白你来自哪里了。

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]

}

【讨论】:

  • 好的。现在java是按引用传递还是按值传递?
  • Java 通过引用传递除原始类型以外的任何内容。 int 通过值传递,而Integer 通过引用传递。上面代码中的列表对象总是通过引用传递的。
  • 虽然您已经在回答中说明了这一点,但为了在 cmets 中完全清楚,它始终是传递的引用的 VALUE,而不是引用本身。 Java 中的一切都是按值传递的。一切!基元或对象。
  • "按值传递对 listOne 的引用" 不,它没有。它通过值传递listOne
  • "按值传递对 listOne 的引用" listOne 时,我的意思可能有点不清楚:对象。我会解决的。但是:这正是它的作用。引用传递值,它引用的对象通过引用传递。查找术语“按引用传递”的定义;按值传递引用正是 java 为实现这一目标所做的。
【解决方案2】:
 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);
            }
        }
    }

现在,listOnelistTwo 具有相同的引用,指向相同的后备数组。因此,无论哪个 handle(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

就通过value/reference 而言。你自己说的:

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

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

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

【讨论】:

  • 那么,java是按引用传递还是按值传递?
  • 按值传递。总是。
【解决方案3】:

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

当你写作时

List 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 的正确名称,但使用它是因为它简短且方便。

【讨论】:

  • 没有“东西 3”
  • "thing 3" 表示 listOne 变量的值,在回复中修复了打印错误。
【解决方案4】:

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-01-21
    • 2016-11-28
    相关资源
    最近更新 更多