空值是一个对象吗?

129

在Java中,null是一个对象吗?


46
不,不是这样的。对于那些想知道为什么会有这样一个问题的人来说,有一些语言中null的确像任何其他对象一样成为了一个对象,例如Ruby。 - JRL
8
在Scala中,非常注重类型,存在一个名为Null的类型(实际上是一种特质),它具有一个名为null的单例实例。需要注意的是,该翻译并未包含解释或其他任何额外内容。 - Carl Smotricz
1
@JRL: 只是出于好奇,我想知道那会对JRUBY的工作产生什么影响...(我不熟悉这个层面的实现,所以不能确定。) - Benjamin Oakes
补充@JRL的评论 - Ruby中与null相当的是nil,它是NilClass的一个实例。 - Eliot Sykes
或者JavaScript中,null instanceof Object是false,但typeof(null)返回'object'。在这种情况下它是一个对象吗?谁知道呢。 - Don Hatch
14个回答

175
如果null是一个对象,它将支持java.lang.Object的方法,例如equals()。但事实并非如此-对null的任何方法调用都会导致NullPointerExceptionJava语言规范对此问题的表述如下:
特殊的null类型也存在,即表达式null的类型,其没有名称。由于null类型没有名称,因此不可能声明null类型的变量或将其强制转换为null类型。null引用是表达式的唯一可能值,该表达式具有null类型。null引用始终可以强制转换为任何引用类型。“在实践中,程序员可以忽略null类型”,只需假装null仅是可作为任何引用类型的特殊文字。
我认为这可以概括为“null是特殊的”。

1
如果一个在Java中的对象等于或者是java.lang.Object的子类,那么它才是一个真正的对象。实际上 - 是这样的。你无法创建一个不是java.lang.Object子类的类,但我从来没有从哲学的角度去思考过这个问题。 - Andreas Dolk
你说:“空引用总是可以转换为任何引用类型”。那么,我们能否在一个返回对象引用类型的方法中返回null(如果允许进行类型转换)? - Srichakradhar
1
@Srichakradhar:是的,我们可以做到!你最好尝试在代码中实现它,而不是在这里问。 - Michael Borgwardt
1
“空引用是空类型表达式的唯一可能值。”是时候阅读规范文档了。 :) - sofs1
1
就像-1的平方根一样,i也是特殊的。 - Gaurav Mall
显示剩余4条评论

33
根据Java 规范null是可以分配给对象变量的类型(如注释中所述)。但是您不能实例化或创建此类型的变量,必须使用编译器提供的字面值null

8
null是一种类型和一个值。 - Joachim Sauer
5
“null”名称显然是“null”类型的一个“实例”。 - strager
null不是一个变量,它是一个字面量:JLS,3.10.7. 空字面量 - Gerold Broser
关于“_null是可以被分配的类型_”:1)在代码中,null是_null字面量_,而不是_null类型_。2)通常情况下,在Java中无法将类型分配给变量,参见JLS 4.1:“_有两种数据值可以存储在变量中:原始值(§4.2)和引用值(§4.3)_”。可以通过null字面量来分配_null引用_。...续... - Gerold Broser
"对象变量 "中的 "对象" 通常与类变量不同,不是指类型而是指生命周期。当涉及到类型时,通常称为 "引用类型变量" 或简称为 "引用(类型)变量 "。我知道 Java API 中有 4 种公开实例/对象变量的类型(可能还有更多):具有其 length 属性的数组java.awt.geom.Point2D 的子类。 - Gerold Broser

29
绝对不行:null instanceof Object 返回false。

18
它仍然可以与所有引用类型进行赋值兼容。 - Chris Vest

13
JRL(及其他人)写道:

不,不是这样的……

通常情况下,这取决于你从哪个角度看待它,相信谁更多。
根据JLS,是的,它是。特别是如果你把问题改为:“null字面值是Object类型吗?”除了Michael Borgwardt上面引用的JLS 4.1
请参见JLS 3.10.7

null字面值始终是null类型。

以及JLS 4.10

类型T的子类型是所有类型U,使得T是U的超类型,并且是null类型。

或者JLS 4.10.2

null类型的直接超类型是除了null类型本身之外的所有引用类型。

[强调是我的。]
根据Eclipse 2019-09的编译器,不是这样的
true.toString();  // Cannot invoke toString() on the primitive type boolean
null.toString();  // Cannot invoke toString() on the primitive type null

根据OpenJDK 12.0.1版本的javac,它是:
true.toString();  // error: boolean cannot be dereferenced
null.toString();  // error: <null> cannot be dereferenced

角括号表示null是除原始类型以外的其他类型。根据JLS 4.1:
Java编程语言中有两种类型: 原始类型(...)和引用类型(...)。
如果不是一种就是另一种。
Claudiu写道:

