Java中指针和引用变量有什么区别?

24

我的Java书解释说,要使用对象,我们可以将它们分配给引用变量。那与指向对象的指针有何不同?Java有指针吗?

谢谢 :)


1
如果谈论Java,就不能谈论指针:https://dev59.com/EXVD5IYBdhLWcg3wQJOT#7034719 - Marsellus Wallace
请参见 https://softwareengineering.stackexchange.com/questions/141834/how-is-a-java-reference-different-from-a-c-pointer。 - Andrejs
1
JLS §4.3.1:“一个对象是一个类实例或一个数组。引用值(通常只是引用)是指向这些对象的指针,以及一个特殊的空引用,它不引用任何对象。” - Radiodef
9个回答

28

引用有点像指针,但你不能对它进行算术操作...虽然它更不透明。虽然底层的比特可能是虚拟内存中的地址,但它们不必是。它们只是一种访问对象(或表示空值)的方式。因此,虽然它们并不完全相同,但如果你习惯于将指针视为“标识对象或导航到对象的一种方式”(在某种意义上),那么这些想法也适用于引用。

Java本身没有指针(与C#不同,C#既有引用有指针——后者在“不安全”代码中使用)。


在底层是否有可能引用其实是指针,只不过被抽象化了? - lightning_missile
2
@morbidCode 这取决于JVM的实现。它不一定需要,但可以使用。本地指针必须在垃圾收集器完成工作后进行更新。 - Thorbjørn Ravn Andersen

15
Cat x = new Cat();

这行代码在内存中创建了一个Cat对象,并将其引用存储在x中。

现在,x包含对Cat对象的引用,但如果你执行以下操作:

x = x + 1;

这不会像在C语言中那样给出下一个内存地址,而是会导致编译器错误。Java不允许控制引用或内存位置。


2
这个简单的例子展示了最重要的区别。 - Jimmy

14

术语“引用”和“指针”基本上是等效的。我看到的许多关于Java基础知识的文献都声称Java没有指针。但是,如果您尝试使用null引用,就会得到一个NullPointerException。所以这都是语义问题。

(真正的区别在于,在C或C++中,“指针”一词严格意义上指的是一种整数,恰好是某些数据的内存地址。而在Java中,“引用”一词更接近于C++的“引用”概念。您甚至无法直接使用内存地址,但使用方式相同。)


8
早期NullPointerException这个名称被使用。更好的名称应该是NullReferenceException。 - Thorbjørn Ravn Andersen

4
如果我们把引用或指针看作是访问或处理内存中对象的一种手段,那么它们实际上是非常相似的。然而,它们在实现方面有所不同。以下是它们之间的区别:
  1. 指针支持指针算术运算,这使它们有点不安全。因为它们为程序员提供了比所需更多的访问级别。然而,引用通过一个更抽象的隐藏实现为对象提供了一个句柄。
  2. 指针类型较弱,而引用类型更强。我的意思是,在引用的情况下,代码更简单,而在指针的情况下,稍微不太正式。您需要使用 reinterpret_cast 等东西来使用指针转换,而引用则支持类似于 "C" 中基本类型的转换。
  3. 指针是不安全的,而引用是安全的。如果在两者之间选择,应选择引用。在像 C# 这样的语言中,您有这种自由。
  4. 指针存在于 C/C++ 中,而引用存在于 Java 中。不要将 C/C++ 中的引用与 Java 中的引用混淆。在 C/C++ 中,引用是指针的右值的一种同义词。

2
不,Java没有指针。Java中的基本概念是“值”和“引用”。

9
Java拥有指针并将它们称为引用。Java没有“指针运算”,而引用是有类型的,但仍然是指针。 - Matteo
你说得对,那也是我的意思。Kerrek最初看到了和我一样的东西。 - apollosoftware.org
@Matteo:在设计Java代码时,以“指针”为思考方式有何用处?我认为值/引用二分法更加有用:值被复制,引用被别名化。 - Kerrek SB
@Kerrek:我觉得告诉一个习惯于使用指针的人说它们不存在是令人困惑的。如果我想在Java中实现一棵树,我可以像在C中一样做,使用指针/引用来引用某些数据结构。 - Matteo
1
@Matteo:对于有经验的C++程序员来说,这样的解释可能会很有用。一般来说(我们不知道OP知道什么),我喜欢干净、自包含的方法,它与语言内在的思想相符,不会引入额外的负担。我想这是品味问题,但保持语言和仅仅是好比喻或实现的区别是很好的。 - Kerrek SB
1
JLS实际上说它们是指针,因此说Java没有指针是不正确的。"引用值(通常只是引用)是指向这些对象的指针,[...]。" - Radiodef

2

引用是一个指针,你通常看不到它的值(即内存地址)。唯一允许的操作是将其设置(从另一个引用)并通过它引用所引用的对象。它可以从引用值表达式(如new运算符)或从另一个引用设置(在语法上是一个简单的引用值表达式)。


1

就Java语法而言——确实,Java没有指针,但为了澄清情况,Java Runtime指针。 每次发生GC时,你存储在heap中的对象很可能会在物理上改变其内存地址。这只能通过使用真正被称为Pointer的东西来实现。由于你来自C++的世界,你知道引用限制。但这并不意味着JVM不使用引用=)。

若想获得更多信息,请参阅 Ordinary Object Pointer

因此,由于您已经对核心JVM内存管理有简要的了解,您可以将Java Reference术语视为运行时的Pointer

不,根本没有按引用传递。只有传值,因为真正的Java方法参数是Java Reference的副本,因此它是另一个Pointer

因此,从语法使用的角度来看 - Java参考更接近于C++参考,但在真实的运行时世界中,它更接近于指针
附注:为了更好地理解,最好阅读更多有关普通对象指针的文章或查看oop.hpp

0

由于Java不支持指针,因此引用可能看起来像是一种特殊类型的指针。但我们必须注意关键区别:使用指针时,我们可以指向任何地址(实际上是内存中的一个数字槽位)。因此,使用指针很可能会指向无效地址,然后在运行时可能会遇到意外问题。但引用类型始终将指向有效地址或将指向null。


-2

指针只包含地址,但引用不包含地址,坦率地说,对象的地址被分配给索引或哈希码,并且将哈希码和大小写代码赋予引用变量,如果我们查看引用变量的内容,它以类名@开头,然后是一些十六进制代码。这些数字不是地址,而是索引值或哈希码。

第二点,我们不能对引用值的内容执行任何算术操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接