什么是空?

null是任何东西的实例吗?

null属于哪个集合?

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


当前回答

null是任何东西的实例吗?

不,不存在null是实例的类型。

15.20.2类型比较操作符instanceof

RelationalExpression: ReferenceType的RelationalExpression实例 在运行时,如果RelationalExpression的值不为空,并且引用可以强制转换为ReferenceType而不引发ClassCastException,则instanceof操作符的结果为true。否则结果为假。

这意味着对于任何类型E和R,对于任何E o,其中o == null, o instanceof R总是false。


'null'属于哪个集合?

类型和值的种类

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


什么是空?

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

在Java中,null == null(在其他语言中并不总是这样)。还要注意,通过契约,它也有这个特殊的属性(from java.lang.Object):

public boolean equals(对象obj) 对于任何非空参考值x, x = (null)应该返回false。

它也是所有引用类型的默认值(对于具有该值的变量):

变量的初值

每个类变量、实例变量或数组组件在创建时都使用默认值初始化: 对于所有引用类型,默认值为null。

它的使用方式各不相同。您可以使用它来启用所谓的字段的惰性初始化,其中字段的初始值为null,直到实际使用为止,在实际使用中它被“真实”值所取代(这可能计算成本很高)。

还有其他用途。让我们看一个来自java.lang.System的真实例子:

公共静态控制台控制台() 返回:系统控制台(如果有),否则为空。

这是一种非常常见的使用模式:null用于表示对象不存在。

下面是另一个用法示例,这次来自java.io.BufferedReader:

public String readLine()抛出IOException 返回:一个包含行内容的字符串,不包括任何行终止字符,如果已经到达流的末尾则返回null。

因此,在这里,readLine()将为每一行返回instanceof String,直到它最终返回一个null来表示结束。这允许你像下面这样处理每一行:

String line;
while ((line = reader.readLine()) != null) {
   process(line);
}

可以设计API,使终止条件不依赖于readLine()返回null,但是可以看到,这种设计的好处是使事情变得简洁。注意,空行没有问题,因为空行"" != null。

让我们再举一个例子,这次来自java.util.Map<K,V>:

V get(对象键) 返回指定键映射到的值,如果此映射不包含该键的映射,则返回null。 如果这个映射允许空值,那么返回值为null并不一定表明映射不包含键的映射;也有可能map显式地将键映射为null。可以使用containsKey操作来区分这两种情况。

在这里,我们开始看到使用null会使事情变得复杂。第一个语句表示,如果键没有映射,则返回null。第二个语句表示,即使映射了键,也可以返回null。

相比之下,java.util.Hashtable通过不允许空键和值来简化事情;它的V get(对象键),如果返回null,明确表示键没有映射。

您可以通读其余的api,并找到在哪里以及如何使用null。请记住,它们并不总是最佳的实践示例。

一般来说,null被用作一个特殊的值来表示:

未初始化状态 终止条件 不存在的对象 未知值


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

在Java中?不关你的事。最好保持这种状态。


空是好事吗?

这是一种近乎主观的说法。有人说null会导致很多程序员错误,而这些错误本来是可以避免的。有人说,在像Java这样捕获NullPointerException的语言中,使用它是很好的,因为您将在程序员错误上快速失败。有些人通过使用空对象模式等来避免null。

这本身就是一个很大的话题,所以最好把它作为另一个问题的答案来讨论。

我将引用null的发明者c.a.r. Hoare(以快速排序而闻名)的话来结束这篇文章:

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

这个演示的视频更深入;这是推荐的手表。

其他回答

null是任何东西的实例吗?

不。这就是为什么null instanceof X将为所有类X返回false(不要被这样的事实所愚弄,即可以将null赋值给类型为对象类型的变量。严格来说,赋值涉及隐式类型转换;见下文)。

'null'属于哪个集合?

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

还有一种特殊的null类型,即表达式null的类型,它没有名称。因为null类型没有名称,所以不可能声明null类型的变量或强制转换为null类型。空引用是null类型表达式的唯一可能值。空引用总是可以转换为任何引用类型。在实践中,程序员可以忽略null类型,只是假装null只是一个特殊的文字,可以是任何引用类型。”JLS 4.1

什么是空?

见上图。在某些上下文中,null用于表示“没有对象”或“未知”或“不可用”,但这些含义是特定于应用程序的。

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

这是特定于实现的,您无法在纯Java程序中看到null的表示。(但在大多数(如果不是所有)Java实现中,null表示为零的机器地址/指针。)

Null是一个特殊值,它不是任何东西的实例。很明显,它不能是任何东西的实例。

Java中的null类似于c++中的nullptr。

c++程序:

class Point
{
    private:
       int x;
       int y;
    public:
       Point(int ix, int iy)
       {
           x = ix;
           y = iy;
       }
       void print() { std::cout << '(' << x << ',' << y << ')'; }
};
int main()
{
    Point* p = new Point(3,5);
    if (p != nullptr)
    {
       p->print();
       p = nullptr;
    }
    else
    {
        std::cout << "p is null" << std::endl;
    }
    return 0;
}

Java中的相同程序:

public class Point {
    private int x;
    private int y;
    public Point(int ix, int iy) {
        x = ix;
        y = iy;
    }
    public void print() { System.out.print("(" + x + "," + y + ")"); }
}
class Program
{
    public static void main(String[] args) {
        Point p = new Point(3,5);
        if (p != null)
        {
            p.print();
            p = null;
        }
        else
        {
            System.out.println("p is null");
        }
    }
}

现在你从上面的代码中明白什么是Java中的空了吗?如果没有,那么我建议你学习C/ c++中的指针,然后你就会明白。

注意,在C语言中,与c++不同,nullptr是未定义的,但使用NULL代替,这也可以在c++中使用,但在c++中nullptr比NULL更可取,因为C语言中的NULL总是与指针相关,所以在c++中,后缀“ptr”被附加在单词的末尾,而且所有字母现在都是小写的,但这并不重要。

在Java中,每一个类非原语类型的变量都是对该类型或继承的对象的引用,null是空类对象引用,但不是空指针,因为在Java中没有“指针”这样的东西,而是使用对类对象的引用,Java中的null与类对象引用有关,所以你也可以称它为“nullref”或“nullrefobj”,但这很长,所以就叫它“null”。

在c++中,你可以为可选成员/变量使用指针和nullptr值,即没有值的成员/变量,如果它没有值,那么它等于nullptr,所以在Java中如何使用null例如。

字节码表示

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

aconst_null:例如,将一个变量设置为null,如Object o = null; Ifnull和ifnonnull:例如,if (o == null)将对象与null进行比较

第6章“Java虚拟机指令集”接着提到了null对其他指令的影响:它会对许多指令抛出NullPointerException异常。

2.4. “引用类型和值”在通用术语中也提到了null:

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

Java中的Null (tm)

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

    0

or:

    0L

or:

    ((void*)0)

取决于编译器和内存模型选项。严格地说,NULL不是C/ c++本身的一部分。

在Java(tm)中,“null”不是关键字,而是null类型的特殊文字。它可以强制转换为任何引用类型,但不能转换为任何基本类型,如int或boolean。null字面量的值不一定是0。并且不可能强制转换为null类型或声明该类型的变量。