Java方法参数之谜
我偶然发现了Java的一个非常令人费解的特性(?) 似乎使用“new”关键字替换方法参数会将该对象转移到不同的范围: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);
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中,您可以将所有变量视为指向真实对象的指针 结果是:
在java中,您可以将所有变量视为指向真实对象的指针 结果是:
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);
}