基本概念
传值
:传递的是值的副本。方法中对副本的修改,不会影响到调用方。传引用
:传递的是引用的副本,共用一个内存,会影响到调用方。此时,形参和实参指向同一个内存地址。对存储了引用副本(对象的地址)的引用变量的修改,如设置为null,重新指向其他对象,不会影响到调用方。其实,在Java中所有的参数都是传值的,引用符号&的传递是C++中才有的。对于普通对象(非fianl修饰的类类型对象)而言,不是将对象本身传递给方法,而是将对象的引用或者说对象的首地址传递给方法,对于引用变量来说,它是按值传递的,传递的是本身存储的对象的地址的副本,但由于这种传值的确让形参和实参指向同一个内存地址,使得形参对自身引用对象的修改会实际影响到实参,所以可把普通对象传递给形参的方式称为伪引用方式。
代码示例
传值
传递基本数据类型的值(byte/byte[],short/short[],int/int[],long/long[],double/double[],float/float[],char/char[],boolean/boolean[])。
// 基本数据类型
public class ParamChangeValue {
public static void main(String[] args) {
int s=11;
System.out.println("s="+s);
change(s);
System.out.println("s="+s);
}
private static void change(int i){
i = 22;
}
}
运行结果
s=11
s=11
从运行结果可知,把int类型的变量s
(实参)传递进方法,并且在方法中这个参数(形参)也进行了修改后,实参s并没有被修改,即传值传递传的是值的副本,而不会影响到本身。
传引用
传递普通类类型的对象。
// 对象
class A {
public int a = 0;
public int b = 0;
public A(int a, int b) {
this.a = a;
this.b = b;
}
public void print(){
System.out.println("a="+a+",b="+b);
}
}
public class ObjectChangeValue {
private static void changeObject(A bb){
bb.a=33;
bb.b=44;
}
public static void main(String[] args) {
A aa = new A(11, 22);
aa.print();
changeObject(aa);
aa.print();
}
}
运行结果
a=11,b=22
a=33,b=44
从运行结果可知,对象aa的a和b属性被修改了,这说明方法调用语句changeObject(aa);
并不是把aa所引用的对象的副本赋给bb,而是把aa所引用的对象的地址赋给了bb,如此,对bb的修改即为对aa的修改。地址即为引用,因为引用类型变量aa存储的是aa所引用对象的地址,而方法调用时传递的就是aa所引用对象的地址,即是把aa的副本传递了进去,从这一点看,这所谓的“传引用”也是“传值”,传给形参的是实参的副本。而由于这个副本不是对象本身,而是对象的地址,即引用,因此,也把引用类型的实参和形参之间的传递也被称为“传引用”。另外要注意一点的是,如果对象被重新创建或赋值为null,即new会重新指向其他对象,不影响其原对象的值。
传引用(final)
传递由final修饰的类类型的对象,如传递String、Integer等immutable(不变的)类型的对象。
// String、Integer、Long等
public class StringChangeValue {
public static void main(String[] args) {
String aa="string_aa";
System.out.println(aa);
changeString(aa);
System.out.println(aa);
}
private static void changeString(String bb){
bb="string_bb";
}
}
输出:
string_aa
string_aa
从运行结果可知,String类型的变量aa并没有改变,原因是String、Integer、Double等immutable(不变的)类型是被final修饰的,是final的,由这些类型所定义的变量所引用的对象是不可修改的,只能给变量重新赋值或生成对象。
总结
基本类型(byte,short,int,long,double,float,char,boolean)为传值;对象类型(Object,数组,容器)为传引用;String、Integer、Double等immutable类型因为类的变量设为final属性,无法被修改,只能重新赋值或生成对象。当Integer作为方法参数传递时,对其赋值会导致原有的引用被指向了方法内的栈地址,失去原有的的地址指向,所以对赋值后的Integer做任何操作都不会影响原有值。