为什么java值传递时传递的是一份拷贝?
大家都知道,java里面,无论是引用传递还是值传递,实际上传递的只是他们的一份拷贝,但是我有一点想不明白,为什么要传递拷贝,而不能传递他们原生的值或引用呢?求大神门指点一下迷津,万分感谢。
回答:
大更新后,原来的回答就删了
为了回答Lance_D的提问,重新翻看了一下java虚拟机的书。
1.先看一段代码
public static void main(String args[]){ char[] c1 = {'a','b'};
System.out.println("c1:"+c1[0]+" "+c1[1]);
changer1(c1);
System.out.println("c1 change1 after:"+c1[0]+" "+c1[1]);
changer2(c1);
System.out.println("c1 change2 after:"+c1[0]+" "+c1[1]);
}
private static void changer1(char[] c1) {
char[] c2 = {'e','f'};
c1 = c2;
}
private static void changer2(char[] c1) {
char[] c2 = {'e','f'};
c1[0] = c2[0];
}
输出
c1:a bc1 change1 after:a b
c1 change2 after:e b
看一下内存里change1的真实过程
change2的过程
change3的过程
2.理解String
Java中的String类其实就是char数组的包装类,源码:
/** The value is used for character storage. */private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
所以不管是String s1="ab";
或者String s1=new ("ab");
其实真实的情况是
当s1 = "cd"
时
3.重新看一下java虚拟机中支持的原始数据类型与引用数据类型
原始数据类型
- 数值类型
- boolean类型
- returnAddress类型
数值类型
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.看个复杂一点点的实例
public class Test { class Student{
public String name;
public int number;
public Student(String sName, int sNumber){
name = sName;
number = sNumber;
}
}
public void test(){
Student s1 = new Student("Jack",1);
System.out.println("s1:"+s1.name+" "+s1.number);
change1(s1);
System.out.println("s1:"+s1.name+" "+s1.number);
change2(s1);
System.out.println("s1:"+s1.name+" "+s1.number);
}
private void change1(Student s1) {
s1 = new Student("Mack",2);
}
private void change2(Student s1) {
s1.name = "Mack";
s1.number = 2;
}
public static void main(String args[]){
new Test().test();
}
}
输出:
s1:Jack 1s1:Jack 1
s1:Mack 2
实际change1过程:
change2过程:
回答:
看你怎么理解引用跟值了。从某种角度上说引用也是值,所以在说我的理解前先下个定义:
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了一次,不会影响到外面的。
回答:
多看看jvm内存
回答:
值传递传的是拷贝,引用传的是地址。
回答:
基本数据类型是值传递, 其他的是引用传递吧
回答:
看怎么理解,可以理解为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本身是值传递,如果传递常量,是传递拷贝,如果传递的是对象,则传递的是引用指向拷贝,引用本身指向是不能改变,但是能够改变引用本身的内容。
理解为传递的是引用指向的拷贝即可,指向不能更改,引用所引用的内容可以更改。
回答:
如果传入参数是对象的话,实际是对象的引用,根据按值传递的原则,又新建了一个引用副本,所以在方法体内对该引用内容进行修改,当然会直接改变所指向对象的值。而对于基本类型的参数,我们传递值后又建了这个值的副本,对这个副本的修改自然不会修改原参数的值。
以上是 为什么java值传递时传递的是一份拷贝? 的全部内容, 来源链接: utcz.com/p/172903.html