龙空技术网

Java面试-为什么 Java 只有值传递?

幽默的程序员面试宝典 367

前言:

眼前姐妹们对“java 传入函数”大致比较关切,小伙伴们都需要剖析一些“java 传入函数”的相关资讯。那么小编同时在网摘上网罗了一些对于“java 传入函数””的相关知识,希望各位老铁们能喜欢,咱们快快来了解一下吧!

在开始之前,我们首先需要搞懂如下的两个概念。

什么是形参与实参?什么是值传递?什么是引用传递?形参与实参

在Java方法的定义可能会用到参数的传入操作,在参数的定义中又可以分为如下的两种

实参(实际参数):用于传递给函数或者是方法的参数,它必须要有确定的值。

形参(形式参数):用户定义函数或者方法,用户接收实际参数,所以不需要有确定的值。

如下代码所示

String hello = "Hello!";// hello 为实参sayHello(hello);// str 为形参void sayHello(String str) {    System.out.println(str);}
值传递与应用传递

在编程语言中将实际参数传递给具体的方法调用或者是某个函数的方式一般分为如下的两种。

值传递:方法接收到的实际参数的值的拷贝,会创建一个副本对象进行使用。引用传递:方法接收到的直接是实际参数在堆中的应用地址,不会创建对象副本,对于参数值的修改会直接影响到实际参数的堆中的值

在其他的编程语言中,提供了两种参数传递方式,但是在Java语言中只是提供了值传递这一种方式。

为什么Java语言只有值传递?

传递基本类型的参数

public static void main(String[] args) {    int num1 = 10;    int num2 = 20;    swap(num1, num2);    System.out.println("num1 = " + num1);    System.out.println("num2 = " + num2);}public static void swap(int a, int b) {    int temp = a;    a = b;    b = temp;    System.out.println("a = " + a);    System.out.println("b = " + b);}

在上述代码中,swap()方法中对a和b二者的值进行了交换,并不会影响到num1和num2的值,因为a、b的值是从num1和num2进行了复制,也就是说a、b相当于num1和num2的副本。而且这个副本的内容无论如何修改,都不会影响到原来的值。

通过上面的例子我们知道,一个方法调用不修改一个基本数据类型的参数,如果采用对象引用作为参数就不一样了。

传递引用类型参数

	public static void main(String[] args) {      int[] arr = { 1, 2, 3, 4, 5 };      System.out.println(arr[0]);      change(arr);      System.out.println(arr[0]);	}	public static void change(int[] array) {      // 将数组的第一个元素变为0      array[0] = 0;	}

上面代码输出结果如下

10

根据上面的代码来分析,可能有人会觉得Java对引用类型的参数采用的是引用传递。也就是将引用进行了复制,但是实际上,并不是这样,这里的传递的还是值传递。只不过这里传递的值是实际参数的地址。

也就是说change方法的参数拷贝的是arr实际参数的地址,所以参数与arr指向的是同一个数据对象,也就是说在方法内部对于形参的修改会影响到实际参数的值。下面我们就来根据下一个例子来介绍一下。

public class Person {    private String name;   // 省略构造函数、Getter&Setter方法}public static void main(String[] args) {    Person xiaoZhang = new Person("小张");    Person xiaoLi = new Person("小李");    swap(xiaoZhang, xiaoLi);    System.out.println("xiaoZhang:" + xiaoZhang.getName());    System.out.println("xiaoLi:" + xiaoLi.getName());}public static void swap(Person person1, Person person2) {    Person temp = person1;    person1 = person2;    person2 = temp;    System.out.println("person1:" + person1.getName());    System.out.println("person2:" + person2.getName());}

上面代码执行结果如下

person1:小李person2:小张xiaoZhang:小张xiaoLi:小李

分析代码会知道,两个引用类型的参数互换,并没有影响的实际参数?这是为什么呢?swap 方法的参数 person1 和 person2 只是拷贝的实参 xiaoZhang 和 xiaoLi 的地址。因此, person1 和 person2 的互换只是拷贝的两个地址的互换罢了,并不会影响到实参 xiaoZhang 和 xiaoLi 。所以两个参数相互交换并没有影响到实际的对内存中的数据。

引用传递是怎么样的?

到这里,我们就明白了在Java中只有值传递,而没有引用传递。但是对于引用传递大家还是很好奇,下面我们就通过一个简单的C++的代码来分析一下引用传递到底如何?

#include <iostream>void incr(int& num){    std::cout << "incr before: " << num << "\n";    num++;    std::cout << "incr after: " << num << "\n";}int main(){    int age = 10;    std::cout << "invoke before: " << age << "\n";    incr(age);    std::cout << "invoke after: " << age << "\n";}

运行结果如下

invoke before: 10incr before: 10incr after: 11invoke after: 11

从上面代码可以看出,在使用 incr 函数中对传入的形参进行了修改,并且对于形参的修改影响到了实参的值。这里需要注意的是 incr 形参的数据类型用的是 int& 才为引用传递,也就是将这个地址给到了操作参数,这个时候其操作的值就变成了引用所指的地址。但是如果是用 int 的话则还是值传递。

为什么Java不使用引用传递呢?

引用传递看似非常完美,并且能在方法内部就把实际参数值进行修改,但是在Java中还是没有采用引用传递。其实理由很简单,就是为了安全,因为在Java语言中对于对象的封装都是比较安全的,如果采用了引用传递,则传递的值就会影响到对象内部封装的方法,这个时候如果想再次使用该对象的话就会获取到原来的数据,这样对于对象封装是极不安全的。

标签: #java 传入函数