Java 为什么ArrayList副本的行为与整数副本不同?

Java 为什么ArrayList副本的行为与整数副本不同?,java,arraylist,reference,Java,Arraylist,Reference,我遇到了一个问题,可以简化为这样的问题: public static void main(String[] args) { ArrayList<String> firstList = new ArrayList<>(); firstList.add("Hello"); firstList.add("World"); firstList.add("This"); firstList.add("Is"); firstList.a

我遇到了一个问题,可以简化为这样的问题:

public static void main(String[] args) {
    ArrayList<String> firstList = new ArrayList<>();
    firstList.add("Hello");
    firstList.add("World");
    firstList.add("This");
    firstList.add("Is");
    firstList.add("A");
    firstList.add("Test");

    System.out.println("Size of firstList: " + firstList.size());

    ArrayList<String> tempList = firstList;
    System.out.println("Size of tempList: " + tempList.size());

    firstList.clear();
    System.out.println("Size of firstList: " + firstList.size()); // should be 0
    System.out.println("Size of tempList: " + tempList.size());
}
我希望第二轮
templast
的大小是
6
,而不是
0

已经有一些与这种效应相关的问题,例如和

从答案中,我发现这是因为
templast
引用了与
firstList
相同的引用,所以当
firstList
发生变化时,
templast
也会发生变化(如果我错了,请纠正我)

因此,更好的解决方案是:

ArrayList<String> tempList = new ArrayList<String>(firstList);
给出以下输出:

firstValue: 5
tempValue: 5
firstValue: 3
tempValue: 5
?

第二次打印时,
tempValue
是否也应为
3


我觉得我误解了引用的工作原理,所以有人能解释一下为什么第一个示例中的临时列表和原始列表会同时受到影响,而临时整数和原始整数给出的结果与第二个示例中的不同吗?

因为基元值没有引用,而且包装器类型是不可变的(因此
Integer
的行为方式相同)。作为反例,数组是引用类型(甚至是基元数组)。所以


另请参见,

,因为原语值没有引用,而且包装类型是不可变的(因此
Integer
的行为方式相同)。作为反例,数组是引用类型(甚至是基元数组)。所以


另请参见,

有关ArrayList示例,这两个变量都指向堆内存中其他位置的同一对象,因此更改一个引用的内容会影响另一个引用


对于integer示例,当前行为是预期的,因为它们是基元类型而不是引用类型。对于基元类型,变量存储值本身而不是内存中对象的引用。

对于ArrayList示例,两个变量都指向堆内存中其他位置的同一对象,因此更改一个引用的内容会影响另一个引用


对于integer示例,当前行为是预期的,因为它们是基元类型而不是引用类型。对于基元类型,变量存储的是值本身,而不是内存中对象的引用。

Java有两种变量类型:基元和引用。将一个变量分配给另一个变量时,如

ArrayList<String> tempList = firstList;
您正在做同样的事情,但是使用一个原始值


一般来说,这样想。变量不共享内存位置;每个变量都有自己的值。但是,当值是引用时,两个引用变量可能包含相同的引用(正如两个基本变量可能包含相同的基本值,如
5
)。对于引用类型,如果使用一个变量更改被引用对象的内容,则通过第二个变量访问时,将看到该对象中的更改。在计算机科学文献中,这种行为被称为。对于原语,这种别名不会发生。

Java有两种变量类型:原语和引用。将一个变量分配给另一个变量时,如

ArrayList<String> tempList = firstList;
您正在做同样的事情,但是使用一个原始值


一般来说,这样想。变量不共享内存位置;每个变量都有自己的值。但是,当值是引用时,两个引用变量可能包含相同的引用(正如两个基本变量可能包含相同的基本值,如
5
)。对于引用类型,如果使用一个变量更改被引用对象的内容,则通过第二个变量访问时,将看到该对象中的更改。在计算机科学文献中,这种行为被称为。对于原语,这种别名不会发生。

int tempValue是一种原语类型,意味着它直接按值存储
ArrayList tempList
不是基元类型,因此通过引用存储

您在
int
中看到的情况也会发生在所有其他Java静态类型原语变量中。同时,只要Java非原语变量引用的实例的值发生变化,Java非原语变量就会在发生变化时发生变化


(这引出了一个后续问题:
templast
当您使用
firstList=new ArrayList()
而不是
firstList.clear()
?它的值在重新分配和变异之间是相同的吗?为什么?

int tempValue
是一个基本类型,这意味着它直接按值存储
ArrayList tempList
不是基元类型,因此通过引用存储

您在
int
中看到的情况也会发生在所有其他Java静态类型原语变量中。同时,只要Java非原语变量引用的实例的值发生变化,Java非原语变量就会在发生变化时发生变化

(这引出了一个后续问题:
templast
当您使用
firstList=new ArrayList()
而不是
firstList.clear()
,它的值在重新分配和变异之间是相同的吗?为什么?)

int[] arr = { 1 };
int[] arrCopy = Arrays.copyOf(arr, arr.length); // <-- deep copy
int[] b = arr; // <-- shallow copy
b[0] = 2; // <-- same as arr[0] = 2
System.out.printf("arr = %s, arrCopy = %s, b = %s%n", //
        Arrays.toString(arr), Arrays.toString(arrCopy), //
        Arrays.toString(b));
arr = [2], arrCopy = [1], b = [2]
ArrayList<String> tempList = firstList;
int tempValue = firstValue;