在Java中什么是空?

null是什么?

null是一个实例吗?

null属于什么集合?

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

377363 次浏览

null关键字是一个字面值,表示空引用不涉及任何对象的事物。Null是引用类型变量的默认值。

也可以看看

null: Java Glossary

不,它不是任何东西的实例,instanceof总是false。

null是任何东西的实例吗?

不,不存在nullinstanceof的类型。

15.20.2类型比较运算符instanceof . bb0

RelationalExpression:
RelationalExpression instanceof ReferenceType

在运行时,如果RelationalExpression的值不是null,那么instanceof操作符的结果是true,并且可以将引用转换为ReferenceType而不引发ClassCastException。否则,结果为false

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


'null'属于哪个集合?

JLS 4.1类型和值的种类 . 0

还有一个特殊的类型,即表达式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变量的初值 . 0

    每个类变量、实例变量或数组组件在创建时都使用默认值初始化:
    • 对于所有引用类型,默认值是null
    • 李< / ul > < / >

它的使用方式各不相同。你可以使用它来启用所谓的字段的延迟初始化,其中字段的初始值为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<K,V>:

V get(Object key)

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

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

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

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

你可以通读其余的api,找到null被使用的位置和方式。请记住,它们并不总是最佳实践示例。

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

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

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

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


null是一个好东西吗?

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

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

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

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

这次演讲的录像更深入;这是推荐的手表。

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是任何东西的实例吗?

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

'null'属于哪个集合?

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

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

什么是空?

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

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

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

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

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

Java中的Null (tm)

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

    0

或者:

    0L

或者:

    ((void*)0)

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

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

什么是空?

这没什么。

null是任何东西的实例吗?

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

null属于哪个集合?

没有任何集合

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

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

Object o=new Object();

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

现在o=null;

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

在我看来,在java中看待null的一种有趣的方式是,将它视为一种不表示信息缺失的东西,而仅仅是可以分配给任何类型引用的文字值。如果你想一下,如果它表示信息的缺失,那么a1==a2为真就没有意义了(如果它们都被赋值为null),因为它们真的可以指向任何对象(我们根本不知道它们应该指向什么对象)……顺便说一下,null == null在java中返回true。如果java像SQL:1999一样,那么null==null将返回unknown (SQL:1999中的布尔值可以取三个值:true,false和unknown,但在实践中,unknown在实际系统中实现为null)…http://en.wikipedia.org/wiki/SQL

字节码表示

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

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

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

2.4. “参考类型及值”在通用术语中也提到了null:

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

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

String x = null;

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

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

3.10.7. 空文字

null类型有一个值,即null引用,由 null literal null,由ASCII字符组成。< / p >

空字面值总是null类型。

只有赋值为null类型的引用才会被分配。您不需要为引用分配任何值(对象)。 这样的分配是特定于JVM将占用多少引用以及它将分配在哪个内存区域

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。