在Java中取消引用“null”时是否可能产生未定义的行为?

我刚刚了解到在C和C ++中取消引用null有时会产生未定义的结果 。 这对我来说非常有趣,就像所有离奇的编程行为一样(我曾经有人告诉我他们调试了“损坏的RAM – 程序在合法的生产环境中不能像运行一样运行”)。 因为我主要是一名Java开发人员,所以我想知道这种语言是否有可能以这种语言发生?

JLS并没有具体说明如何实现null引用( 3.10.7,4.1,15.8.1 ),所以我不太确定。 但我认为通过使用Unsafe API直接操作内存地址可能是可能的。 不幸的是,我对JVM的内部工作原理知之甚少,无法知道这是否可行。

如果可能,那么恶意程序也可能这样做,这将开启一个有趣的安全问题。

那么:当解除引用null ,Java是否有可能具有未定义的行为,而不是简单地抛出NullPointerException

您无法在纯Java中从null获取未定义的行为(除非JVM中存在严重错误!)。 JLS指定任何显式或隐式取消引用null尝试都将导致NullPointerException 。 没有蠕动空间允许任何与null处理相关的未定义行为。

但是,如果您的应用程序包含…或使用… native方法,则其中一种方法可能会以导致未定义行为的方式error handlingnull 。 您还可以使用Unsafe类获取未定义的行为。 但这两种情况都意味着您不使用 Java。 (当你走出 Java之外,JLS的保证不再适用!)

(可能发生不可预测事情的一个领域是multithreading。但即便如此,也可以定义一可能的行为。例如,如果你没有充分同步状态共享,你可能会看到字段中的陈旧值。但是你赢了看不到完全随机的值…或导致分段违规的错误地址。)


如果可能,那么恶意程序也可能这样做,这将开启一个有趣的安全问题。

恶意程序几乎可以做任何事情。 但处理此问题的正确方法是在沙箱中执行您不信任的代码(即可能是恶意代码)。 典型的沙箱禁止调用Unsafe或加载本机库……以及恶意程序可以利用的许多其他东西。

JLS并未具体说明如何实现null引用,但它指定了它的行为 。 换句话说,没有没有未指明的行为。 如果您遇到JLS中指定的行为以外的行为,那就是一个错误。

让我澄清一下:您可以使用本机代码来删除某些结构以使JVM崩溃,但这与任何Java行为无关。 但是在典型的JVM实现中, null行为的实现是你可以打扰的最后一件事。 不是,重要的是,如果你从本机代码覆盖任意内存,你会丢弃什么

“未指定的行为”意味着规范本身允许在结果行为中存在差异。 Java不是这种情况。

该行为在15.12.4.4定位调用方法中定义:

否则,将调用实例方法并且存在目标引用。 如果目标引用为null,则此时抛出NullPointerException。 否则,目标引用被称为引用目标对象,并将在调用的方法中用作关键字this的值。 然后考虑调用模式的其他四种可能性。

取消引用null应抛出NullPointerException。

具有未定义行为的语言特征的概念是C和C ++标准的编写者用来明确标准不需要任何特定行为的东西。 这使得C和C ++的各种实现者能够为实现所针对的特定硬件或操作系统做最有效或最方便的事情。 这是因为C始终具有优于可移植性的性能。 但Java具有相反的优先级; 它的早期口号是“一次编写,随处运行”。 所以Java语言规范没有讨论未定义的行为 ,并努力定义所有语言特性的行为。

您似乎认为使用空引用可能会在某些情况下以某种方式破坏内存。 我认为你将C / C ++指针与Java引用混淆。 指针本质上是一个内存地址:通过将其转换为void *并取消引用它,您可以无限制地破坏内存内容。 Java引用与内存地址不同,因为垃圾收集器必须可以自由地将对象移动到内存中的不同位置。 将Java引用转换为内存地址是只有JVM才能做到的事情; 它永远不会是Java程序本身可以做的事情。 由于此转换完全由JVM控制,因此JVM可以确保转换始终有效,并始终指向它应该和其他任何地方的对象。