详解java参数传递
言简意赅的介绍java中值传递与参数传递
1.值传递与引用传递的定义
值传递:
方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。
1.基本类型作为参数传递
1.1基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的
/**
* @author wang7
*测试java中值的传递
*/
public class ValueTest {
public static void main(String[] args) {
int a = 1;
System.out.println("Before a = " + a);
changeData(a);
System.out.println("After change a = " + a);
}
//测试基本数据类型变为参数传递时值的变化
private static void changeData(int a) {
// TODO Auto-generated method stub
a = 10;
}
}
//输出结果:
//Before a = 1
//After change a = 1
1.2堆栈信息
这种类型如int=3的形式来定义,称为自动变量。自动变量存在的是字面值,即不是类的实例,也不是类的引用。a 是一个指向int类型的引用,指向3这个字面值。这些字面值的数据由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退了,字段值就消失了),处于追求速度的原因就存在栈中。
2.对象作为参数传递
2.1.对象作为参数传递时,是把对象在内存中的地址拷贝了一份传给了参数。
/**
* @author wang7
*参数为引用类型时值的传递
*/
public class ValueTest {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("Before sb = " + sb);
changeData(sb);
System.out.println("After sb = " + sb);
}
public static void changeData(StringBuffer strBuf) {
strBuf.append("World!");
}
}
//输出结果:
//Before sb = Hello
//After sb = Hello World!
2.2堆栈信息:
未执行 strBuf.append(“World!”);的堆栈中的信息,现在这种情况下引用变量作为参数传递时传递的是地址
在Java中对象作为参数传递时,是把对象在内存中的地址拷贝了一份传给了参数。
/**
* @author wang7
*参数为引用类型时值的传递
*/
public class ValueTest {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("Before sb = " + sb);
changeData(sb);
System.out.println("After sb = " + sb);
}
public static void changeData(StringBuffer strBuf) {
strBuf = new StringBuffer("HHH ");
strBuf.append("World!");
}
}
堆栈信息
3.特别注意final修饰的类
这里要特殊考虑String,以及Integer、Double等基本类型包装类,它们的类前面都有final修饰,为不可变的类对象,每次操作(new或修改值)都是新生成一个对象,对形参的修改时,实参不受影响,与值传递的效果类似,但实际上仍是引用传递。
总结:
1)基本类型变量作为方法中的参数,进行的值传递,对形参的修改不影响实参的原来的值;
2)非final修饰的类、数组、接口作为方法中的参数,进行的传递,对形参修改后实参也会改变,因为二者指向的是同一个实例;
3)final修饰的类作为方法中的参数,因为final的存在初始化后值不可变,每次操作都相当于产生一个新的实例对象,因此对形参修改时,实参也不受影响。