从一个Java面试题学习Java值传递和引用传递
< 返回列表时间: 2020-06-24来源:OSCHINA
对于Java是值传递还是引用传递的问题,我个人一直没有做深入研究,只是简单记住了结论:Java中只有值传递。(参考:Java核心技术 第五版)
今天因为在面试题中遇到了这个问题,所以深入得研究一下这个知识点。
首先,我们知道在C语言中,一个函数的形参可以是算数类型或指针类型,举最简单的例子,自定义交换值函数swap():
如果将swap的函数原型定义为void swap(int a,int b),然后调用swap(x,y),在swap里进行数值交换操作:
void swap(int a,int b){
a+=b;
b=a-b;
a-=b;
}
这里在swap里操作的a,b,是外部调用swap()函数时传入的x,y值的拷贝,因此在函数内进行a,b的交换,不影响外部调用的实参x,y的数值。
如果改成下面的形式:
void swap(int *a,int *b){
*a += *b;
*b = *a - *b;
*a -= *b;
}
那么此处的形参是指针,它接收2个地址(也就是外部的实参x,y的地址),swap函数内通过解引用操作,操作了对应地址上的数值,也就修改了x,y的值。
Java中,类似的概念变成了传值和传引用,我们可以这么理解:
java中方法参数传递方式是按值传递。
如果参数是基本类型,传递的是基本类型的字面量值的拷贝。
如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝。
如果传递的是引用,在函数内进行操作时,要看该引用操作的地址是否就是外部的实参相对应的地址。(相当于有一个人把自己家的钥匙给了你,你可以用钥匙去他家,这样如果你在他家做了破坏,他是可以感觉到的,但是你也可以不用这把钥匙,而去造访一个其他的地方,这样的话相当于引用指向了一个新的地址,那么此时引用对新地址做的任何修改都不会影响到老的地址)
下面举3个例子:
1、直接传递字面量值 public class Test { public static void main (String[] args) { Test test = new Test() ; int x = 10 ; test.myStdOut(x) ; System. out .printf( "x in main = %d \n " , x) ; } public void myStdOut ( int x) { x = 20 ; System. out .printf( "x in myStdOut =%d \n " , x) ; } }
控制台输出:
x in myStdOut =20
x in main = 10
2、传递对象引用(拷贝地址) public class Test { public static void main (String[] args) { User user = new User() ; user.setName( "abc" ) ; user.setSex( "man" ) ; new Test().test(user) ; System. out .printf( "user in main:%s,sex:%s \n " , user.getName() , user.getSex()) ; } private void test (User user) { user.setName( "def" ) ; user.setSex( "female" ) ; System. out .printf( "user in test:%s,sex:%s \n " , user.getName() , user.getSex()) ; } }

控制台打印:

user in test:def,sex:female
user in main:def,sex:female
这是因为拷贝的地址,然后通过拷贝的地址对数据进行了操作,而原来的引用也指向这个地址。
3、传递对象引用(拷贝地址),但是在函数中修改了引用指向的地址 public class Test { public static void main (String[] args) { User user = new User() ; user.setName( "abc" ) ; user.setSex( "man" ) ; new Test().test(user) ; System. out .printf( "user in main:%s,sex:%s \n " , user.getName() , user.getSex()) ; } private void test (User user) { user = new User() ; user.setName( "def" ) ; user.setSex( "female" ) ; System. out .printf( "user in test:%s,sex:%s \n " , user.getName() , user.getSex()) ; } }

控制台打印:
user in test:def,sex:female
user in main:abc,sex:man
这里仅仅是在test函数中加入了 user = new User(),这句话为一个新的User对象分配了空间,并让user指向了这个新的对象,因此user对新对象的操作不会影响到原来的对象,可以看到,结果和2截然不同。
知乎上对这个问题的解释非常好,可以参考: https://www.zhihu.com/question/31203609
热门排行