在Java中,null是什么?

284

null是什么?

null是任何实例吗?

null属于哪个集合?

它在内存中如何表示?


yegor256。关于JLS中的null。"Null字面值。null类型只有一个值,即null引用,由ASCII字符组成的null字面值,它始终是null类型。" 关于文章中的要点。'可变和不完整对象'是一种特性。'慢失败'是一种设计能力。'计算机思维与对象思维'只是两种思考方式。'模糊语义'太主观了。'特定错误处理'是另一种处理错误的方式。null是JLS中指定的字面值或其他任何东西,与好坏无关。 - Oleksii Kyslytsyn
14个回答

329

空值是某个实例吗?

不是的,没有任何类型可以让 null 成为其 instanceof 实例。

15.20.2 类型比较运算符 instanceof

RelationalExpression:
    RelationalExpression instanceof ReferenceType

At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast to the ReferenceType without raising a ClassCastException. Otherwise the result is false.

这意味着对于任何类型的 ER,对于任何 E o,其中 o == nullo instanceof R 总是 false

JLS 4.1 类型和值的种类

还有一种特殊的null类型,即表达式null的类型,它没有名称。因为null类型没有名称,所以无法声明null类型的变量或将其强制转换为null类型。 null引用是null类型表达式的唯一可能值。 null引用始终可以转换为任何引用类型。在实践中,程序员可以忽略null类型,只需假装null仅是一个可以是任何引用类型的特殊字面量。


什么是null?

正如上面的JLS引用所说,在实践中,你可以简单地假装它是“只是一个可以是任何引用类型的特殊字面量”。

在Java中,null == null(在其他语言中并不总是这样)。还要注意,按照合同,它还具有这个特殊属性(来自java.lang.Object):

public boolean equals(Object obj)

对于任何非null引用值xx.equals(null)应该返回false

对于所有引用类型,它也是所有引用类型变量的默认值(如果有的话):

JLS 4.12.5 变量的初始值

  • 每个类变量、实例变量或数组组件在创建时都会初始化为默认值
    • 对于所有引用类型,缺省值为null
这个用法有所不同。您可以使用它来启用所谓的惰性初始化字段,其中字段将具有其初始值null,直到实际使用它时,它被“真实”值(可能计算代价高昂)替换。
还有其他用途。让我们从 java.lang.System 中拿一个真实的例子:

public static Console console()

返回:系统控制台(如果有),否则为null

这是一种非常常见的用法模式:null用于表示对象不存在。
这里是另一个用法示例,这一次来自 java.io.BufferedReader

public String readLine() throws IOException

返回:包含行内容但不包括任何行终止字符的String,或者null,如果已到达流的末尾。

因此,在这里,readLine()会为每行返回String的实例,直到最终返回null以表示结束。这使您可以按以下方式处理每行:
String line;
while ((line = reader.readLine()) != null) {
   process(line);
}

可以设计API,使终止条件不依赖于readLine()返回null,但可以看出这种设计的好处在于使事情更简洁。请注意,空行没有问题,因为空行"" != null
让我们再来看一个例子,这次是来自java.util.Map<K,V>

V get(Object key)

返回映射到指定键的值,如果此映射不包含键的映射,则返回null

如果此映射允许null值,则null的返回值并不一定表示该映射不包含键的映射;也有可能映射将键明确地映射到null。可以使用containsKey操作来区分这两种情况。

在这里,我们开始看到如何使用null会使事情变得复杂。第一个语句表示,如果未映射键,则返回null。第二个语句表示,即使键已映射,也可以返回null
相比之下,java.util.Hashtable更简单,因为它不允许使用null键和值;如果V get(Object key)返回null,则意味着该键没有映射关系。
您可以阅读其余的API并查找null的使用位置和方式。请记住,它们并不总是最佳实践的例子。
一般来说,null用作特殊值,表示:
  • 未初始化状态
  • 终止条件
  • 不存在的对象
  • 未知值

它在内存中是如何表示的?

在Java中?你不需要关心。最好保持这种状态。


使用null是否好?

现在这已经是一个有争议的问题了。有些人认为null会导致许多本可以避免的程序员错误。有些人则认为,在像Java这样捕获NullPointerException的语言中,使用它是好的,因为你会快速地检测到程序员错误。一些人通过使用Null对象模式等方式来避免使用null

这是一个很大的话题,最好作为回答另一个问题来讨论。

我将以null的发明者C.A.R Hoare(快速排序的创始人)的话来结束:

我称之为我的十亿美元错误。 这是在1965年发明null引用的时候。当时,我正在设计第一个面向对象语言(ALGOL W)中引用的全面类型系统。我的目标是确保所有引用的使用都是绝对安全的,并由编译器自动执行检查。但我无法抵制放置一个null引用的诱惑,仅仅因为它非常容易实现。这导致了无数的错误、漏洞和系统崩溃,可能在过去四十年里造成了十亿美元的痛苦和损失。

