注:本文是對另一篇文檔( https://blog.csdn.net/duke_ding2/article/details/142365872
)的補充。
文章目錄
- 環境
- 初始化
- 局部變量(棧)
- 成員變量(堆)
- 其它
- 數組
- 分析
- 安全性
- 性能
- 成員變量 VS. 局部變量
- 總結
環境
- Windows 11 專業版
- Java 21
初始化
局部變量(棧)
局部變量不會自動初始化,所以必須要先賦值,再使用。
public static void main(String[] args) {int n1 = 0;int n2;System.out.println("n1: " + n1);System.out.println("n2: " + n2); // 編譯錯誤:變量沒有初始化boolean b1 = false;boolean b2;System.out.println("b1: " + b1);System.out.println("b2: " + b2); // 編譯錯誤:變量沒有初始化Object o1 = null;Object o2;System.out.println("o1: " + o1);System.out.println("o2: " + o2); // 編譯錯誤:變量沒有初始化}
注意:在Java 21之前(比如Java 17),對于引用類型的局部變量(比如上例中的 o2
),是會自動初始化為null的。Java 21引入了更加嚴格的限制,所有局部變量都必須先賦值,再使用。
成員變量(堆)
成員變量會自動初始化為 0
、 false
、 null
等。
public class Test1212_31 {private int n1;private boolean b1;private Object o1;public static void main(String[] args) {var obj = new Test1212_31();System.out.println(obj.n1);System.out.println(obj.b1);System.out.println(obj.o1);}
}
輸出結果如下:
0
false
null
其它
數組
在Java里,數組是對象,所以,創建數組后,數組里的元素可以隱式的初始化( 0
、 false
、 null
等)。
數組對象是在堆上創建的,可以把數組里的元素想象成類似數組對象的成員變量。
(注意:Java的數組是定長的,一旦創建了數組對象,其長度就不能變化了。當然,對于多維數組,只有最高維是不能變化的。)
public static void main(String[] args) {int[] arr1 = new int[3];for (int n : arr1)System.out.println(n);boolean[] arr2 = new boolean[3];for(boolean b : arr2)System.out.println(b);Object[] arr3 = new Object[3];for (Object o : arr3)System.out.println(o);}
輸出結果如下:
0
0
0
false
false
false
null
null
null
分析
局部變量不會自動初始化,成員變量會自動初始化。為什么要如此設計呢?
安全性
“先賦值,再使用”是一個通用的法則,通常我們也是這么做的,很少出現不賦值就使用的情況。
如果不清楚語言特性,那么“先賦值,再使用”顯然是一個good practice。如果不賦值就使用,那么假如沒有隱式初始化,則可能會出現無法預料的結果(因為變量的值無法預料)。通過強制程序員初始化變量,Java編譯器可以在編譯階段就發現這些問題,提高代碼的質量和安全性。
性能
我們知道,局部變量是在棧(stack)里的,其特點是生命周期較短,而調用較頻繁,比如:
public void foo(int arg1) {int n1;n1 = arg1 * 2;......}
foo()
方法可能會被頻繁調用,如果 n1
隱式初始化為 0
,顯然在頻繁調用 foo()
方法時,其開銷會更大(而且一般也沒有必要)。
再看另外一個例子:
public void bar() {for (int i = 0; i < 100; i++) {int temp;temp = i * 2;......}}
temp
變量是在循環內部定義的,和上一個例子類似,在循環次數很多時,隱式初始化的開銷會更大(而且一般也沒有必要)。
成員變量 VS. 局部變量
我們知道,對象是在堆(heap)上創建,所以,對象的成員變量也是在堆上的。對象的特點(相對于局部變量)是:
- 數量較少
- 生命周期較長
可能是為了幫助程序員確保對象的一致性和完整性,編譯器對成員變量進行了隱式初始化。由于數量相對比較少,隱式初始化的開銷也不算特別大。
如果沒有隱式初始化,程序員很可能需要在對象的構造方法里對成員變量做初始化。隱式初始化使得代碼更加簡潔,程序員可以集中精力在更重要的事情上面。
總結
- 局部變量(在棧上創建)沒有隱式初始化,必須先賦值,再使用
- 成員變量(在堆上創建)會隱式初始化(
0
、false
、null
等),可以直接使用