爲何 Java 中全局變量不必定初始化,局部變量必須初始化?

前幾天,有個大佬考了我一個問題:爲何類的成員變量不須要指定值就能夠自動賦予初始值,而方法內的局部變量就必須指定初始值呢?

說實話,這個問題確實難倒我了,以後我在網上一頓操做,終於把這個問題弄得稍微明白一點了。
首先我給出一個具體的場景來講明這個事情:
image.png
定義一個Cat類,裏面有各類屬性,包括8大基本數據類型和String類型,咱們把String類視爲複雜數據類型。Cat類裏面有一個setAge方法。咱們在main方法裏面給tom這個Cat賦值年齡,結果發現,若是給定的年齡沒有賦初始值,編譯器會報錯:
image.png
那咱們來看下未給Cat裏面的各類屬性初始化,各項屬性的初始值到底是怎樣的:
重寫一下toString方法:
image.png
而後輸出結果爲:
image.png
咱們可以看到,對於8大基本類型的初始化已經實現了,分別是如圖所示的值。對於複雜的類,會賦予null做爲默認值。(這裏char的默認值爲'/u0000'也就是null)
那麼問題來了,爲何Java會有這樣的操做呢,爲何不能將方法內的局部變量也自動賦值一個默認值呢?java


首先,我在網上找到了這樣的一個答案以下,若是不想看原文,能夠直接跳過至引用答案的結尾處直接看個人總結:
這位做者在讀《深刻理解Java虛擬機》的時候記錄了一個相關知識點。程序員

類的成員變量有默認初始值,而方法內的局部變量卻沒有初始值。這個問題涉及到 JVM類加載字節碼執行兩個階段,這兩個階段是依次執行的。

JVM類加載是JVM利用類加載器將class文件加載到JVM的過程,涉及「加載」、「驗證」、「」準備「、「」解析「和」初始化「。
1、類的成員變量初始化   ---在JVM類加載階段完成編程

類的成員變量又分爲靜態成員變量和非靜態成員變量。性能

靜態成員變量spa

靜態成員變量會被初始化兩次,第一次在「準備」階段,先進行一次初始化,系統附上默認值;第二次在「初始化」階段,根據代碼中的賦值狀況再進行一次初始化。.net

例如:線程

public static int i =3 ;code

第一次初始化後i的值爲0,第二次初始化後,值才爲3.對象

數據最終存放在方法區中。blog

非靜態成員變量

僅「初始化」階段賦值。根據代碼中的賦值狀況,代碼不賦值直接賦默認值,有賦值則等於代碼中的賦值。對象實例化後,該變量隨java對象分配到java堆中。

2、方法區的局部變量沒有初始化

而方法中的局部變量沒有初始化步驟,以下圖:
image.png
須要在代碼中進行初始化。
image.png
————————————————
緣由就是類方法中的代碼,實在字節碼執行的時候,纔會被運行到,此時局部變量是存儲在虛擬機棧-棧幀中的局部變量表中。局部變量定義了可是沒有賦值是不能使用的。
版權聲明:本文爲CSDN博主「一步一臺階」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。
原文連接:https://blog.csdn.net/liufang...


這篇帖子主要是說明了兩種變量在JVM編譯代碼的時候把他們放在了哪裏。

  1. JVM加載類的時候,不論是靜態類仍是非靜態類,都會給每一個類分配內存,存在堆裏面,都有初始化的這一步操做。
  2. 對於方法內的局部變量,因爲方法要放到堆棧中(堆棧這個詞,其實意義就是棧,習慣稱爲堆棧,其實和堆不要緊),只有字節碼執行的時候纔會被運行到,因此沒有賦值是不能使用的。

………………??? 這是什麼意思?也就是說,兩種變量的存儲位置不同,會對是否初始化有影響,可是沒有說明爲何成員變量在堆裏就有初始化,方法內局部變量爲啥放在堆棧裏面,只有執行方法的時候纔會被運行到就不能初始化呢?
而後我就找到另外一篇文章以下:

爲何 Java 中全局變量不必定初始化,局部變量必須初始化?

做者:Intopass
連接:https://www.zhihu.com/questio...
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

  1. 首先 Java 語言就是這麼規定的。
  2. 而後爲何 Java 語言要這麼規定呢?有什麼內部機理嗎?

可能的緣由以下,當咱們新建一個對象時,Java會在Heap中申請一塊內存區域用以存放類的數據。而成員變量就是類的數據,也是放在這塊內存區域中的。只須要JVM在申請內存的時候順便把整塊區域都置爲零便可完成初始化,方便快捷。
而對於方法的局部變量,是在線程的Stack中,固然Stack他也能夠幫咱們初始化,不過有一個問題。對於有些局部變量,在方法的一開始是沒有的,有些在循環中的局部變量是要反覆的聲明屢次的。有些局部變量做用域結束後,另外一個局部變量又會佔用這個局部變量的位置。
那麼初始化要放在什麼時候呢?固然JVM能夠幫咱們初始化屢次,不過那樣或許會帶來性能問題。

for (int i = 0; i < 10; i++) {
    int n;
    if (i % 2 == 0) {
        n = 10;
    } else {
        n = 20;
    }
}

像是這個n,咱們徹底不用JVM幫咱們初始化,若是每次循環他都幫咱們初始化一次,那麼是沒有必要的。綜上所述,對於局部變量,可能不幫咱們初始化是一個不錯的選擇。(並且JVM實現起來也更容易!!!)


經過看這位做者的講解,咱們就可以理解得更清楚一些了。爲何堆內的成員變量能夠初始化?由於容易,申請內存的時候順便就實現了初始化。爲何棧內的局部變量不能初始化?由於麻煩,並且沒有必要。
最後,我又看到了一個內容,同知乎頁面另外一個匿名做者的回答:

套用《Thinking in Java》做者Bruce Eckel的話

編譯器固然能夠爲局部變量附一個默認值,可是未初始化的局部變量更有多是程序員的疏忽,因此採用默認值範圍會掩蓋這種失誤。所以強制程序員提供一個初始值,每每可以幫助找出程序裏的缺陷。


其實我以爲這句話應該是對於爲何局部變量不可以初始化的最合理的解釋了吧。
總結一下,爲何局部變量須要手動初始化?從技術上來說,局部變量通常來講總量大,生命週期短,JVM進行初始話開銷較大;從業務上講,局部變量通常用於實際問題下的運算,不多會用到默認值,賦值意義不大;從編程思想上講,局部變量不初始化,而是報錯提醒,更有助於程序員減小開發過程當中出現缺陷的可能。一舉三得,何樂而不爲?回到開頭,因此說大佬就是大佬,隨隨便便問一個問題,看似是一個小問題,可是深究下去居然牽扯到這麼多深層次的知識點,甚至有點哲學的意義在裏面,佩服佩服!

相關文章
相關標籤/搜索