前言:

在使用Java语言进行开发过程中,涉及到局部变量与方法内部作用域的数据交换与解析的过程,而这一过程,一般都是通过方法形参的方式进行java对象的传递。

这里引出一个问题,当对象作为参数传递时,究竟传的是对象的值,还是对象的引用呢?—_—

这是一个保守争议的话题。

假设,传的是值,那么函数接收的只是一个副本,由于作用域的存在,函数对象形参的操作,并不会对实参产生影响;若传的是引用,那么此时对形参的操作则会影响到实参。

在这里引用一句代码来举例分析:

1Object obj = new Object();

这句代码的意思是:创建一个Object对象,并在堆内存开辟一个空间(new),同时创建一个名为obj 的引用,让这个引用指向这个对象,如下图所示:

java jni 传递指针对象 java对象传递传值还是引用_System

在上面我们创建了一个对象以及其引用,下面我们通过例子来从代码层面进行分析。

基本数据类型作为参数传递:

例1:

/**
* @ClassName test.java
* @Description TODO
* @Author wushaopei
* @Date 2020年3月10日
* @Version 1.0
*/
public class test{
public static void main(String[] args){
int i = 1;
System.out.println("before change, i = "+i);
change(i);
System.out.println("after change, i = "+i);
}
public static void change(int i){
i = 5;
}
}

这个例子中使用基本数据类型的 int 作为形参传递,执行结果如下:

before change, i = 1
after change, i = 1

从 int 类型作为形参的例子的执行结果可知,当基本数据类型(Boolean,byte,char,String,int,Long,float,double)作为参数传递时,传递的是实参值的副本,即传的是值,无论在函数中怎么操作这个副本,实参的值是不会被改变的。

对象作为参数传递:

例2: 我们使用 StringBuffer对象作为参数传递到change函数


public static void main(String[] args){
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("before change, sb is "+sb.toString());
change(sb);
System.out.println("after change, sb is "+sb.toString());
}
public static void change(StringBuffer stringBuffer){
stringBuffer.append("world !");
}

程序的运行结果:

before change, sb is Hello
after change, sb is Hello world !

从输出结果中我们可以发现,sb所指向的对象的值被改变了,那么是否我们可以推论出,在Java中,当对象作为参数传递时,传递的是该对象的引用呢?我们再来看下面这个例子:


public class test{
public static void main(String[] args){
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("before change, sb is "+sb.toString());
change(sb);
System.out.println("after change, sb is "+sb.toString());
}
public static void change(StringBuffer stringBuffer){
stringBuffer = new StringBuffer("Hi ");
stringBuffer.append("world !");
}
}

如果上面的推论是正确的,即Java中对象作为参数传递,实际传递的是该对象的引用,那么在调用change函数之后,原对象的值应该是会改变的,变为“Hi world !”,但是,当我们运行程序后,结果却是如下所示:

before change, sb is Hello
after change, sb is Hello

原对象的值并没有被改变,这与上面的推论相矛盾!为什么在Java中,当对象作为参数传递时,有的时候实参被改变了,而有的时候实参并未被改变呢?下面让我们来分析一下其中的原因:   从文章的开头我们知道,当执行StringBuffer sb = new StringBuffer(“Hello “)时,我们创建了一个指向新建对象“new StringBuffer(“Hello “)”的引用“sb”,如下图所示:

java jni 传递指针对象 java对象传递传值还是引用_System_02

在例2中,当我们调用change函数后,实际上,形参stringBuffer也指向了实参sb所指向的对象,即:

java jni 传递指针对象 java对象传递传值还是引用_Java_03

那么当我们执行stringBuffer.append(“world !”)后,便通过对象的引用“stringBuffer”修改了对象的值,使之变成了“Hello world !”,即:

java jni 传递指针对象 java对象传递传值还是引用_System_04

但是,在例3中的change函数中,我们又新建了一个对象“new StringBuffer(“Hi “)”(这实际上在内存中开辟了一块在原对象地址之外的新区域),这让形参stringBuffer实际指向了这个新建的对象,并将新对象的值设置为“Hi world !”,例三中stringBuffer的值已经被改变为了Hi world,但是因为值没有被return返回赋值给sb对象,所以sb对象并没有被改变,所以输出的任然是hello,即:

java jni 传递指针对象 java对象传递传值还是引用_System_05

那么我们就不难理解,为何在执行完change函数之后,实参的值仍为“Hello”了。

结论

综上所述,我们可以得出结论:在Java中,当对象作为参数传递时,实际上传递的是一份“引用的拷贝”。 (实际传递的是对象的引用)