1. 程式人生 > >如何排查can not find symbol的編譯錯誤

如何排查can not find symbol的編譯錯誤

Cannotfind symbol意味著什麼

首先,它是一個編譯錯誤,意味著你的原始碼有問題或者編譯的方式有問題。

你的原始碼有以下部分組成:

Ø  關鍵詞:比如 true  false  class while等等

Ø  字面值:比如42  ’x’ 和 “Hi mum!” 等等

Ø  操作符和其他非字母數字符號:比如  +  =  { 等等

Ø  註釋和空白格

一個cannot find symbol 報錯就是關於識別符號的。當你的程式碼編譯時,編譯器需要弄明白你你程式碼中每一個識別符號的含義。而這類報錯就意味著編譯器不明白你程式碼指代的東西。

引起cannot findsymbol錯誤的原因

歸根到底無非是因為編譯器查找了所有識別符號應該被定義的地方都找不到定義。有很多原因可以導致,常見的如下:

l  通用識別符號

  • 名字拼寫錯誤:比如StringBiudler而不是StringBuilder。Java不會試圖彌補糟糕的拼寫或輸入錯誤
  • 大小寫錯誤:比如stringBuilder而不是StringBuilder。所有的Java識別符號是大小寫敏感
  • 下劃線使用不正確:比如mystring和my_string是不同的(如果你嚴格按照Java的風格規則,你就能很大程度避免這類錯誤)

l  變數識別符號

  • 忘記宣告變數
  • 變數聲明範圍無法覆蓋你嘗試使用的點

l  方法名識別符號

 也許你試圖引用一個繼承的方法,而它卻沒在父/祖先類/介面中定義

l  類名識別符號

  •  忘記匯入類
  • 用了star 匯入,但是該類卻不在你匯入的任何包中定義
  • 忘記new關鍵字使用:比如Strings=String();

通常問題可能是以上的幾個原因導致。比如,也許你星號匯入java.io.*並且嘗試使用Files類(存在java.nio而不是java.io),其實你是想寫File(存在java.io的類)

以下是一個不正確的變數方位導致”cannot find symbol”錯誤的例子:

for (int i = 0; i < strings.size(); i++) {

if(strings.get(i).equalsIgnoreCase("fnoord"

)) {

break;

}

}

if (i < strings.size()) {

...

}

儘管我們預先聲明瞭i,但是宣告的範圍只是在for 語句和迴圈體裡面,而第二個if語句中的i引用是看不見這個宣告。這裡比較合適的修改是把第二個if語句挪進迴圈體,或者在迴圈之外重新宣告一個i變數。

如果你是從命令列去編譯的話還有可能是因為忘記編譯或者重編譯其他的類所以編譯器就報該類錯誤。比如你有Foo和Bar類,其中Foo會使用到Bar。如果你忘記編譯Bar而至直接跑javac Foo.java就會收到編譯器報cannot find symbol錯誤。簡單的解決就是直接javac Foo.java Bar.java 或者javac *.java。最好還是用java構建工具,如Ant,Maven,Gradle等等

如何修改該類錯誤

通常來講,從弄明白引起報錯原因下手,然後想想程式碼要做什麼,最後選擇正確的修改。

注意,並非所有修改都是合適的。比如這個

for(int i =1; i <10; i++){
for(j =1; j <10; j++){
...
}
}

假設編譯器報錯“cannot findsymbol for j”,有很多方式可以修改:

  • 把裡面的for 該為for (int j = 1;j < 10; j++ )       --很有可能對
  • 在裡面或者外面的for迴圈前新增j宣告,或者      --可能對
  • 在內迴圈把j改成I   --很有可能錯

為了正確修改報錯,關鍵是要理解你的程式碼想要做什麼

模糊的原因

以下是一些”cannot find symbol”報錯不大明朗的情況

1.        你沒檢查對原始碼:這種情況發生在新手身上,他們還沒弄清楚java工具鏈的工作流程或一個可重複構建的過程。比如使用IDE/Ant/Maven等等。這樣情況下

2.        IDE問題:早有使用者反饋IDE混淆或編譯器找不到實際存在的類等問題

a)        如果IDE的快取不能和檔案系統同步就會發生報錯。

b)        可能是IDE的Bug。比如@Joel Costigliola描述的Eclipse不能正確處理一個Maven “test”樹的問題,參考http://stackoverflow.com/a/37207223/139985

3.        重定義系統類:有過編譯器報錯指出substring在如下場景是未知的符號,結果發現是程式設計師建立了自己的String類而該類中沒有定義substring方法。(注意不要使用通用庫類名來命名自己的類)

String s = ...
String s1 = s.substring(1);

4.  同形字:如果你的原始碼使用utf-8,那麼有可能一些識別符號存在形相似而義不同,因為utf-8中包含同形字。為避免這種情況,你可以通過只使用ASCII或者Latin-1來編碼並且使用Java \uxxxx來轉義其他字元。