Java没有指针; Java有参考。
这是一个很好的观点,但是一个指针有额外的操作,你可能(或不可以)通常使用; 由于这些操作可能是不安全的,因此缺less这些操作。
例如,如果您使用指针索引数组的第一个元素,如下所示:
int squares[] = {1, 4, 9, 16, 25, 36, 49}; int* intPointer = squares;
您可能需要取消引用指针并获取值“1”,但您也可以:
intPointer++
当你这样做的时候,当你取消引用指针时,你会得到值“4”。 一秒
intPointer++;
将被解除引用,给你的价值“9”。 这是因为++操作将指针向前移动一个“单位”在内存中。
这个问题来自C / C ++types检查系统的弱点(C ++必须保持与C的兼容性,所以它允许相同的问题)。 指针将地址存储在内存中,++操作将相应数量的字节添加到地址中。 在很多系统上,int一个int增加了四个字节,但是如果指针是一个char指针++的话,它应该只添加一个字节。 请注意,由于指针的基础数据types是内存中的地址,因此以下内容是合法的(但不推荐):
char* charPointer = squares; charPointer++; void* voidPointer = squares; voidPointer++;
由于指针是内存中的地址,因此它们可能(正确)表示计算机中的任何内存位,但只有在底层数据符合指针的types和alignment时才能正确解除引用。 对于不被大量代码pipe理的指针来保证它们的安全,这意味着您可能会丢弃所需信息的数据types(或alignment方式),并且解除引用可能会导致灾难。 试图用自定义代码解决这个问题往往会使一个指针变得非常慢,以致于您注意到了性能问题,并且会在自定义“指针pipe理”代码中添加错误。
Java方面通过返回一个引用来解决所有这些问题。 参考不涉及内存中的任何位置; Java维护一个内部的“指针”表的引用。 该表采用引用并返回与其关联的数据,无论数据驻留在内存中的哪个位置。 这会减慢代码的执行速度,因为每个“取消引用”都会执行两次查找,参考表中有一次查找,机器内存中有一次查找。
Java使用引用的一大优点是内存可以被移动而不会破坏可能的指针地址。 在C程序中,如果将数据移动到新的内存位置,则很难知道程序的其他部分是否有指向数据的指针。 在移动内存之后,应该废除一个陈旧的指针,程序将访问损坏的数据,并且通常会导致崩溃。
在正在运行的程序中移动内存的能力允许程序轻松地回收内存。 任何不需要大块内存的程序都可以释放未使用的内存,但是这会在使用过的内存块之间产生未使用内存的内存空洞。 内部计算机使用相当大的内存页面。 如果一个稀疏使用的内存页面可能有less量使用的位移动到另一个页面,则可以释放一页内存。 这增加了数据到内存的密度,提高了caching的性能。 有时这会转化为性能改善,这可能相当戏剧性。
Java的垃圾收集器通过临时阻止访问一组引用的数据来利用引用。 在访问阻塞期间,它会移动数据(压缩它)。 阻塞之后,对地址表的引用具有新的存储器地址。 由于代码的“function”层始终不知道地址,因此该操作不会中断正在运行的Java程序。