采摘处:http://hi.baidu.com/etrigger/blog/item/c6a24a7a1671daee2f73b3e0.html
作为一名程序员,我们应该对新知识和新技术刨根问底,而不应泛泛而谈。我未曾接触到Java的时候,我想听得最多的东西还是关于Java中不存在指针的问题。此时,我会不断地想:如果Java不存在指针的话,那么是如何实现复杂的数据结构?这样的语言与VB有什么差别?如果一个静态过程式或面向对象语言,如果不存在指针的话,那它如何会得到程序员的喜爱呢?功能是何其的有限?幸好有机会和一位师弟在交流C#,当时我也没有接触过C#,不过从他的观点令我看清楚了一些问题。我还是很清楚地记得他说了一句:C#中同样有指针,不过是有限制的指针,因此在C#中把它称为引用(references)。经过对Java的学习后,我非常赞同他的那句话。即是Java中也存在指针,不过是限制的指针,因此在Java语言的规范说明里把它称为引用。下在从C++中的对象类型为依据,谈谈Java语言中的引用到底与C++中的哪种对象类型更类似。
Java的对象类型
在这里,我不泛谈程序语言原理方面的知识,如何为引用,何为指针。只以C++的对象类型为蓝本,讨论C++中对象类型与Java对象类型的异同。
C++的对象类型分为三种:对象变量,对象指针和对象引用(这里特指是C++的引用)。对象变量,与基本数据类型变量一样,分配在栈中,对象在栈的生命空间结束后,系统会自动释放对象所占用的空间;对象指针,与C语言中的指针一样,都是一个地址,它指向栈中或堆中的一个对象。对象引用是C++中与C不同之外,形象地说,引用就是一个别名,定义引用的时候必须一起初始化,不能引用不存在的对象。下面是C++中定义三种对象类型的代码:
String a(“string a”);
String *pA = &a;
String *pB = new String(“string b”);
String &c = a;
语句1中定义一个String变量a,它的内容是”string a”;语句2中定义一个String对象指针,它指向对象a(栈对象);语句3中定义一个String对象指针,不过它指向一个分配在堆中的对象。最后一个语句是定义一个String对象的引用c,它引用a,也即是说c是a的别名,即同一个变量,两个不同的名字而已。只要改变a或c,该变量内容都会发生改变的。
Java中的对象类型只有一种,那就是引用(注意是Java的引用,而非C++的引用)。下面是定义一个引用的代码。
String s = new String(“string”);
在执行此代码时,在内存空间生成的结构如下面所示:
上面的语句中其实做了两件事情,在堆中创建了一个String对象,内容为”string”,在栈中创建了一个引用s,它指向堆中刚创建好的String对象。并且引用s值的改变不影响它所指的对象,只有通过它调用对象的方法对可能改变对象的内容。请看如下语句:
s = new String(“abc”);
在上面这个语句中,只改变s的值,因此不会对内容为”string”对象造成影响(不考虑垃圾回收情况)。只不过是s指向堆中的新对象而已,从指针上来说,就是s的值改变了而已。
从上面来看,Java的引用,并不与C++的引用相同,因此它不是一个别名;与对象变量也不同,它只是表示一个内存位置,该位置就是存在一个对象的位置,而不是真实的对象变量。并且从指针的意义角度来说,C/C++的指针与Java的引用却是不谋而合。它们都表是一个内存地址,都可以通过这个内存地址来操纵它所对应的对象。因此Java的引用更像C++中的指针,在下文中把它称为Java中的指针,同样也可称为Java中的引用。
Java中的指针与C++中的指针
本文开始提到Java中的指针是限制的指针,那么在这里分析Java中的指针可以执行什么运算符。
在C++的对象指针里面,出现的指针运算符主要有以下几个:*,->。
运算符*是返回指针所指向的对象,而->是返回指针所指向对象的数据成员或方法成员。由于不存在对象变量,而是通过指针来访问对象的,因此Java中不需要提供*运算符,这是Java优化了C++的一个指针问题。对于->运行符,Java的指针是提供的,不过是采用.运算符的方式提供,看起来与C++中对象变量的.运算符一样,其实意义是有不一样的地方。
如String s = new String(“abc”);
s.indexOf(“a”);
与下面C++代码等价的
String *s = new String(“abc”);
s->indexOf(“a”);