Java 中没有任何内容通过引用传递——但您需要知道变量的值是什么。
类型变量的值int[]
不是数组。它是对数组的引用。所有数组都是引用类型,即使它是一个基元数组。
当你写:
int[] x = { 1, 2, 3, 4, 5 };
someMethod(x);
然后 x 的值按值传递给someMethod
。它是对数组的引用——该方法可以更改数组的内容,但不能更改x
自身的值,如果 Java 使用传递引用,它可以做到这一点。
一旦你理解了任何表达式的值要么是一个引用,要么是一个原始值,很多事情就会变得更加清晰。例如,使用以下代码:
int[] x = { 1, 2, 3, 4, 5 };
int[] y = x;
y[0] = 10;
System.out.println(x[0]);
你期望结果是什么?赋值运算符将值从 RHS 复制到 LHS - 所以x
和y
是对同一数组的引用。因此最后一行打印出 10。这种“复制值”与用于参数传递的原理完全相同。
这里没有不一致 - 您只需要了解发生了什么,以及按值传递和按引用传递的真正含义。
编辑:我真的很惊讶对此仍有任何疑问。
来自 Java 语言规范,第 8.4.1 节(形式参数):
当调用方法或构造函数时(第 15.12 节),实际参数表达式的值在执行方法或构造函数的主体之前初始化新创建的参数变量,每个声明的类型
这实际上是按值传递语义的定义:参数的值用作参数的初始值。
这些值可能是引用,也可能是原始值 - 它不会改变它是传递的值的事实。
编辑:您使用的定义虽然在我看来表达得很糟糕,但当然并不意味着声称 Java 按值传递所有内容具有误导性。
它说,对于按值传递:
这会复制变量,如果变量像数组一样大,可能会非常缓慢且效率低下。
请注意,它是在谈论 C 和 C++(尽管实际上 C++也确实有通过引用传递)。它谈到了制作变量的副本。这正是 Java 所做的。不同之处在于,在 Java 中,变量的值始终是原始值或引用。它永远不是一个对象。
一旦你理解了这个关键点(而且它不仅仅对参数传递很重要),就可以完全直接地正确地说 Java 通过值传递所有内容。当调用方法或构造函数时,会计算参数并将值用作参数的初始值。这就是按值传递,这就是 Java 对所有参数所做的。
至于您链接到的 PDF - IMO 对这个主题的讨论非常糟糕。它使通过引用的方式变得一团糟,它无缘无故地特例 String(String 恰好是不可变的,但其他类也可以)并且通常是错误的。如果我提供一些支持我观点的链接会有所帮助吗?
还有数百个。您不是第一个对此感到困惑的人,但 Java 确实通过值传递所有内容,甚至是引用。