先上一段代码,无码无真相 ^-^
class="java">
import java.util.ArrayList;
import java.util.Date;
public class JavaReference
{
public static void change(Date date)
{
date = null;
}
public static void changeList(ArrayList<Integer> lst)
{
lst.add(3);
lst = null;
}
public static void main(String[] args)
{
Date d = new Date();
System.out.println(d);
JavaReference.change(d);
System.out.println(d); // 这里会打印 null 吗?
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
System.out.println(list.size());
JavaReference.changeList(list);
System.out.println(list.size()); // 这里会报空指针错误码?还是会打印 3 呢?
}
}
上面的 d 会打印null吗?
最后的打印语句会报空指针吗?
继续看之前,请您在心中该处答案,并且分析为什么结果是这样的。
===================================华丽的分割线======================================
打印结果为:
Wed Dec 03 13:35:21 CST 2014
Wed Dec 03 13:35:21 CST 2014
2
3
您答对了吗?
为什么结果是这样的呢?
原因分析:
有人说Java中没有指针,但是java中有处处是指针。指针的本质是什么呢?学过C/C++的应该不陌生,指针是一个变量,他自己的
内存空间在栈上分配,既然指针是一个变量,那么这个变量的值是什么呢?指针这个变量专门用于保存 地址值 ,而这个地址值,在Java中是一个堆上的对象的地址。在C/C++中指针也会指向栈上的变量或者对象。但是在Java中指针或者说引用只能指向堆上的某个对象。
在Java中函数参数的传递,是值传递呢?还是引用传递呢?
没有异议:绝对是值传递!
有了上面的基础,再来分析上面的结果:
JavaReference.change(d);
change函数将 d 这个保存了 new Date() 语句所产生的对象的地址传给了函数change,在C/C++中,如果要在change函数中修改 d 所指向的对象,必须如下操作:
*d = null;
这里的含义是: *d 表示取得 d 所指向的对象,就是得到d所指向的对象,然后再来修改d所指向的那个对象。
但是在java中不能这样操作,那么java中change函数中的
date = null
是什么意思呢?
是这样的:change(d) 将 new Date() 对象的地址传递给了 change函数的参数 date, 此时date是change函数局部变量,然后再将null赋值给这个局部变量,那么实际参数 d 的值变了吗?没有!d 还是指向 new Date() 所产生的那个对象。
所以 System.out.println(d); 不会打印null,他会自动调用 d.toString()
注意注意:d.toString() 这个调用很神奇!!!! 他为什么神奇,他哪里神奇呢?
我们知道 d 保存了指向 new Date() 的那个对象,那么 d 是如何访问 new Date() 对象的方法的呢?语法我们都知道: d.toString(),但是其中的暗含了下面的过程:
1)先获得 d 指向或者说引用的对象,即那个 new Date() 产生的对象;
2)然后调用他的 toString()方法;
在C/C++中相当于: d->toString(); 或者: (*d).toString();
看到这里,您应该明白了,因为java中没有 (*d) 这样的
caozuofu.html" target="_blank">操作符来访问d所指向的对象,所以java中直接省略了(*d) 或者,将 (*d) 暗含在 d.toString()中了。
所以java 中的 d.toString() 等价于C/C++中的 (*d).toString().
明白了这一点就一切真相大白了。
JavaReference.changeList(list);
调用,在changeList中,将list所指向的 new ArrayList<Integer>() 对象的地址传递给了changeList的局部变量lst ,然后 lst.add(3) 相当于C/C++中的 (*lst).add(3);即先获得lst这个局部变量中保存的地址所指向的对象,也就是指向 new ArrayList<Integer>() ,然后调用这个对象 的 add(3)方法。所以list.size() == 3
那么 局部变量 lst = nul; 是什么意思呢?他只是将 局部变量 lst 的值赋值为null,他没有改变实际参数 list.
lst = null 不等价于C/C++中的 (*lst) = null;
原因是这里没有使用调用操作符 “.”,他就是普通的局部变量的赋值操作。
调用操作符 “.”为什么会相当于C/C++中的 (*lst).add(3)呢?即局部变量 lst 调用函数 add(3) 时,为什么先要 访问 lst 所指向的对象 new ArrayList<Integer>() ??
废话,不先访问他指向的对象,怎么去调用他的方法呢???
所以到这里:最重要的是,java中对象参数的传递时基于值的传递,传递的是实际参数所引用的那个对象的地址。指针,或者说引用在调用函数时,会自动先去访问它的地址所指向的那个对象,也就是它说引用的那个对象,然后调用该对象的方法。所以就修改了该对象。所以最后的list.size() == 3;