Java 与 C++ 中的值传递和引用传递解析

4 minute

先说结论:Java 只有值传递,而 C++ 既有值传递又有引用传递。

Java 的参数传递

先定义 3 个方法如下:

 1public static void change1(String str, int num) {
 2    str = "world"; // 这里就相当与新 new 了一个对象!
 3    num = 100;
 4}
 5public static void change2(User user) {
 6    user.age = 1;
 7    user.name = "mary";
 8}
 9public static void change3(User user) {
10    user = new User(1, "mary");
11}

进行测试:

 1public static void main(String[] args) {
 2    String str = "hello";
 3    int num = 1;
 4    System.out.println(str + " " + num); // hello 1
 5    change1(str, num);
 6    System.out.println(str + " " + num); // hello 1
 7
 8    System.out.println("------------------");
 9
10    User user = new User(123, "peter");
11    System.out.println(user.name + " " + user.age); // peter 123
12    change2(user);
13    System.out.println(user.name + " " + user.age); // mary 1
14    
15    System.out.println("------------------");
16    
17    user = new User(123, "peter");
18    System.out.println(user.name + " " + user.age); // peter 123
19    change3(user);
20    System.out.println(user.name + " " + user.age); // peter 123
21}

由 change2 和 change3 可知,对于引用类型,java 是值传递,在函数中只能改变形参对应的实参所引用的对象,而无法改变实参本身,也就是说形参传递的是实参所引用的对象,而不是实参本身。

由 change1可知,对于基本数据类型,java 是值传递。

对于 String 类型,应作特殊理解:String 本身属于引用类型,String 底层由 char 数组维护,是final 类型的,本身是不可改变,通过 “=” 赋值即相当于通过 new 新创建了一个对象,本质就是 change3 的操作。

C++ 的参数传递

解释了 java 的参数传递,可能会陷入困惑,到底什么才是引用传递呢?

我们再来看看 C++ 的参数传递:

定义 2 个方法如下:

1void change1(User* user) {
2    user->age = 999;
3    user->name = "mary";
4}
5void change2(User* user) {
6    user = new User(999, "mary");
7}

进行测试:

1User* user1 = new User(21, "peter");
2cout << user1->age << " " << user1->name << endl; // 21 peter
3change1(user1);
4cout << user1->age << " " << user1->name << endl; // 999 mary
5
6User* user2 = new User(21, "peter");
7cout << user2->age << " " << user2->name << endl; // 21 peter
8change2(user2);
9cout << user2->age << " " << user2->name << endl; // 21 peter

这样的效果和 java 测试中的 change2 和 change3 是一致的,都是传递了实参引用的对象!

下面看看如何实现引用传递吧:

这里形参就传递了实参本身!

1void change3(User*& user) {
2    user = new User(999, "mary");
3}

测试如下:

1User* user3 = new User(21, "peter");
2cout << user3->age << " " << user3->name << endl; // 21 peter
3change3(user3);
4cout << user3->age << " " << user3->name << endl; // 999 mary

可见在函数中实现了对形参所对应实参本身的修改!

为什么 Java 取消了引用传递

应该是为了更简单,更安全的开发吧。

函数调用无法修改实参,这样一定程度上避免了很多错误的发生,但同时限制了可以做的事情,可以说有利有弊。