当我们在调用一个有参方法时,会把实际参数传递给形式参数。
这个传递过程中有两种情况,分别是值传递和引用传递。
我们来看下程序语言中是如何定义和区分值传递和引用传递的。
值传递(pass by value)是指在调用方法时将实际参数拷贝一份传递到方法中,这样在方法中如果对参数进行修改,不会影响到实际参数。
引用传递(pass by reference)是指在调用方法时将实际参数的地址传递到方法中。在方法中对参数进行的修改,会影响到实际参数。
public static void main(String[]args){
int number=10;
int i = System.identityHashCode(number);
change(number);
// System.out.println("***方法后****,内存地址为"+i);
System.out.println("***方法后****,值为"+number);
}
public static void change(int a){
a=20;
int i = System.identityHashCode(a);
// System.out.println("***方法中****,内存地址为"+i);
System.out.println("***方法中****,值为"+a);
}
上面代码里,我们在main方法声明一个变量number,通过change方法想要修改number的值,但是结果如下:
***方法中****,值为20
***方法后****,值为10
发现,change方法并没有改变实际参数(number)的值。
有人通过这个例子就确定了,java就是值传递。
但也有人不认可,认为是引用传递的,看下代码:
public static void main(String[]args){
Dog dog=new Dog();
dog.setAge(1);
change(dog);
System.out.println("***方法后****,年龄为"+dog.getAge());
}
public static void change(Dog dog){
dog.setAge(2);
System.out.println("***方法中****,年龄为"+dog.getAge());
} public static void main(String[]args){
Dog dog=new Dog();
dog.setAge(1);
change(dog);
System.out.println("***方法后****,年龄为"+dog.getAge());
}
public static void change(Dog dog){
dog.setAge(2);
System.out.println("***方法中****,年龄为"+dog.getAge());
}
上面代码里,change方法中传入的实际参数是一个dog对象,结果输出如下:
***方法中****,年龄为2
***方法后****,年龄为2
这个时候参数的值发生了改变,有人就会得出结论(错误的):java中传递普通类型是值传递,传递对象是引用传递。
接下来,再看一段代码:
public static void main(String[]args){
String str="hello";
change(str);
System.out.println("***方法后****,内存地址为"+System.identityHashCode(str));
System.out.println("***方法中****,值为"+str);
}
public static void change(String a){
System.out.println("***方法中****,第一次内存地址为"+System.identityHashCode(a));
a="world";
System.out.println("***方法中****,第二次内存地址为"+System.identityHashCode(a));
System.out.println("***方法中****,值为"+a);
}
上面代码的输出结果为:
***方法中****,第一次内存地址为460141958
***方法中****,第二次内存地址为1163157884
***方法中****,值为world
***方法后****,内存地址为460141958
***方法中****,值为hello
都知道,String str="hello" 等同于 String str=new String("hello")。
str作为对象通过change方法传递,按照之前的例子,此时传递的对象应该是改变实际参数值啊。
其实,在方法调用前,我们创建了str引用,指向了“hello”,然后调用方法时,将str引用作为实际参数进行传递。此时,a变量的值等同于str的值,值为引用地址(0x10),同时指向“hello”。
然后我们让a=“world”,意思就是让a重新申请一块内存空间(创建对象),覆盖原来的引用地址(新的地址0x11)。此时a和str已经毫无关系,所以在被调方法中输出的都是a的值。但是主调方法中输出str的值还是原来的对象没有发生变化,依然是“hello”。
值传递和引用传递的区别:
值传递会拷贝一个副本,引用传递不会创建副本。
java中,
值传递中参数是基本类型,传递的是字面量值得拷贝。
值传递中参数是引用类型,传递的是该变量所引用的对象在堆中地址值的拷贝。