Java方法参数之谜

Java方法参数之谜,java,arguments,pass-by-reference,Java,Arguments,Pass By Reference,我偶然发现了Java的一个非常令人费解的特性(?) 似乎使用“new”关键字替换方法参数会将该对象转移到不同的范围: import java.util.ArrayList; public class Puzzle { public static void main(String[] args) { ArrayList<Integer> outer = new ArrayList<Integer>(); outer.add(17);

我偶然发现了Java的一个非常令人费解的特性(?)

似乎使用“new”关键字替换方法参数会将该对象转移到不同的范围:

import java.util.ArrayList;

public class Puzzle {
    public static void main(String[] args) {
        ArrayList<Integer> outer = new ArrayList<Integer>();
        outer.add(17);
        Puzzle.change(outer);
        outer.add(6);
        System.out.println(outer);

        // excpected output:
        // [23]
        // [23, 6]
        //
        // actual output:
        // [23]
        // [17, 7, 6]
    }

    public static void change(ArrayList<Integer> inner) {
        inner.add(7);
        inner = new ArrayList<Integer>();
        inner.add(23);
        System.out.println(inner);
    }
}
import java.util.ArrayList;
公共类难题{
公共静态void main(字符串[]args){
ArrayList outer=新的ArrayList();
增加(17);
改变(外部);
增加(6);
系统输出打印项次(外部);
//预期产出:
// [23]
// [23, 6]
//
//实际产量:
// [23]
// [17, 7, 6]
}
公共静态无效更改(ArrayList内部){
加入(7);
内部=新的ArrayList();
新增(23);
系统输出打印项次(内部);
}
}

有人能解释这个奇怪的现象吗?我注意到了与赋值相同的行为。

这是java初学者的经典问题之一


内部参数通过值传递(对于非基本体对象,它是引用)。 如果您对它进行操作,它将影响与外部代码中相同的对象,因此您可以在外部方法中看到影响

如果用新对象替换该对象,则该对象不同。 当您使用新方法时,您不会更改前一个方法,也不会看到外部方法的影响



更新:很抱歉,词汇错误导致了很多评论。我现在更正了我的答案。我相信这一点已经提出来了,但现在已经清楚多了。

这是java初学者的经典问题之一


内部参数通过值传递(对于非基本体对象,它是引用)。 如果您对它进行操作,它将影响与外部代码中相同的对象,因此您可以在外部方法中看到影响

如果用新对象替换该对象,则该对象不同。 当您使用新方法时,您不会更改前一个方法,也不会看到外部方法的影响



更新:很抱歉,词汇错误导致了很多评论。我现在更正了我的答案。我相信这一点已经提出来了,但现在已经清楚多了。

外部引用仍然指向在主方法中创建的原始ArrayList。只有
内部
引用曾经指向在
更改
方法内部创建的新ArrayList,并且此ArrayList从未在
更改
外部被引用


这是预期的行为。您需要返回对内部ArrayList的引用,以便从调用范围访问它。

外部引用仍然指向在主方法中创建的原始ArrayList。只有
内部
引用曾经指向在
更改
方法内部创建的新ArrayList,并且此ArrayList从未在
更改
外部被引用


这是预期的行为。您需要返回对内部ArrayList的引用,以便从调用范围访问它。

您的“实际输出”非常有意义。您已在change()方法中将inner赋值给一个新值,而outer不再受影响。尝试使用调试器跟踪执行过程,您将了解发生了什么。

您的“实际输出”非常有意义。您已在change()方法中将inner赋值给一个新值,而outer不再受影响。尝试使用调试器跟踪执行过程,您将了解发生了什么。

您没有转移作用域,只是将新的ArrayList分配给了
内部
参数。尝试将
内部
设为
最终
参数以防止出现这种情况。

您没有移动范围,只是将新的数组列表指定给
内部
参数。尝试将
internal
设置为
final
参数以防止出现这种情况。

'internal'是对“outer”最初引用的同一对象的引用(因为Java对方法上的对象参数使用pass-by-reference,所以internal和outer都指向同一对象),然后在方法内部将“internal”引用设置为新对象


Java的重要之处在于,这不会改变主方法中“外部”引用的内容。一旦方法调用完成,“内部”就不再在作用域中,最终将被垃圾收集。“outer”指向的对象仍在范围内(因为outer仍然处于活动状态)。

“inner”是对“outer”最初引用的同一对象的引用(因为Java对方法上的对象参数使用pass-by-reference,所以inner和outer都指向同一个对象),然后在方法内部使“inner”引用成为新对象


Java的重要之处在于,这不会改变主方法中“外部”引用的内容。一旦方法调用完成,“内部”就不再在作用域中,最终将被垃圾收集。“outer”指向的对象仍在范围内(因为outer仍然处于活动状态)。

据我所知,这不是一个难题,Java只支持按值传递,我的意思是始终复制参数。
更多。

据我所知,这不是一个难题,Java只支持按值传递,我的意思是总是复制参数。
更多。

在java中,您可以将所有变量视为指向真实对象的指针

结果是:

  • 您可以创建一个列表
  • 再加上17个
  • 将列表发送到另一个函数 有自己的指针指向 名单
  • 将7添加到第一个列表中
  • 创建一个新列表并指向 指向那个的“内部”指针
  • 将23添加到新列表中
  • 打印新列表并返回
  • 在原始函数中,您仍然 让指针指向 和以前一样的东西
  • 在第一个列表中添加6
  • 然后打印第一个列表

  • 在java中,您可以将所有变量视为指向真实对象的指针

    结果是:

  • 您可以创建一个列表
  • 再加上17个
  • 把名单发给另一个有趣的人
    import java.util.ArrayList;
    
    public class Puzzle {
        public static void main(String[] args) {
            ArrayList<Integer> outer = new ArrayList<Integer>();
            outer.add(17);
    
            ArrayList<Integer> inner = outer;
            inner.add(7);  // inner refers to same array list as outer
    
            inner = new ArrayList<Integer>();  // inner refers to new array list
            inner.add(23);
            System.out.println(inner);  // new list is printed
    
            outer.add(6);
            System.out.println(outer);  // outer list is printed
    }
    
       ArrayList<Integer> outer = @1234; //The first reference where the ArrayList was created.
    
      Puzzle.change(@1234);
    
    public static void change(ArrayList<Integer> inner) { // a new reference inner is created.
        //inner starts out as @1234
        inner.add(7);
        //now inner becomes @5678
        inner = new ArrayList<Integer>();
        //The object @5678 is changed.
        inner.add(23);
        //And printed.
        System.out.println(inner);
    }