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)
原因
这里显示的结果正确的,虽然形参是对实参的拷贝,但是修改的内容都是对同一个堆中对象的修改。所以在方法调用后,可以完成对内容的修改。