我终于忍不住喷一下某些书了,关于Java传引用的XX言论
凡是说Java对象传的是引用,简直一派胡言,尤其误导我这种Java初学者,更严重的是以前用过C++的Java初学者。
我们都知道Java建立对象一般都是需要这样的格式:
Object obj = new Object(“初始化”);
但是在C++中则是可以这样写:
Object obj = Object(“初始化”);
少了new,为什么会这样呢?
因为Java对于声明一个对象建立的是一个指针,相当于C++的这样:
Object *obj = new Object(“初始化”);
这下看上去就一样了,事实上就是这样。给函数传递参数时,两种语言没有多少区别。我们先看一个C++例子(为了简化代码,突出重点,变量直接public了):
1 #include <stdio.h> 2 3 class MyTest 4 { 5 public: 6 int x; 7 MyTest(int x) 8 { 9 this->x = x; 10 } 11 }; 12 13 void func(MyTest *&test); 14 15 int main() 16 { 17 MyTest *test = new MyTest(3); 18 printf("调用前 : %d\n", test->x); 19 func(test); 20 printf("调用后 : %d\n", test->x); 21 return 0; 22 }
很多Java书上说Java中类的对象作为函数参数时传递的是引用,我们就可以这样定义C++的func函数,模拟Java书上所说的传递引用的行为:
1 void func(MyTest *&test) 2 { 3 test = new MyTest(4); 4 }
函数体就一行,这时执行main函数的输出是:
调用前 : 3
调用后 : 4
这个结果在任何C++初学者看来都很显然。
然后我们写一个“完全一样”的Java版本:
1 public class MyTest { 2 public int x; 3 public MyTest(int x) { 4 this.x = x; 5 } 6 }
1 public class Main { 2 3 public static void main(String[] args) { 4 MyTest test = new MyTest(3); 5 System.out.println("调用前 : " + test.x); 6 func(test); 7 System.out.println("调用后 : " + test.x); 8 } 9 10 private static void func(MyTest test) { 11 test = new MyTest(4); 12 } 13 }
这下输出却另我们大失所望:
调用前 : 3
调用后 : 3
竟然不一样,说好的传引用呢?为什么形参的改动没有影响到实参呢?简直了。为什么跟C++这样写效果一样啊:
1 void func(MyTest *test) 2 { 3 test = new MyTest(4); 4 }
所以Java完全没有引用这种东西!一切都是值传递,我查资料得出的结论是:C++只是把引用符号(&)解析成了指针,也就相当于这样写func函数:
1 void func(MyTest **test) 2 { 3 *test = new MyTest(4); 4 }
这就是为什么做到了引用,其实传的还是值,只不过是传的指针的指针,就算是这样,传的还是这个指针的副本,只是里面保存的内容一样而已。
我被误导了很久,因为这样写Java的func函数可以:
1 private static void func(MyTest test) { 2 test.x = 4; 3 }
但是这样却不行:
1 private static void func(MyTest test) { 2 test = new MyTest(4); 3 }
所以标题写的比较偏激,表达一下纠结的心情。我个人认为正确的说法应该是:Java是值传递,类对象变量都是一个对象指针,作为参数传到函数中跟传基本类型一样,都是复制了一份副本传递的,所以可以改变其成员变量的值,但不能改变其自身。希望跟我一样的初学者没有在某些书的误导下陷入歧途!