数组是通过值传递还是通过Java引用传递?

Fro*_*koy 164 java arrays

可能重复:
Java是"传递引用"吗?

数组在Java 中不是原始类型,但它们也不是对象,它们是通过值还是通过引用传递的?它取决于数组包含的内容,例如引用或基本类型吗?

Roh*_*ain 217

Everything in Java are passed-by value..在Array(它只是一个Object)的情况下,数组引用按值传递..(就像通过值传递对象引用一样)..

将数组传递给其他方法时,实际上会复制对该数组的引用.

  • 通过该引用对数组内容的任何更改都将影响原始数组.
  • 但是将引用更改为指向新数组不会更改原始方法中的现有引用.

看这篇文章..

Java是"通过引用传递"还是"传递价值"?

看到这个工作示例: -

public static void changeContent(int[] arr) {

   // If we change the content of arr.
   arr[0] = 10;  // Will change the content of array in main()
}

public static void changeRef(int[] arr) {
   // If we change the reference
   arr = new int[2];  // Will not change the array in main()
   arr[0] = 15;
}

public static void main(String[] args) {
    int [] arr = new int[2];
    arr[0] = 4;
    arr[1] = 5;

    changeContent(arr);

    System.out.println(arr[0]);  // Will print 10.. 

    changeRef(arr);

    System.out.println(arr[0]);  // Will still print 10.. 
                                 // Change the reference doesn't reflect change here..
}
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说是最有用的答案.谢了哥们! (27认同)
  • 为什么不直接说数组是通过引用传递的呢? (6认同)

Ste*_*n C 106

您的问题基于错误的前提.

数组在Java中不是原始类型,但它们也不是对象......"

实际上,Java 中的所有数组都是对象1.每个Java数组类型都有java.lang.Object其超类型,并继承了ObjectAPI 中所有方法的实现.

与所有Java对象一样,数组按值传递......但该值是对数组的引用.

通过引用进行实际传递涉及传递变量的地址,以便可以更新变量.这不是在Java中传递数组时发生的情况.

以下是一些解释"pass-by-reference"和"pass-by-value"之间区别的链接:

相关问题:

历史背景:

短语"pass-by-reference"最初是"引用调用",它用于区分FORTRAN(通过引用调用)的语义与ALGOL-60(按值调用)的语义区分.并且按名称呼叫).

  • 在call-by-value中,参数表达式被计算为一个值,并将该值复制到被调用的方法.

  • 在call-by-reference中,参数表达式被部分计算为传递给调用方法的"左值"(即变量或数组元素的地址).然后,调用方法可以直接读取和更新变量/元素.

  • 在按名称调用时,实际的参数表达式被传递给调用方法(!!),它可以多次评估它(!!!).这实现起来很复杂,可以使用(滥用)来编写非常难以理解的代码.名字叫声只在Algol-60中使用过(谢天谢地!).

UPDATE

实际上,Algol-60的call-by-name类似于将lambda表达式作为参数传递.皱纹是这些不完全lambda表达式(它们在实现级别被称为"thunk")可以间接地修改调用过程/函数范围内的变量的状态.这是使他们如此难以理解的部分原因.(例如,请参阅Jensen设备上的维基百科页面.)


1.链接的Q&A(Java中的数组以及它们如何存储在内存中)中没有任何内容表明或暗示数组不是对象.


Tud*_*dor 59

数组实际上是对象,所以传递了一个引用(引用本身是通过值传递的,但却被混淆了?).快速举例:

// assuming you allocated the list
public void addItem(Integer[] list, int item) {
    list[1] = item;
}
Run Code Online (Sandbox Code Playgroud)

您将从调用代码中看到对列表的更改.但是,您无法更改引用本身,因为它是通过值传递的:

// assuming you allocated the list
public void changeArray(Integer[] list) {
    list = null;
}
Run Code Online (Sandbox Code Playgroud)

如果传递非空列表,则在方法返回时它不会为空.

  • @aleroot:我说的是一个引用传递给方法,否则你看不到变化,并不是说java是按引用传递的!是的,引用是通过值传递的,但这不是重点。 (2认同)
  • @Tudor你的判决不清楚...... (2认同)
  • *“但是您无法更改引用本身,因为它是按值传递的”* - 实际上,您可以(本地)更改引用。您无法更改的是*在调用上下文中获取引用的变量*。只有当人们将引用和保存引用的变量混为一谈时,这才会令人困惑。 (2认同)

sak*_*dar 13

不,这是错的.数组是Java中的特殊对象.所以它就像传递其他对象传递引用的值,而不是引用本身.意思是,更改被调用例程中数组的引用将不会反映在调用例程中.


Ste*_*ath 6

数组的权威讨论位于http://docs.oracle.com/javase/specs/jls/se5.0/html/arrays.html#27803。这清楚地表明 Java 数组是对象。这些对象的类在 10.8 中定义。

语言规范的第 8.4.1 节http://docs.oracle.com/javase/specs/jls/se5.0/html/classes.html#40420描述了如何将参数传递给方法。由于 Java 语法源自 C 和 C++,因此行为类似。基本类型按值传递,与 C 一样。传递对象时,对象引用(指针)按值传递,镜像按值传递指针的 C 语法。参见4.3.1,http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.3

实际上,这意味着在方法内修改数组的内容会反映在调用作用域中的数组对象中,但为方法内的引用重新分配新值对调用作用域中的引用没有影响。这正是您所期望的 C 结构体指针或 C++ 对象指针的行为。

术语上的混乱至少部分源于 C 语言普遍使用之前的高级语言的历史。在以前流行的高级语言中,应尽可能避免通过地址直接引用内存,而且被认为是语言的工作是提供一个抽象层。这使得该语言有必要显式支持从子例程(不一定是函数)返回值的机制。这种机制就是“按引用传递”的正式含义。

当 C 被引入时,它带来了过程调用的精简概念,其中所有参数都是仅输入的,并且返回给调用者的唯一值是函数结果。然而,传递引用的目的可以通过指针的显式和广泛使用来实现。由于它具有相同的目的,因此将指针作为值的引用传递的做法通常通俗地称为按引用传递。如果例程的语义要求通过引用传递参数,则C语法要求程序员显式传递指针。按值传递指针是在 C 中实现按引用传递语义的设计模式。

由于 C 中原始指针的唯一目的通常看起来是创建崩溃错误,因此后续开发(尤其是 Java)已寻求返回更安全的参数传递方法。然而,C 的主导地位使得开发人员有责任模仿熟悉的 C 编码风格。结果是引用的传递方式与指针类似,但实现了更多保护以使它们更安全。另一种选择是使用 Ada 等语言的丰富语法,但这会带来不受欢迎的学习曲线,并降低 Java 的采用可能性。

简而言之,Java中对象(包括数组)参数传递的设计本质上是为了服务于引用传递的语义意图,但是是通过值传递引用的语法来实现的。