【Java】带你了解Java的传值方式
一、结论
我先把结论放在前头,在java中,传递的对象如果是基础类型的话,就会直接将值传递过去(深拷贝),传递的对象是需要new的话,就是将对象的地址传递过去(浅拷贝)。
这个也困扰了我很久,c语言里还有指针可以区分,而java中就没有指针了,就很难区分了。
二、分析
1.直接上代码
package test;
/**
* @author xxj
* 检验java的传值方式
*/
public class TransmitValue {
private int a=0;
private MyClass m=new MyClass();
public static void main(String[] args){
TransmitValue tv=new TransmitValue();
tv.changeInt(tv.a);
tv.changeMyClass(tv.m);
System.out.println("tv.a:"+tv.a);
System.out.println("----");
System.out.println("tv.m:"+tv.m.i);
}
private void changeInt(int i){
i=10;
}
private void changeMyClass(MyClass m){
m.i=10;
}
public class MyClass{
int i=0;
}
}
运行的结果:
2.发生这种情况原因是什么呢?
最开始的总结中也提到了,需要new出来的对象才会,这是因为在new这个操作时,需要在jvm的堆中开辟一块空间,(jvm的组成以后有空再写,先埋个坑)开辟完成之后就返回这个对象的地址。
这时候,又有一个问题了,那不需要new的对象,放在哪里呢?
如果是方法内的对象是放在栈里面,如果是.class文件本身就带有的对象,则放在常量池中。
我从别的博客拉了一个图过来,大概是这样子,new出来的对象就是实例。
如果是存储在栈中,就不会存在引用,而是直接使用,换句话说,栈中的值,就是这个方法的本地变量。
3. 关于步骤1中代码的解释
看懂的话就直接跳过这一步了,没看懂的还有点疑惑的可以看一下。
为什么tv.a的值改变不了?
因为在调用changeInt方法时,tv.a中存储的数据就是值,不是地址,不存在引用,直接将数值传递过去肯定改变不了tv这个对象中的本地变量,改变的只是changeInt方法的本地变量。
为什么tv.m的值可以改变?
因为在调用changeMyClass方法时,tv.m中存储的数据是一个new出来的对象的地址,这个对象是存储在堆中的,所以在方法中,改变的是方法接收到的地址所找到的对象(也就是堆中的tv.m)的本地变量。
额外提一点
在changeMyClass方法中的MyClass m对象,是存储在这个方法的栈中的,一旦方法结束了,栈就会移除。
三、浅拷贝和深拷贝
- 浅拷贝
通过new创建出来的对象,一般在传值的时候都是浅拷贝,意思就是只复制了对象的地址,还是共用同一个对象。
一般出现在方法传参中,也不需要特地地去实现这个浅拷贝,算是默认的规则。 - 深拷贝
深拷贝是指能够生成两个一模一样的对象,这两个对象没有公用同一个地址,而是两个独立存在的对象。
一般的实现方法:可以通过转成JSON格式后,再调用new转成一个对象,这样就可以在堆中创建一个一模一样的对象了。
四、总结
说了那么多,其实就是传递的是地址还是值的问题。
引用C语言中的指针来做一个总结吧
在C中,是有指针和非指针的对象的,非指针的对象,就像java中的基础数据类型,只能传递值;指针的对象,就像java中new出来的对象,传递的是地址。而C语言需要我们主动的去创建一个对象时给这个对象设定是否是指针类型,也就是要不要加个*,但是在java中,java将这种需要主动设置的操作改为了默认的一种设定。
——————————————————————————————
你知道的越多,不知道的越多。
如果本文章内容有问题,请直接评论或者私信我。如果觉得我写得还不错的话,点个赞也是对我的支持哦
未经允许,不得转载!
微信搜【程序员徐小白】,关注即可第一时间阅读最新文章。回复【面试题】有我准备的50道高频校招面试题,以及各种学习资料。