Java中的数组是按引用传递还是按值传递?
假设我有一个名为data
的数组,其中包含某种类型的对象。现在让我们假设我将该数组传递并存储在类A中,然后将其传递到类B中,并且类B更改了数组中的一个条目。类A版本的数组会改变吗?如果这是原语类型的数组(例如int
),会有什么影响吗?那么ArrayList呢?
Java中的数组是按引用传递还是按值传递?
假设我有一个名为data
的数组,其中包含某种类型的对象。现在让我们假设我将该数组传递并存储在类A中,然后将其传递到类B中,并且类B更改了数组中的一个条目。类A版本的数组会改变吗?如果这是原语类型的数组(例如int
),会有什么影响吗?那么ArrayList呢?
Java中的所有内容都是按值传递的。但是,如果您传递引用,则是引用的值。
由于Java方法无法访问调用者的堆栈以重新分配变量,因此任何方法调用都无法更改引用(地址)的标识符。这就是我们所说的Java不是按引用传递的含义。这与C ++(以及类似语言)形成对比,后者在某些情况下允许这样做。
现在让我们看一些效果。
如果我执行以下操作:
Object[] o = ...
mutateArray(o);
接下来的内容可能会有所不同,因为mutateArray
只需要一个数组的地址就可以改变其内容。但是o
的地址将保持不变。如果我执行:
String x = "foo";
tryToMutateString(x);
x
的地址在此之后仍然相同。由于字符串是不可变的,这意味着它仍将是"foo"
。o
的最后一个元素,或尝试将“foo”的最后一个字母更改为'd')。这不应与在调用者的堆栈中重新分配x
或o
混淆(不可能)。Java中的所有内容都是按值传递的,这很令人困惑,因为当我们在Java中创建一个对象或数组时,我们将该对象的地址存储在变量中(而不是对象本身)。因此,当我们将该变量传递给一个方法时,该方法会获取该地址(即一个值)并将其存储在其本地变量中。对本地变量所做的任何更改都不会反映在原始变量中。
然而,我们可以使用包含对象地址的本地变量来访问对象的字段和方法。同样,数组也是一个对象。
以下是如何利用所有这些知识:
package newStart;
import java.util.Arrays;
public class JavaIsAlwaysCallByValueArray {
static void swap(int[] a,int[] b )
{
int[] temp=a;
a=b;
b=temp; //all this is doing is swapping the address of local variables
of this method which will not be reflected in main method
}
static void swapThisWay(int[] a,int b[])
{
int[] temp=new int[b.length];
for(int i=0;i<a.length;i++) //here we are using this variable to
access field of array object
temp[i]=a[i];
for(int i=0;i<b.length;i++)
{
a[i]=b[i];
}
for(int i=0;i<b.length;i++)
b[i]=temp[i];
`enter code here`}
public static void main(String args[])
{
int a1[]= {1,2,4,6,8};
int a2[]= {6,5,3,8,9};
swap(a1,a2);
System.out.println("just swap \na1 : "+Arrays.toString(a1)+"\na2 :
"+Arrays.toString(a2));
swapThisWay(a1,a2);
System.out.println("Now \na1 : "+Arrays.toString(a1)+"\na2 :
"+Arrays.toString(a2));
}
}
数组和其他对象一样,是按引用传递的(从技术上讲,你是通过值传递引用,但从对象的角度来看,它是按引用传递的)。如果你将一个数组传递给一个方法,并且该方法更改了数组,调用者将看到这些更改。如果你想避免副本被修改,你需要自己复制它。无论数组包含原始类型还是对象,都没有关系。通常,这是你想要的行为,因为按值传递会在每次使用它作为参数时不必要地复制(可能很大的)数组。
Java的要点是 - 除非它是原始类型,否则Java中的所有内容都是按引用传递的。