将对象(通过引用)传递给方法时,对象不会更新(通过 Lambdas 过滤器)
Object is not updated (by Lambdas filter) when passing it (by reference) to a method
我正在使用 java8
、SpringBoot 2
和 JPA2
,但我 运行 遇到了一个奇怪的问题。假设如下代码:
public void doSome() {
List<Integer> arr = new ArrayList<>(Arrays.asList(1,2,3,4,5));
List<Integer> arr2 = new ArrayList<>(Arrays.asList(1,2,3,4));
otherMethod(arr, arr2);
System.out.println(arr);
}
在同一个 class 我有 otherMethod()
和这个版本:
public void otherMethod(List<Integer> arr, List<Integer> arr2) {
arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());
System.out.println(arr); // here print just 5
}
当代码流将我带回到 doSome()
:
System.out.println(arr); // print [1,2,3,4,5]
如果我按如下方式更改 otherMethod()
:
public void otherMethod(List<Integer> arr, List<Integer> arr2) {
// arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());
arr.removeIf(x -> x < 3);
System.out.println(arr); // print [3,4,5]
}
并且更改会影响我通过引用传递的对象,在 doSome()
方法中我看到:
System.out.println(arr); // print [3,4,5]
我不明白为什么 arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList())
更改不会影响我通过引用传递的对象。
我哪里错了?
首先我想说的是Java只有值传递,没有引用传递。
这个post
中明确提到了这一点
让我们遍历您的代码。
public void doSome() {
//Memory is allocated in heap for two new array lists
// and the address of each copied to arr, arr2 variables respectively.
List<Integer> arr = new ArrayList<>(Arrays.asList(1,2,3,4,5));
List<Integer> arr2 = new ArrayList<>(Arrays.asList(1,2,3,4));
// Here you are passing the value stored in arr and arr2 variables.
// And the called method copies the values to another set of variables defined as parameters in the called method.
otherMethod(arr, arr2);
// Print the content of the object(ArrayList) whose address is stored in arr variable.
System.out.println(arr);
}
public void otherMethod(List<Integer> arr, List<Integer> arr2) {
// When this method is called, Two variable are created. The value of parameters from the calling method will be copied to these variables.
//Here Collectors.toList() creates a new list after going through stream and filter.
// And then you are assigning the new list to arr varibable.
//Which means arr stores the reference to newly created list and loses the reference to original list.
// This statement will not affect the arr variable in doSome()
arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());
//Printing the value of list and this list is different from the called list
System.out.println(arr); // here print just 5
}
其他方法中的 arr.removeIf(x -> x < 3);
在 doSome()
中生效,因为 arr 仍指向相同的堆位置。
如果你想在doSome()
方法中修改列表,你有两个选择。
- return新的arraylist形成调用方法并在调用方法中使用它。
- 或者将新的筛选列表复制到另一个临时变量。清除 arr 变量指向的列表,然后将过滤列表中的所有项目添加到 arr 变量。
我正在使用 java8
、SpringBoot 2
和 JPA2
,但我 运行 遇到了一个奇怪的问题。假设如下代码:
public void doSome() {
List<Integer> arr = new ArrayList<>(Arrays.asList(1,2,3,4,5));
List<Integer> arr2 = new ArrayList<>(Arrays.asList(1,2,3,4));
otherMethod(arr, arr2);
System.out.println(arr);
}
在同一个 class 我有 otherMethod()
和这个版本:
public void otherMethod(List<Integer> arr, List<Integer> arr2) {
arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());
System.out.println(arr); // here print just 5
}
当代码流将我带回到 doSome()
:
System.out.println(arr); // print [1,2,3,4,5]
如果我按如下方式更改 otherMethod()
:
public void otherMethod(List<Integer> arr, List<Integer> arr2) {
// arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());
arr.removeIf(x -> x < 3);
System.out.println(arr); // print [3,4,5]
}
并且更改会影响我通过引用传递的对象,在 doSome()
方法中我看到:
System.out.println(arr); // print [3,4,5]
我不明白为什么 arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList())
更改不会影响我通过引用传递的对象。
我哪里错了?
首先我想说的是Java只有值传递,没有引用传递。
这个post
中明确提到了这一点让我们遍历您的代码。
public void doSome() {
//Memory is allocated in heap for two new array lists
// and the address of each copied to arr, arr2 variables respectively.
List<Integer> arr = new ArrayList<>(Arrays.asList(1,2,3,4,5));
List<Integer> arr2 = new ArrayList<>(Arrays.asList(1,2,3,4));
// Here you are passing the value stored in arr and arr2 variables.
// And the called method copies the values to another set of variables defined as parameters in the called method.
otherMethod(arr, arr2);
// Print the content of the object(ArrayList) whose address is stored in arr variable.
System.out.println(arr);
}
public void otherMethod(List<Integer> arr, List<Integer> arr2) {
// When this method is called, Two variable are created. The value of parameters from the calling method will be copied to these variables.
//Here Collectors.toList() creates a new list after going through stream and filter.
// And then you are assigning the new list to arr varibable.
//Which means arr stores the reference to newly created list and loses the reference to original list.
// This statement will not affect the arr variable in doSome()
arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());
//Printing the value of list and this list is different from the called list
System.out.println(arr); // here print just 5
}
其他方法中的 arr.removeIf(x -> x < 3);
在 doSome()
中生效,因为 arr 仍指向相同的堆位置。
如果你想在doSome()
方法中修改列表,你有两个选择。
- return新的arraylist形成调用方法并在调用方法中使用它。
- 或者将新的筛选列表复制到另一个临时变量。清除 arr 变量指向的列表,然后将过滤列表中的所有项目添加到 arr 变量。