null有点丑。

相反,null很美。你建议一个引用类型变量的默认值是什么?任意位组合吗?欢迎进入访问违规或更糟的指针地狱!
Joachim Sauer写道:

null是一种类型和值。

实际上,与null相关联的有三个项目(也可以参见JLS 3.10.7):
  1. (未命名的) null类型
  2. null 字面值
  3. null引用值。(通常缩写为null value或简称null。)
(1)请注意,根据上面引用的JLS 4.10.2null类型不仅适用于接口,而且还适用于类的多重继承。我们都知道对于应用程序员来说这是不可能的。
(2)null字面值可以想象为一个变量被定义为: JVM_global final null_type null = new null_type(); 还要注意JLS 3.9:

有时会错误地假定各种字符序列是关键字:

  • null不是关键字,而是null字面值(§3.10.7)。

关于null instanceof <any type>

考虑到 JLS 4.10.2(“null 类型是每种类型的子类型”),null instanceof <any type> 应该被认为是会评估为 true,对吗?乍一看是这样,但是 JLS 15.20.2 给出了深入的解答:

[...] instanceof 运算符的结果是 true,如果 RelationalExpression 的值不是 null [...]. 否则结果为 false

[强调是我添加的。]

从应用程序员的角度来看,你自己问什么更有意义:

  • Giving false and thus indicating that a reference expression is not of a type exposed to us, i.e. indicating it's not referencing anything useful to us

  • or giving true, thus informing us that the expression evaluates to a special reference, the null reference, referencing an "object" we don't know whether it even exists and which is of the special null type which has no name, is not exposed to us but via the null literal, is a subtype of any type including multiple inheritance and is to be ignored anyway? Consider also the more practical example:

       class Car implements Vehicle {  
       ...
       Vehicle car = null;
       ...
       boolean b = car instanceof Car;  // True? There's not even an instance
       ...                              // which could be of type Car.
    

这也导致了:

为什么instanceof不能正确表示null的对象性?

它被称为instanceof而不是sameorsubtypeof。这意味着我们比较的是一个实例的类型和一种类型,而不是两种类型。现在null的意思是:“没有实例”,如果没有实例,就没有实例的类型。显然,将空值与某个值进行比较应该会得到false

或者用一个“更真实”的例子来说:

  • 我手里有一个真正大小的苹果照片(=引用类型),上面写着“大苹果”(=引用类型名称)。
  • 桌子前有一张桌子(=堆)。
  • 如果桌子上有一个苹果(=实例),则连接着一根绳子(=引用)。
  • 我握住这根绳子的另一端(=引用变量)。
  • 我沿着绳子追踪苹果并将其与我的照片进行比较(=instanceof)。
  • 如果苹果的尺寸与照片相同或更大,则适用于“大苹果”的文字(=true)。
  • 如果它更小,则不适用(=false)。
  • 如果桌子上没有苹果(=没有实例),因此也没有绳子存在(=null),则文字也不适用(=false)。因为:没有苹果是大苹果吗?不是。


正如迈克尔总结的那样:“null是特殊的”。


2
苹果和null?你不怕被起诉吗? :) - Gábor Lipták

12

Null表示缺少一个对象。


但是 null 类型可以分配给任何引用类型。 - Tom Hawtin - tackline
没有所谓的“null类型”;null是非原始表达式(即引用)的特定值(据我理解,在Java中也没有“引用类型”)。 - Tommy McGuire
3
汤米:JLS 4.1:“还有一种特殊的 null 类型,即表达式 null 的类型,它没有名称。” - Ken
@TommyMcGuire 关于“Java中没有引用类型”的问题,请参见JLS 4.1:“Java编程语言中有两种类型:原始类型(§4.2)和引用类型(§4.3)。” - Gerold Broser

11

不,它不是一个对象。


9
不,它不是一个类的实例或类本身。它只是一个对于空对象的引用。
编辑:我没有阅读规范,因此上述可能不是100%准确。

6
正如Java语言规范的第4.1 The Kinds of Types and Values章所解释的那样,null是一个类型,有一个值,即null引用(表示为文字null):

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

你可能想了解关于Null Object Pattern(我不推荐使用)的内容。请查看C2 WikiWikipedia以获取更多关于该模式的信息。

4
不,null不是一个对象,因为null instanceof Object的结果总是false。另外,null只有一个,而不是每个类都有一个。

4
实际上,null instanceof <任何类型> 的结果也将返回 false - Bombe

4
根据Java规范,还有一个特殊的null字面量可用作任何引用类型的值。null可以分配给除基本类型变量以外的任何变量。除了测试其是否存在之外,你几乎不能对null值做任何事情。因此,在程序中通常使用null作为标记来指示某个对象不可用。

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