值传递:是指在调用函数时将实际参数复制一份传递给形参,这样在函数中对形参的修改将不会影响到实际参数的值。
引用传递:是指在调用函数时将实际参数的地址直接传递到形参,那么在函数中对参数所进行的修改,将会影响到实际参数的值。
java怎么传值?
java的传值方式:值传递(所有发生的变化只限制在方法体中,出了方法体,任何的修改操作都不再有效)。【推荐学习:java课程】
我们可以使用一段程序来验证Java中只有值传递
class User{
private String name; public String getName() { return name;
} public void setName(String name) { this.name = name;
}
}public class TestValue { public static void change(User user2,int a2){
System.out.println("改变之前:"+user2.getName()+",a2="+a2);
user2.setName("李四"); //改变 user2 的 name 值
a2 = 10; //改变 a2 的值
System.out.println("改变之后:"+user2.getName()+",a2="+a2);
user2 = new User(); //将 user2 重新指向一个新对象
user2.setName("王五");
System.out.println("重新指向一个新对象后:"+user2.getName());
} public static void main(String[] args){
User user1 = new User();
user1.setName("张三"); //初始化 user1 的 name 为张三
int a1 = 5; //初始化 a1 的值为 5
change(user1,a1); //调用方法验证传值方式
System.out.println("调用方法后:"+user1.getName()+",a1="+a1);
}
}
运行这段程序,输出结果为:
改变之前:张三,a2=5
改变之后:李四,a2=10
重新指向一个新对象后:王五
调用方法后:李四,a1=5
结果分析
下面我们以上图为辅助,来分析这段程序,首先我们定义了一个User
类,然后在测试类中实例化了一个User
对象,名为user1
,并且为其赋值name = '张三'。
此时在内存中如图1
所示,实例化一个对象相当于在堆中开辟了一块内存,内存地址为017
,此时这个对象的引用为user1
,内存地址为001
,它保存了该对象在内存中的地址,也就是指向了该对象。
接下了,我们调用方法change()
,来尝试改变user1
的name
值以此验证java中的传值方式。
我们将user1
作为实参传给change()
方法,形参user2
来接受这个实参,在这里就体现出了两种传参方式的不同。如果是按值传递,那么就像定义的那样。
如图2
所示,user2
是user1
的一份副本,也就是说在传递参数时,将user1
(本身是一个对象的引用),复制了一份,名为user2
,它同样也是一个对象的引用,并且user1
和user2
此时指向同一个对象。
而如果是引用传递,也如同定义的那样,如图5
所示,在传递参数时,是直接将user1
传递给了形参,只是换了一个名字叫做user2
,但是本质上user1
和user2
其实是同一个。它是一个对象的引用。
接着来分析输出的结果,不管是按值传递还是引用传递,第1行输出的结果一定都是张三
,因为都是指向同一个对象。对于第2行输出,我们还是无法判断是哪种方式,因为都是改变同一个对象,值也会改变;关键在于第3行输出和第4行输出。
此时,我们将user2
重新指向了一个新的对象,并且为这个对象赋值name = '王五'
,如果是引用传递的方式,那么user1
同样也会改变指向,指向新的这个对象,最后一行调用方法之后输出的结果将会和第3行一样是王五
,但是事实输出的是李四
。这表明user1
和user2
其实并不是同一个。
真实的调用过程如 图2
~图4
所示,这样才会使得user2
指向一个新的对象后,user1
指向的对象并没有改变,还是原来那个对象。
对于基本类型的参数来说,a1
的值最后没有改变,说明在执行方法时,a2
是a1
的一个副本。
对于引用类型的参数来说,例如User
对象,在调用方法时,实际上是将其引用user1
作为实际参数,那么传递给形参的将是该引用的一份副本引用user2
,虽然说这是两份引用(好比a1
与a2
的关系)。
但是却指向同一个对象,所有的操作也都是对这同一个对象而言的。
尾声
通过以上分析我们可以知道。Java中只有值传递这一种方式,只不过对于引用类型来说,传递的参数是对象的引用罢了。