1.1 前言
之前在學習C++語言的時候,將實參傳遞給方法(或函數)的方式分為兩種:值傳遞和引用傳遞,但在JAVA中只有值傳遞(顛覆認知,基礎沒學踏實)
參考文章:https://blog.csdn.net/aaaa_1111111/article/details/143747247
1.2 幾個值傳遞示例
1. Boolean類型值傳遞問題
demo
// Boolean類型
@Test
public void BooleanTest() {Boolean bool = false;transmitBoolean(bool);System.out.println(bool);
}
private void transmitBoolean(Boolean bool) {bool = true;
}
結果
false
原因分析
明明傳遞的是引用類型,為什么無法修改呢?
首先Java只支持值傳遞,此時的形參bool是實參的副本(即實參和形參的值都指向值=false的Boolean對象,但是形參時實參的拷貝副本),當我們在方法中修改形參bool的Boolean值的時候,因為Boolean 是不可變的對象,因此在方法中改變它的值時,它并不會影響原始的值,因此會創建一個新的對象并賦值給形參(即拷貝實參的副本),其并沒有影響到實參,因此在該方法調用結束后,實參的值還是false。
調用方法前,實參地址
調用方法中,形參地址
方法中修改Boolean值后,形參地址
解決方法
- 使用
AtomicBoolean
:
AtomicBoolean
是一個可以在多線程環境下保證原子性的類,它是可變的。你可以使用 AtomicBoolean
來避免不可變性的問題。
import java.util.concurrent.atomic.AtomicBoolean;public class Main {public static void main(String[] args) {AtomicBoolean pd = new AtomicBoolean(false);method(pd);System.out.println(pd.get()); // 現在會打印 true}public static void method(AtomicBoolean if1) {if1.set(true); // 修改 AtomicBoolean 的值}
}
AtomicBoolean
使用 get()
方法來獲取值,使用 set()
方法來修改值。
- 使用數組或者容器對象(例如
List
):
如果你不想使用 AtomicBoolean
,你還可以使用一個數組或容器(例如 List
)來傳遞值,因為數組和容器是可變的。
public class Main {public static void main(String[] args) {Boolean[] pd = { false };method(pd);System.out.println(pd[0]); // 現在會打印 true}public static void method(Boolean[] if1) {if1[0] = true; // 修改數組中的值}
}
- 使用
Wrapper
類來返回新值:
如果你不想使用 AtomicBoolean
或容器,你可以通過方法的返回值來返回修改后的 Boolean
值。
public class Main {public static void main(String[] args) {Boolean pd = false;pd = method(pd); // 方法返回修改后的 Boolean 值System.out.println(pd); // 現在會打印 true}public static Boolean method(Boolean if1) {return true; // 直接返回修改后的值}
}
2. Map類型值傳遞問題
demo
// Map
@Test
public void MapTest() {Map<String, String> map = new HashMap<>();map.put("hhh", "123");transmitMap(map);System.out.println(map);
}
private void transmitMap(Map map) {//map.put("hhh", "321");map = new HashMap();map.put("xixi", "321");
}
結果
{hhh=123}
原因分析
和1是一樣原因,在方法中對形參指向引用對象的更改只對形參有效,形參只是對實參的一個拷貝,不會對實參造成影響!
3.正常對象的值傳遞問題
demo
// 自定義引用類型
@Test
public void ClassTest() {A a = new A();a.setId(123L);a.setName("www");transmitClass(a);System.out.println(a);
}
private void transmitClass(A a) {a.setId(321L);a.setName("hhh");
}
@Data
public class A{private Long id;private String name;
}
結果
DemoApplicationTests.A(id=321, name=hhh)
原因
這里顯示的結果正確的,雖然形參是對實參的拷貝,但是修改的內容都是對同一個堆中對象的修改。所以在方法調用后,可以完成對內容的修改。