哪有什么引用传递,所有都是值传递
经常看到有人说什么值传递、引用传递,其实都是值传递,区别不过是传的值的类型罢了。
传值方式
java传值有且只有一种方式,将参数的“值”复制后传入,这个“值”是指变量名所对应的地址中存放的值,对于值类型和对象类型,由于地址中存放的东西不同,因此表现有所不同:
- 对于8种值类型,其存放的就是本身的值,因此表现为将值传递到函数中,修改后的值对原值无影响。
- 对于对象来说,其存放的是对象头,里面包含了对象的类型、首地址等。将对象头的值传递到函数中,其仍然能正确指向对象本身。
传递的是值的拷贝,而非其本身
值类型
对于值类型来说
7++;
这种无疑是错误的,因为不能对常量进行修改。任何一个IDE都会报错。
但如果将其作为参数传入
public class ObjTest {
public static void main(String[] args) {
inc(7);
}
private static void inc(int a) {
a++;
System.out.println(a);
}
}
那么就不会报错,并且输出8
。这是因为在传递到函数里面的并不是常量7
,而是一个拷贝int a = 7
,而a
是一个int
类型的变量,因此可以自增。
对象
而对于对象来说,同样如此。
public class ObjTest {
public static void main(String[] args) {
inc(7);
Node n1 = new Node();
f1(n1);
System.out.println("n1 = " + n1);
}
private static void f1(Node node) {
node.a++;
node.b += 2;
node.c += 3;
node.d = new int[]{1, 5};
// 在此设置断点2
node = new Node();
node.a = -1;
node.b = -2;
node.d[0] = 3;
System.out.println("node = " + node);
}
private static void inc(int a) {
a++;
System.out.println(a);
}
}
public class Node {
public int a;
public int b;
public int c;
public int[] d = new int[2];
}
在执行到断点1的时候,如下图所示,可以看到,n1
的所有值都为默认值,地址为0x704
在执行到断点2(此行未执行)时,如下图所示,可以看到,node
指向的地址仍为@704
,值已经进行了对应的修改
继续执行到函数结束,可以看到node
指向了@708
,属性的值变为了新的值。
结束子函数,回到主函数中,可以看到n1
的所有属性都与node
指向@704
时相同
可见,同值类型的变量相同,传入子函数的对象头node
并不是主函数中的对象头n1
本身,而是它的一个拷贝,他们指向同一个对象@704
,无论是通过n1
,还是初始的node
,都可以对@704
进行操作(调用方法,修改属性),因而好像和值类型的传递有所不同。但如果修改node
本身的值,令其指向@708
,这对n1
没有任何影响,n1
依然指向@704
。此后通过node
修改对象的值,修改的是@708
的值,与@704
没有任何关系,因此也对主函数中的n1
没有任何影响。
因此,所谓引用传递,不过是值是引用(或者说指针)的值传递。