什么是值传递 和 引用传递?
值传递:在调用函数时将实参复制一份给形参,在函数中修改形参不会影响实参。
引用传递:在调用函数时将实参的地址直接给形参,在函数中修改形参会影响实参。
值传递和引用传递的区别?
给的是实参值的备份,还是实参值。
生活举例:我家大门只有1把钥匙,朋友要我家的钥匙。
- 值传递:我配了把备用钥匙给朋友。
- 引用传递:我把仅有的那把钥匙给朋友。
问题一:不是说值传递形参修改不会影响实参吗?
方法A的入参是对象,方法A中修改对象的属性;方法B创建对象,调用方法A,输出对象,发现对象的属性变了;不是违反了吗?
答:见下代码。functionB中new Car并给age赋值1,调用functionA修改age为2,functionB输出car,发现age变成2。
- 首先:引用类型的变量的值是地址,指向堆空间的对象。functionB中的变量car的值是地址。
- 其次:方法调用会备份实参的值,传递给形参。functionB备份变量car的值(也就是地址),传递给functionA。
- 最后:functionA根据地址找到堆空间的对象,修改对象的属性。但是,functionB中的变量car的值 (地址) 没变,变的是地址指向的对象的属性。
public class ParamTest {
public void functionA(Car car){
car.setAge(2);
}
/**
* 代码注意点:
* Car类没有重写equals 和 hashCode方法,默认用的是Object类的方法。
* Object类的hashCode方法返回对象在堆空间的地址的hash码。
* 所以调用hashCode方法,一定程度上可以表示对象的地址。
*/
public void functionB(){
Car car = new Car("五菱宏光",1);
System.out.println("调用A方法前地址的hash值:"+car.hashCode());
System.out.println("调用A方法前内容:"+car);
functionA(car);
System.out.println("调用A方法后地址的哈希值:"+car.hashCode());
System.out.println("调用A方法后内容:"+car);
}
public static void main(String[] args){
ParamTest test = new ParamTest();
test.functionB();
}
}
输出结果:
调用A方法前地址的hash值:821270929
调用A方法前内容:Car{name='五菱宏光', age=1}
调用A方法后地址的哈希值:821270929
调用A方法后内容:Car{name='五菱宏光', age=2}
问题二:不是说引用类型传递的是地址吗,为什么String类型的数据作为形参并修改,调用方根据地址找到对象,发现没变?
答:见下代码。stringB中new String并赋值“abc”,调用stringA修改为“ab”,stringB输出发现还是“abc”。
- 首先:String类的对象具有不可变性,值一旦确定就不能变。
- 其次:String s1 = new String("abc"),先在堆空间创建对象,再在字符串常量池创建“abc”,堆空间的对象保存常量池“abc”的地址。结果:s1的值是堆空间String对象的地址,堆空间String对象存的是常量池中“abc”的地址。
- 最后:
- stringA中str的值是常量池中“ab”的地址。stringA中str="ab",会先去常量池找等于“ab”的字符串,没找到就新增“ab”字符串。
- stringB中s1是堆空间String对象的地址,对象存的是堆空间“abc”的地址。
public class ParamTest {
public void stringA(String str){
str = "ab";
}
public void stringB(){
String s1 = new String("abc");
stringA(s1);
System.out.println(s1);
}
public static void main(String[] args){
ParamTest test = new ParamTest();
test.stringB();
}
}
输出
abc