最近在工作中踩到了一个坑,就是Java的值传递和引用传递。对于值传递和引用传递定义有了解,但编写代码时没有特别注意。因为这个原因导致一个重大的线上bug,这个是不可原谅的。由此决定把这些内容再次牢记,记录下来。
作为一个工作几年还犯这个错误真是太惭愧!!
定义
- 传值
传递的是值的副本。方法中对副本的修改,不会影响到调用方 - 传引用:
传递的是引用的副本,共用一个内存,会影响到调用方。
此时,形参和实参指向同一个内存地址。
对引用副本本身(对象地址)的修改,如设置为null,重新指向其他对象,不会影响到调用方。
基本数据类型
public class ParamChangeValue {
public static void main(String[] args) {
int s = 1;
System.out.println("args = [" + s + "]");
change(s);
System.out.println("args = [" + s + "]");
}
private static void change(int i){
i = i* 5;
}
}
输出
args = [1]
args = [1]
对象
public class ObjectChangeValue {
public static class Score{
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
public static void main(String[] args) {
Score score = new Score();
score.setValue(1);
System.out.println("args = [" + score.getValue() + "]");
change(score);
System.out.println("after args = [" + score.getValue() + "]");
}
private static void change(Score score){
score.setValue(2);
}
}
输出
args = [1]
after args = [2]
注:
如果对象被重新创建或赋值为null,即new则会重新指向其他对象,不影响其远对象的值
public class ObjectChangeValue {
public static class Score{
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
public static void main(String[] args) {
Score score = new Score();
score.setValue(1);
System.out.println("args = [" + score.getValue() + "]");
change(score);
System.out.println("after args = [" + score.getValue() + "]");
}
private static void change(Score score){
score = new score();
}
}
输出
args = [1]
after args = [1]
String、Integer、Long等
public class StringChangeValue {
public static void main(String[] args) {
String s = "test1";
System.out.println("args = [" + s + "]");
change(s);
System.out.println("args = [" + s + "]");
}
private static void change(String i){
i = i + " test value";
}
}
输出
args = [test1]
args = [test1]
总结
- 基本类型(byte,short,int,long,double,float,char,boolean)为传值
- 对象类型(Object,数组,容器)为传引用
- String、Integer、Double等immutable类型因为类的变量设为final属性,无法被修改,只能重新赋值或生成对象。
当Integer作为方法参数传递时,对其赋值会导致原有的引用被指向了方法内的栈地址,失去原有的的地址指向,所以对赋值后的Integer做任何操作都不会影响原有值。