这个演示的视频更深入,建议观看。


5
LISP语言中的空引用(以NIL表示)早在1960年就存在,可能更早。但我认为Hoare并不是真正试图声称他发明了空引用。 - Stephen C
10
Hoare并不是在声称他发明了空引用;他只是声称他在一个特别有影响力的地方使它们得以使用。包括Java在内的许多语言明显受到Algol的启发,如果它们对空引用的使用甚至部分受到或复制自Algol的影响,那么Hoare在承担这些成本时是正确的。然而,我觉得他的估计有点低。一万亿美元可能更接近真实成本。 - cjs
这并没有回答问题 :( - Adam Arold

33

null是任何实例吗?

不是。这就是为什么对于所有类X,“null instanceof X”都将返回“false”的原因。(不要被您可以将null分配给对象类型的变量所欺骗。严格来说,该赋值涉及隐式类型转换;请参见下文。)

‘null’属于哪个集合?

它是null类型的唯一成员,其中null类型定义如下:

“还有一个特殊的null类型,即表达式null的类型,它没有名称。由于null类型没有名称,所以无法声明null类型的变量或将其强制转换为null类型。 null引用是null类型表达式的唯一可能值。 null引用始终可以转换为任何引用类型。在实践中,程序员可以忽略null类型,并假装null只是一个可以是任何引用类型的特殊文字。” JLS 4.1

null是什么?

请参见上文。在某些情况下,null用于表示“无对象”、“未知”或“不可用”,但这些含义是应用程序特定的。

它在内存中是如何表示的?

这取决于具体实现方式,您无法在纯Java程序中查看null的表示形式。(但在大多数Java实现中,null表示为零机器地址/指针。)


16

null是什么?

null表示空值。

null是某个实例吗?

不是,因为null表示空值,它不能是任何实例。

null属于哪个集合?

null不属于任何集合。

null在内存中如何表示?

如果有一些引用指向它,比如:

Object o=new Object();

在堆内存中,新创建的对象会被分配一些空间。o将指向内存中分配给该对象的空间。

现在o=null;

这意味着现在o不再指向该对象的内存空间。


1
现在 o=null; 这意味着现在 o 不再指向该对象的内存空间。我认为这就是 JAVA 中垃圾回收的工作方式。 - Hardik Mishra

10

不,这不是任何东西的实例,instanceof 操作符总是返回 false。


9

Java中的Null

C和C++中,"NULL"是在头文件中定义的一个常量,它的值如下:

    0

或者:

    0L

或者:

    ((void*)0)

根据编译器和内存模型选项的不同,NULL并不严格属于C/C++本身。在Java中,“null”不是关键字,而是特殊的null类型字面量。它可以转换为任何引用类型,但不能转换为任何原始类型,如int或boolean。空字面值不一定具有零值。无法将其转换为null类型或声明此类型的变量。


7

空值关键字是表示空引用的文字,它不指向任何对象。空值是引用类型变量的默认值。

另外也可以看看:

null : Java 词汇表


3
这不是一个关键词,而是一个“字面值”(literal)(http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.7)。引用质量较差且不规范。 - user207421

6

Null不是任何类的实例。

然而,你可以将null赋值给任何(对象或数组)类型的变量:

 // this is false   
 boolean nope = (null instanceof String);

 // but you can still use it as a String
 String x = null;
 "abc".startsWith(null);

6

字节码表示

Java中的null在JVM上有直接的支持:它使用了三个指令来实现:

  • aconst_null:例如将变量设置为null,如:Object o = null;
  • ifnullifnonnull:例如将对象与null进行比较,如:if (o == null)

第6章“Java虚拟机指令集”然后提到了null对其他指令的影响:它会对其中许多指令抛出NullPointerException

2.4.“引用类型和值”也以通用术语提及null

引用值还可以是特殊的null引用,即不指向任何对象的引用,在这里用null表示。null引用最初没有运行时类型,但可以转换为任何类型。引用类型的默认值为null。


4

null 是一个特殊的值,它不是任何东西的实例。显然,它不能是任何东西的 instanceof


3

null是一个特殊的值,它不属于任何类的实例。以下程序说明了这一点:

public class X {
   void f(Object o)
   { 
      System.out.println(o instanceof String);   // Output is "false"
   }
   public static void main(String[] args) {
      new X().f(null);
   }
}

6
这个例子只是表明null不是String的一个实例。 - Sasha Chedygov
4
如果你将签名更改为“void f(String o)”,它会更有意义。 - Thilo

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