大家都知道,java里面,无论是引用传递还是值传递,实际上传递的只是他们的一份拷贝,但是我有一点想不明白,为什么要传递拷贝,而不能传递他们原生的值或引用呢?求大神门指点一下迷津,万分感谢。
大家都知道,java里面,无论是引用传递还是值传递,实际上传递的只是他们的一份拷贝,但是我有一点想不明白,为什么要传递拷贝,而不能传递他们原生的值或引用呢?求大神门指点一下迷津,万分感谢。
看你怎么理解引用跟值了。从某种角度上说引用也是值,所以在说我的理解前先下个定义:
Object reference= (Object)value;
上式中reference 是所谓的“引用”, value是所谓的“值”。
从这个定义上来说,java的传递全都是“值传递”。
令Object reference2 = (Object)value;
然后传递reference2 去操作value。reference2是函数范围内的局部变量,用完即收回。
至于你说的“实际上传递的只是他们的一份拷贝”,如果把“他们”理解为reference的话那么这句话是对的。为什么呢?因为java只想传递value,不想修改reference,所以传递一个reference的copy。
那么问题来了:为什么java不能传reference呢?
答:这个问题其实要问java设计者了。个人觉得这么设计牺牲了一些灵活性,但是获得的好处么。。。你想到了C++的指针了吗
是因为java里 没有指针?
java里的reference是一个抽象的概念, 里面放得也不是地址. 试想一下, 每次gc后, 对象实例有可能在不同的 代中移动, 内存地址就变了! 所以java中不会直接操作地址.
java只有值传递,这句话的意思从底层来看,就是栈上的东西永远会被复制。int存于栈上所以传参的时候会被复制。
对于object,他的引用存于栈上,但是实例在托管堆上,复制的是它的引用,实例本身并没有被复制,所以效果相当于引用传值。在子函数里面,对实例本身的任何操作,比如调用其方法,都会影响外面,但是如果你重新new了一次,不会影响到外面的。
看怎么理解,可以理解为Java只有值copy。
先看基本类型:
int a = 10;
有个方法 doWithInt(int a), 当调用doWithInt(a)的时候,实际是把a的值10传递过去了。
再看对象类型:
Object obj = new Object();
有个方法doWithObj(Object obj), 当调用doWithObj(obj)的时候,实际是把obj的引用这个值(比如是0x4123fac9)传过去了。注意这里的值,是指的obj的引用,对于一个对象来说,能标示它的唯一值的就是他的地址引用。
所以你看,理解万岁啊。
在MF的重构中有提交,java本身是值传递,如果传递常量,是传递拷贝,如果传递的是对象,则传递的是引用指向拷贝,引用本身指向是不能改变,但是能够改变引用本身的内容。
理解为传递的是引用指向的拷贝即可,指向不能更改,引用所引用的内容可以更改。
如果传入参数是对象的话,实际是对象的引用,根据按值传递的原则,又新建了一个引用副本,所以在方法体内对该引用内容进行修改,当然会直接改变所指向对象的值。而对于基本类型的参数,我们传递值后又建了这个值的副本,对这个副本的修改自然不会修改原参数的值。
4 回答1.7k 阅读✓ 已解决
4 回答1.5k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
4 回答2.3k 阅读
3 回答1.3k 阅读✓ 已解决
2 回答838 阅读✓ 已解决
2 回答1.4k 阅读
大更新后,原来的回答就删了
为了回答Lance_D的提问,重新翻看了一下java虚拟机的书。
1.先看一段代码
输出
看一下内存里change1的真实过程

change2的过程

change3的过程

2.理解String
Java中的String类其实就是char数组的包装类,源码:
所以不管是


String s1="ab";
或者String s1=new ("ab");
其实真实的情况是当
s1 = "cd"
时3.重新看一下java虚拟机中支持的原始数据类型与引用数据类型
原始数据类型
数值类型
byte类型:值为8位有符号二进制补码整数,默认为零
short类型:值为16位有符号二进制补码整数,默认为零
int类型:值为32位有符号二进制补码整数,默认为零
long类型:值为64位有符号二进制补码整数,默认为零
char类型:值为16位无符号整数表示的、指向基本多文种平面的Unicode码点,以UTF-16编码,默认值为Unicode的nell码点('\u0000')
float类型与double类型要复杂一些
boolean类型
值为布尔值
true
和false
,默认为false
returnAddress类型
表示一条字节码指令的操作码(opcode)
引用数据类型
分别由类实例、数组实例和实现了某个接口的类实例动态创建
4.看个复杂一点点的实例
输出:
实际change1过程:
change2过程:
