專欄原創出處:github-源筆記文件 ,github-源碼 ,歡迎 Star,轉載請附上原文出處鏈接和本聲明。
Java 核心知識專欄系列筆記,系統性學習可訪問個人覆盤筆記-技術博客 Java 核心知識
一、Oracle 官方對 null 的描述
The Kinds of Types and Values 中說明,在實踐中,程序員可以忽略 null 類型,而只是假裝 null 只是可以是任何引用類型的特殊文字。
二、字節碼中與 null 相關的指令
從字節碼的角度看,僅有三個與 null 相關的指令:
-
aconst_null:將 null 對象壓入操作數堆棧
-
ifnull:爲 null 時跳轉
-
ifnonnull:不爲 null 時跳轉
HotSpot 對這 aconst_null 指令的實現,表明最終我們的 null 操作的是 c/c++ 中的「NULL」:
CASE(_aconst_null):
SET_STACK_OBJECT(NULL, 0); // 壓棧操作
UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
C++ Null 指針說明:
在變量聲明的時候,如果沒有確切的地址可以賦值,爲指針變量賦一個 NULL 值是一個良好的編程習慣。賦爲 NULL 值的指針被稱爲空指針。
NULL 指針是一個定義在標準庫中的值爲零的常量。在大多數的操作系統上,程序不允許訪問地址爲 0 的內存,因爲該內存是操作系統保留的。然而,內存地址 0 有特別重要的意義,它表明該指針不指向一個可訪問的內存位置。但按照慣例,如果指針包含空值(零值),則假定它不指向任何東西。
三、Java 中對 null 的理解
我們聲明一個對象,比如 Object o;
在聲明時虛擬機不確定 o 這個引用指針到底哪一塊數據區域,因此默認賦值給 null。表示有一個對象指針,但是還沒有確定要指向哪裏。
現在我們可能會想那我們聲明後直接指向一個對象不行嗎?是可以,這也是一個好習慣,能避免空指針異常。但是有時候我們確實需要在構造函數或者方法中根據其他變量的不同情況來確認對象的內容,或者確認不同的接口實現類。
假設我們不用 null 這個特殊的符號代替。我們讓系統如何表示?用 -1?如果默認-1,那在操作對象的時候 -1 該不該參與運算!
索性就把內存地址裏的 0 這個特殊的地址作爲一個特殊標識。這個地址 0 受到系統保護,程序不能進行寫操作。
總結
null 不是任何實例。null 僅僅是一個標識符,標識這個對象還沒初始化。
可以試着編譯下面的類,然後 javap -c -p -v Null.class
查看相關字節碼
public class Null {
private Object o1 = null;
private Object o2 = null;
private Object[] nullObj = new Object[]{null, null};
public boolean isNull(Object o) {
boolean r = o == null;
return r;
}
}