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

时间:2012-10-06 07:44:16

标签: java arrays

  

可能重复:
  Is Java “pass-by-reference”?

数组在Java中不是primitive type,但它们是are not objects either,它们是通过值还是通过引用传递的?它取决于数组包含的内容,例如引用或基本类型吗?

7 个答案:

答案 0 :(得分:194)

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

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

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

见这篇文章..

Is Java "pass-by-reference" or "pass-by-value"?

请参阅此工作示例: -

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..
}

答案 1 :(得分:95)

你的问题是基于错误的前提。

  

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

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

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

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

以下是一些解释“传递参考”和“传递价值”之间区别的链接:

相关问题:

历史背景:

短语“pass-by-reference”最初是“引用调用”,它用于区分传递FORTRAN语义(通过引用调用)和ALGOL-60语义的参数(调用 - 按价值和按名称呼叫)。

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

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

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

<强>更新

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


1。链接的Q&amp; A(Arrays in Java and how they are stored in memory)中没有任何内容表明或暗示数组不是对象。

答案 2 :(得分:59)

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

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

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

// assuming you allocated the list
public void changeArray(Integer[] list) {
    list = null;
}

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

答案 3 :(得分:13)

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

答案 4 :(得分:4)

Java中的所有内容都按值传递。

对于数组,引用被复制到新引用中,但请记住Java中的所有内容都是按值传递的。

请查看this interesting article以获取更多信息......

答案 5 :(得分:2)

对数组的最终讨论是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中对象(包括数组)的参数传递设计实际上是为了提供通过引用传递的语义意图,但是使用了语法 strong>按值传递引用。

答案 6 :(得分:0)

有点诡计......甚至引用都是通过Java中的值传递的,因此对引用本身的更改是在被调用函数级别的作用域。编译器和/或JVM通常会将值类型转换为引用。