【问题标题】:What is null in Java?Java 中的 null 是什么?
【发布时间】:2011-02-12 00:49:10
【问题描述】:

null 是什么?

null 是任何事物的实例吗?

null 属于哪个集合?

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

【问题讨论】:

  • yegor256.关于 JLS 的 null 。 “空文字。空类型有一个值,即空引用,由空文字 null 表示,它由 ASCII 字符组成。空文字始终是空类型。”关于文章中的要点。 “可变和不完整的对象”是一项功能。 “缓慢失败”是一种设计能力。 “计算机思维与对象思维”只是两种思维方式。 “模棱两可的语义”太主观了。 “临时错误处理”是另一种处理错误的方法。 Null 是文字或 JLS 中指定的任何其他内容,与不好或不好的对比。

标签: java null terminology


【解决方案1】:

字节码表示

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

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

Chapter 6 "The Java Virtual Machine Instruction Set " 然后提到了null 对其他指令的影响:它为许多指令抛出了NullPointerException

2.4. "Reference Types and Values" 还笼统地提到了null

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

【讨论】:

    【解决方案2】:

    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 中的 null 是什么吗?如果不是,那么我建议你学习 C/C++ 中的指针,然后你就会明白。

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

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

    在 C++ 中,您可以为 optional 成员/变量使用指针和 nullptr 值,即没有值的成员/变量,如果它没有值,则它等于 nullptr,所以如何为 null例如可以使用Java。

    【讨论】:

      【解决方案3】:

      简短而准确的答案,正式从 JLS 回答您的所有问题:

      3.10.7。空字面量

      null 类型有一个值,即 null 引用,由 null 文字 null,由 ASCII 字符组成。

      null 文字总是 null 类型。

      仅分配分配给 null 的类型的引用。您没有为引用分配任何值(对象)。 这种分配特定于 JVM 需要多少引用以及将分配到哪个内存区域。

      【讨论】:

        【解决方案4】:

        Java 中有两大类类型:primitivereference。声明为原始类型的变量存储值;声明为引用类型的变量存储引用。

        String x = null;
        

        在这种情况下,初始化语句声明了一个变量“x”。 “x”存储字符串引用。这里是 null。首先,null 不是一个有效的对象实例,因此没有为它分配内存。它只是一个值,表明对象引用当前没有引用对象。

        【讨论】:

          【解决方案5】:

          null 是任何事物的实例吗?

          不,没有类型 nullinstanceof

          15.20.2 Type Comparison Operator instanceof

          RelationalExpression:
              RelationalExpression instanceof ReferenceType
          

          在运行时,如果 RelationalExpression 的值不是 null 并且引用可以转换为 ReferenceTypeinstanceof 运算符的结果是 true /em> 没有提出ClassCastException。否则结果为false

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


          'null'属于什么集合?

          JLS 4.1 The Kinds of Types and Values

          还有一个特殊的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) 应该是return false

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

          JLS 4.12.5 Initial Values of Variables

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

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

          还有其他用途。让我们以java.lang.System的真实例子为例:

          public static Console console()

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

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

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

          public String readLine() throws IOException

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

          所以在这里,readLine() 将为每一行返回instanceof String,直到它最终返回一个null 来表示结束。这允许您按如下方式处理每一行:

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

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

          让我们再举一个例子,这次来自java.util.Map&lt;K,V&gt;

          V get(Object key)

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

          如果此映射允许null 值,则返回值null 不一定表示该映射不包含该键的映射;该映射也可能将密钥显式映射到nullcontainsKey 操作可以用来区分这两种情况。

          在这里,我们开始了解使用null 会如何使事情复杂化。第一条语句表示如果键未映射,则返回 null。第二条语句表示即使key被映射,null也可以返回。

          相比之下,java.util.Hashtable 不允许使用 null 键和值,从而使事情变得更简单;它的V get(Object key),如果返回null,则明确表示该键未映射。

          您可以通读其余的 API 并了解 null 的使用位置和方式。请记住,它们并不总是最佳实践示例。

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

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

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

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


          null 是个好东西吗?

          现在这是边缘主观的。有人说null 会导致许多本来可以避免的程序员错误。有人说,在像 Java 这样可以捕获NullPointerException 的语言中,最好使用它,因为您将在程序员错误时快速失败。有些人通过使用Null object pattern等来避免null

          这本身就是一个巨大的话题,因此最好将其作为另一个问题的答案来讨论。

          我将引用null 的发明者本人C.A.R Hoare(以快速排序闻名)的话来结束这篇文章:

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

          video of this presentation 更深;这是推荐的手表。

          【讨论】:

          • 空引用存在于 1960 年的 LISP(如 NIL)中,可能更早。但我不认为 Hoare 真的试图在该引文中声称发明了空引用。
          • Hoare 并没有试图声称发明了空引用;他只是声称他在一个特别有影响力的地方提供了它们。包括 Java 在内的许多语言显然都是从 Algol 中获得灵感的,如果它们对空引用的使用甚至部分受到 Algol 的启发或复制,那么 Hoare 承担了这些成本的部分责任是正确的。然而,我确实觉得他的估计相当低。一万亿美元可能更接近真实成本。
          • 这不能回答问题:(
          【解决方案6】:

          在我看来,在 java 中查看 null 的一种有趣方式是将其视为不表示缺少信息的东西,而只是作为可以分配给任何类型引用的文字值。如果您考虑一下,如果它表示缺少信息,那么 a1==a2 为真没有意义(如果它们都被分配了 null 值),因为它们实际上可能指向任何对象(我们只是简单地不知道他们应该指向什么对象)...顺便说一句 null == null 在java中返回true。如果 java 例如就像 SQL:1999 然后 null==null 将返回未知(SQL:1999 中的布尔值可以采用三个值:真、假和未知,但实际上未知在实际系统中实现为 null)...http://en.wikipedia.org/wiki/SQL

          【讨论】:

            【解决方案7】:

            null 是任何事物的实例吗?

            没有。这就是为什么null instanceof X 将为所有类X 返回false。 (不要被您可以将null 分配给类型为对象类型的变量的事实所迷惑。严格来说,该分配涉及隐式类型转换;见下文。)

            'null'属于什么集合?

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

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

            什么是空?

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

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

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

            【讨论】:

              【解决方案8】:

              什么是 null?

              没什么。

              null 是任何东西的实例吗?

              不,因为它什么都不是它不能是任何事物的实例。

              null属于什么集合?

              没有设置

              它在记忆中是如何表现的?

              如果一些参考指向它,例如:

              Object o=new Object();
              

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

              现在o=null;

              这意味着现在 o 不会指向对象的那个内存空间。

              【讨论】:

              • "现在 o=null; 这意味着现在 o 不会指向对象的那个内存空间。"我认为这就是垃圾收集在 JAVA 中的工作方式
              【解决方案9】:

              Java 中的 Null(tm)

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

                  0
              

              或:

                  0L
              

              或:

                  ((void*)0)
              

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

              在 Java(tm) 中,“null”不是关键字,而是 null 类型的特殊文字。它可以转换为任何引用类型,但不能转换为任何原始类型,例如 int 或 boolean。空文字不一定具有零值。并且无法强制转换为 null 类型或声明该类型的变量。

              【讨论】:

                【解决方案10】:

                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);
                

                【讨论】:

                  【解决方案11】:

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

                  【讨论】:

                    【解决方案12】:

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

                    也可以看看

                    null : Java Glossary

                    【讨论】:

                    • 这不是关键字,而是literal。质量差,引用不规范。
                    【解决方案13】:

                    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);
                       }
                    }
                    

                    【讨论】:

                    • 该示例显示的唯一内容是null 不是String 的实例。
                    • 如果你把签名改成void f(String o),那就更有意义了。
                    【解决方案14】:

                    不,它不是任何事物的实例,instanceof 将始终为 false。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2023-03-22
                      • 1970-01-01
                      • 2014-01-19
                      • 1970-01-01
                      • 2013-11-26
                      • 1970-01-01
                      相关资源
                      最近更新 更多