对于Java初学者来说,Java的值传递可能是学习Java遇到的第一个比较难以理解的概念,一般在初次接触这个概念的时候,会从基本数据类型和引用数据类型进行区分,由此也引出了关于“Java值传递与引用传递”一说,随着深入理解java的传参机制,笔者认为java中确实不存在引用传递,只有值与地址值传递,而如何去理解,只要你java基础知识扎实,值传递看起来一切都是那么自然。
1.基本数据类型
对于基本数据类型一般我们会引用一段特别经典的代码:
public class Demo01 {
//基本类型参数的传递过程
public static void main(String[] args) {
int x = 3;
show(x);
System.out.println(x);
}
public static void show(int x) {
//被省略的传参过程:x = x(3);
x = 4;
// return;
}
}
输出x的值为3,为什么不是4?
注意:当我们调用方法传实参x时,Java语法会帮我们省略一段代码,就是将实参x赋值给形参x的代码。
那为什么要省略呢?原因很简单:
我们封装方法时并不知道传入实参的变量名,赋值等式右边没法写。
但当我们把省略的这一行代码以自己理解的方式添加到注释中去,一切就明朗了。
那么这个show()方法就可以理解为,给方法中的形参x赋了两次值。
接下来我们用局部变量的知识去理解就足够了。
来看看局部变量的概念:
定义:在方法内定义的变量称为“局部变量”或“临时变量”,只在所属区域中有效,方法结束后局部变量占用的内存将被释放。
在main()方法中的定义的变量x就是一个作用域为整个主方法的局部变量,而在下面show()方法参数列表中定义了一个同名的变量x,这两个变量在各自的方法区中都是唯一的,互不相干。
那么接下来,打印main中局部变量x的值,纵使你show方法中的x被赋值一万次,也与他无关。
2.引用数据类型
public class Demo02 {
//引用类型参数的传递过程
int x ;
public static void main(String[] args) {
Demo02 d = new Demo02();
d.x = 9;
show(d);
System.out.println(d.x);
}
public static void show(Demo02 d) {
//省略的传参过程 d=d;
d.x = 4;
}
}
打印结果是4,那为什么这一次show中的局部变量能改变main方法中的局部变量的属性呢?
我们还是把省略的传参过程加上,很显然这一次我们传递进去的引用类型,对于引用类型,“=”的概念就是改变地址值指向。那么这个show()方法就可以理解为,将main方法中d的地址值提供给show中的局部变量d指向。现在,两个局部变量d共同指向一个地址,那不管哪一个都可以访问到此对象的属性,自然可以改变他。
我们再添一行代码
public class Demo02 {
//引用类型参数的传递过程
int x = 3;
public static void main(String[] args) {
Demo02 d = new Demo02();
d.x = 9;
show(d);
System.out.println(d.x);
}
public static void show(Demo02 d) {
//省略的传参过程 d=d;
d=new Demo02();
d.x = 4;
}
}
输出结果为9,为什么这次又没变呢?
原因也很简单,传参时方法中的局部变量d指向了main方法中的Demo02对象地址,还没来得及修改这个对象的属性,就又被覆盖指向了一个新对象的地址值,那你再怎么改,也找不到回家的路了,那么main方法打印的自然是原来的属性。
看过这两个案例,我们再来看看String类的值传递:
public class Demo03 {
public static void main(String[] args) {
String str="111";
change(str);
System.out.println(str);
}
public static void change(String str) {
//省略的传参过程 str=str("111");
str="222";
}
}
输出结果为111,String不是引用数据类型吗?怎么没改变呢?
原因在于String类的对象根本就不可变,任何你以为的改变str的方法其实都是提供新的地址值指向。那么就和上面一个例子一样,show方法中的局部变量str丢失了原来的地址。
上述这些案例,关于java值传递我们可以肯定的是:
①对于基本数据类型,不管方法内部如何变动,不能改变传递给形参的实参变量值。
②对于引用数据类型,不管方法内部如何变动,不能改变传递给形参的实参变量地址指向,但能改变指向对象的属性。
对于引用数据类型,笔者总结了一个通俗易懂的比喻:
实参和形参是两个好朋友,实参把他家的地址告诉形参,形参可以根据地址到实参家住甚至给实参家装修,但是有一天形参找到新家了,就算把新家全部翻新一遍,实参的家还是原来的家。
本文旨在给初学者简单快速的理解值传递的概念,所以没有引入java内存等较抽象的知识,如有错误欢迎指正。