java值传递彻底明白~

时间:2022-04-24 13:19:23
java值传递彻底明白~时间: 2004-4-06 13:18:27    标题: 一个绝对害了不少人的Java技术问题! java值传递彻底明白~ java值传递彻底明白~

我不记得自己是怎么学到的,但是我相信绝大部分从事java学习Java的人都一直这么以为一个小的技术问题:
在Java中方法参数的传递,对象是传递引用,基本数据类型是传递值。而且一直一来都似乎没有人提出过疑问。
直到最近,我在为公司基本Java开发人员编写考试试卷的时候,我才发现,这错了!在方法中,Java语言中对象传递的是地址,而不是引用,这两个概念是有非常大的差别的,我相信熟悉c++的人都应该知道。
例如下面:假设对象Test有name的属性。
public void call(Test t) {
Test t2 = new Test();
t2.setName("cba');
t.setName("abc");
t = t2 ;
}

public static void main(String[] arg) {
Test obj = new Test();
call (obj) ;
System.out.println("obj"+obj.getName());
}
这个时候,你们可以发现,打印出来的是"abc" ,而不是"cba",原因是这样的,在这次调用中,等于声明了两个变量obj , t,它们指向的是同一个地址,调用call方法,只是将obj指向的地址传递给了t,而obj本身并没有传递过去(也就是没有传递引用),当你重新赋值的时候(也就是将对象引用指向其他存储空间),等于只影响了t,而没有影响obj。
这样的传递方式只能称之为址传递,或者是引用对象传递,而不嫩说是传递引用或者引用传递。
我不知道这究竟属于翻译的错误,还是我们理解的错误。但是这样的问题在c++中是有明显的区分的(通过*与&)




java值传递彻底明白~时间: 2004-4-06 21:07:10    标题: java值传递彻底明白~ java值传递彻底明白~

1、首先弄清楚一个问题:Java有没有指针?

对于在C和C++里头曾经给我们带来欢乐同时也有无限痛苦的指针,很多人宁愿它再也不要出现在Java里头。然而事实上,Java是有指针的,Java中每个对象(除基本数据类型以外)的标识符都属于指针的一种。但它们的使用受到了严格的限制和防范,在<Thinking in Java>一书中称它们为句柄。

2、传递句柄
将句柄传递进入一个方法时,指向的仍然是相同的对象。
public class Testit {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public static void main(String[] args) {
Testit a = new Testit();
a.setName("a");
Testit b = new Testit();
b.setName("b");
System.out.println("before swap: " + "a=" + a + " name: " + a.getName());
swap(a,b);
}

private static void swap(Testit swap1, Testit swap2) {
System.out.println("swaping: " + "a= " + swap1 + " name: " + swap1.getName());
Testit temp;
temp = swap1;
swap1 = swap2;
swap2 = temp;
}

}

输出结果:
before swap: a=com.lib.Testit@16930e2 name: a
swaping: a= com.lib.Testit@16930e2 name: a

3、一个句柄的传递会使调用者的对象发生意外的改变。
public class Testit {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public static void main(String[] args) {
Testit a = new Testit();
a.setName("a");
Testit b = new Testit();
b.setName("b");
System.out.println("before swap: " + "a=" + a + " name: " + a.getName());
swap(a,b);
System.out.println("after swap: " + "a=" + a + " name: " + a.getName());
}

private static void swap(Testit swap1, Testit swap2) {
Testit temp;
temp = swap1;
swap1 = swap2;
swap2 = temp;
swap1.setName("a's name");
swap2.setName("b's name");
}

}

输出结果:
before swap: a=com.lib.Testit@16930e2 name: a
after swap: a=com.lib.Testit@16930e2 name: b's name

我们看到,a依旧是原来那个a,但name却不是原来那个name了!
在swap()方法中,swap1和swap2互相换过来了,这个时候swap2指向的是a,所以在setName()的时候改变的是a的name,而不是b的name。

为什么会这样呢?
liang_chen兄高见:Java里的传值实际上是拷贝引用,而不是拷贝对象。

总结:
1:对于值类型的参数来说,传递的是值的拷贝.
2:对于引用类型的参数来说,传递的是引用本身的拷贝.
所以关键要看你如何理解传值中的这个“值”了。




java值传递彻底明白~时间: 2004-4-06 22:56:27    标题: 哈哈,好热闹 java值传递彻底明白~ java值传递彻底明白~

没有想到这个问题引起这么多朋友的共鸣,
楼上有位仁兄关于“java传递是引用的拷贝,既不是引用本身,更不是对象。”这句话说得非常好!可惜现今发现的任何一本书都没有说明。
当然这个传递是对象,而不是简单数据类型,简单数据类型还是传递值的拷贝的。
楼上还有一位仁兄拿出了编译原理,这正是问题的所在,传递地址、传递引用、传递结果(也就是值拷贝),这里所说的传递引用和传递地址有什么差别?
楼上的liang_chen的理解非常好,我直到前一段才真正发现(在我身边差不多都不清楚这个问题),三年多的java分析设计开发经验,到今天才理解透这样一个基础的问题,我真是汗颜。:(
所以,其他还在争论不清楚的各位朋友,一定要认真地学习java,不能随便说自己精通的,哈哈,大家多加探讨,继续共同提高。



java值传递彻底明白~时间: 2004-11-10 12:38:00    标题: 句柄与指针--讨论凤舞凰扬的问题 java值传递彻底明白~ java值传递彻底明白~

凤舞凰扬的原帖子实在太长了,在这里新开一个帖子讨论这个问题。

我认为,java并没有c++中指针、地址的概念,它只有句柄(handler)的概念。还以凤舞凰扬的两个方法为例:

public void call(Test t) {
Test t2 = new Test();
t2.setName("cba');
t.setName("abc");
t = t2 ;
}

public static void main(String[] arg) {
Test obj = new Test();
call (obj) ;
System.out.println("obj"+obj.getName());
}

总共构建了两个Test对象,假设称main方法构建的对象为“对象1”,call方法构建的对象为“对象2”,
在main方法中,变量obj获得了“对象1”的句柄,
在参数传递中,变量obj把这个句柄传递给变量t,
在call方法中,变量t首先改变了“对象1”的属性,然后变量t又获得了“对象2”的句柄(但obj仍然是“对象1”的句柄),
call方法返回后,由于“对象2”失去了唯一的句柄,不可避免的进入垃圾收集器的视线。而obj仍然是“对象1”的句柄,由于“对象1”的属性已经被重新设置,所以我们可以看到打印出来的结果是“abc”。

所以我认为以下论断是没有问题的:
“在Java中方法参数的传递,对象是传递引用,基本数据类型是传递值。”