簡體   English   中英

為什么javac抱怨沒有初始化變量?

[英]Why does javac complain about not initialized variable?

對於這個Java代碼:

String var;
clazz.doSomething(var);

為什么編譯器報告此錯誤:

變量'var'可能尚未初始化

我認為所有變量或引用都被初始化為null 你為什么要做:

String var = null;

??

實例和類變量初始化為null(或0),但局部變量不是。

請參閱JLS的 §4.12.5 ,以獲得非常詳細的解釋,其中說的基本相同:

程序中的每個變量在使用其值之前必須具有值:

  • 在創建時,每個類變量,實例變量或數組組件都使用默認值進行初始化:
    • [剪掉所有默認值的列表]
  • 每個方法參數都初始化為方法的調用者提供的相應參數值。
  • 每個構造函數參數都初始化為由類實例創建表達式或顯式構造函數調用提供的相應參數值。
  • 異常處理程序參數初始化為表示異常的拋出對象。
  • 必須在使用初始化或賦值之前,通過編譯器使用明確賦值規則驗證的方式,在使用本地變量之前顯式賦予該值。

這是因為Java非常有用(盡可能多)。

它將使用相同的邏輯來捕捉您可能錯過的一些非常有趣的邊緣情況。 例如:

int x;

if(cond2)
   x=2;
else if(cond3)
   x=3;

System.out.println("X was:"+x);

這將失敗,因為有一個未指定的else案例。 事實是,這里應該絕對指定一個else case,即使它只是一個錯誤(默認情況下也是如此:switch語句中的條件)。

有趣的是,你應該從中獲取的是,在你弄清楚實際必須這樣做之前,不要初始化你的局部變量。 如果你習慣總是說“int x = 0;” 你會阻止這個夢幻般的“壞邏輯”探測器運行。 這個錯誤為我節省了不止一次的時間。

比爾K同上。我補充說:

Java編譯器可以通過在函數中使用變量之前未設置變量來保護您免受傷害。 因此,它明確地沒有設置默認值,正如Bill K所描述的那樣。

但是當談到類變量時,編譯器很難為你做這個。 類變量可以由類中的任何函數設置。 編譯器很難確定可能調用函數的所有可能的順序。 至少它必須分析系統中調用此類中任何函數的所有類。 它可能必須檢查任何數據文件或數據庫的內容,並以某種方式預測用戶將做出什么輸入。 充其量任務將極其復雜,最糟糕的是不可能。 因此對於類變量,提供可靠的默認值是有意義的。 這個默認值基本上是用零位填充字段,因此引用為null,整數為零,布爾值為false等。

比爾說,你絕對不應該養成在聲明變量時自動初始化變量的習慣。 如果在程序的上下文中這確實有意義,則僅在聲明時初始化變量。 比如,如果99%的時間你希望x為42,但在某些IF條件下你可能會發現這是一個特例,x應該是666,那么很好,從“int x = 42;”開始 並在IF內部覆蓋此。 但是在更正常的情況下,根據條件確定值,不要初始化為任意數字。 只需用計算出的值填充即可。 然后,如果您出現邏輯錯誤並且無法在某些條件組合下設置值,編譯器可以告訴您,您已經搞砸了而不是用戶。

PS我見過很多蹩腳的節目,比如:

HashMap myMap=new HashMap();
myMap=getBunchOfData();

當你知道你很快就會把這個物體扔掉一毫秒之后,為什么要創建一個對象來初始化變量呢? 那只是浪費時間。

編輯

舉一個簡單的例子,假設你寫了這個:

int foo;
if (bar<0)
  foo=1;
else if (bar>0)
  foo=2;
processSomething(foo);

這將在編譯時拋出一個錯誤,因為編譯器會注意到當bar == 0時,你永遠不會設置foo,但是你會嘗試使用它。

但是如果你將foo初始化為虛擬值,就像

int foo=0;
if (bar<0)
  foo=1;
else if (bar>0)
  foo=2;
processSomething(foo);

然后編譯器會看到無論bar的值是什么,foo都被設置為某個東西,所以它不會產生錯誤。 如果你真正想要的是當bar為0時foo為0,那么這很好。 但是,如果真正發生的是你的意思是其中一個測試是<=或> =或者你想在bar == 0時包含一個最后的else,那么你就欺騙了編譯器無法檢測到你的錯誤。 順便說一下,我認為這樣的結構編碼風格很差:編譯器不僅不能確定你的意圖,而且未來的維護程序員也不能。

我喜歡Bill K關於讓編譯器為你工作的觀點 - 我已經開始初始化每個自動變量了,因為它“看起來像是Java的事情”。 我無法理解類變量(即構造函數所擔心的持久性事物)和自動變量(某些計數器等)是不同的,即使一切都是Java中的類。

所以我回去並刪除了我正在使用的初始化,例如

List <Thing> somethings = new List<Thing>(); 
somethings.add(somethingElse); // <--- this is completely unnecessary

尼斯。 我一直在收到編譯器警告

List<Thing> somethings = new List(); 

我認為問題是缺乏初始化。 錯誤。 問題是我沒有理解規則,我需要在“新”中識別的<Thing> ,而不是任何<Thing>類型的實際項目。

(接下來我需要學習如何將文字小於和大於標記放入HTML中!)

我不知道它背后的邏輯,但局部變量沒有初始化為null 我想讓你的生活變得輕松。 如果可能的話,他們可以用類變量完成它。 這並不意味着你必須在開始時初始化它。 這可以 :

MyClass cls;
if (condition) {
    cls = something;
else 
    cls = something_else;

當然,如果你在展示它時確實有兩條線在彼此之上,請填充它,不需要默認的構造函數。 但是,例如,如果您想要聲明一次並使用它幾次或多次,則默認構造函數或null聲明是相關的。 或者是指向一個如此輕量級的對象的指針,最好在循環中一遍又一遍地分配它,因為指針的分配比對象的實例化要少得多? (據推測,在循環的每個步驟中都有一個新對象的正當理由)。

第四號

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM