請解釋以下有關「找不到符號」、「無法解析符號」或「找不到符號」錯誤(Java 中)的資訊:
這個問題旨在對 Java 中的這些常見編譯錯誤進行全面的問答。
P粉2037924682023-10-10 12:40:19
如果您忘記了new
,您也會收到此錯誤:
String s = String();
對比
String s = new String();
因為沒有 new
關鍵字的呼叫將嘗試尋找不帶參數的名為 String
的(本地)方法 - 並且該方法簽名可能未定義。 p>
P粉9464374742023-10-10 11:07:06
不是真的。 「找不到符號」、「無法解析符號」和「找不到符號」都意味著同一件事。 (不同的Java編譯器是由不同的人寫的,不同的人用不同的措詞來表達同樣的事情。)
首先,這是一個編譯錯誤1。這意味著您的 Java 原始碼中存在問題,或您的編譯方式有問題。
您的 Java 原始碼包含以下內容:
class
、while
等。 true
、false
、42
、'X'
和「嗨媽媽!」
。
、=
、{
等。 Reader
、i
、toString
、processEquibalancedElephants
等。 「找不到符號」錯誤與識別符有關。編譯程式碼時,編譯器需要計算程式碼中每個標識符的含義。
“找不到符號”錯誤意味著編譯器無法執行此操作。您的程式碼似乎引用了編譯器無法理解的內容。
作為第一順序,只有一個原因。編譯器查看了應該定義標識符的所有位置,但找不到定義。這可能是由多種原因造成的。常見的有以下幾種:
對於一般識別碼:
StringBiulder
而不是 StringBuilder
。 Java 不能也不會嘗試彌補錯誤的拼字或輸入錯誤。 stringBuilder
而不是 StringBuilder
。所有 Java 標識符都區分大小寫。 mystring
和 my_string
是不同的。 (如果你堅持 Java 風格規則,你將在很大程度上避免這個錯誤...)對於應引用變數的識別碼:
對於應該是方法或欄位名稱的識別碼:
也許您正在嘗試引用未在父/祖先類別或介面中聲明的繼承方法或欄位。
也許您正在嘗試引用您正在使用的類型中不存在(即尚未聲明)的方法或欄位;例如"rope".push()
2 。
也許您正在嘗試將方法用作字段,反之亦然;例如"rope".length
或 someArray.length()
。
也許您錯誤地操作了數組而不是數組元素;例如
String strings[] = ... if (strings.charAt(3)) { ... } // maybe that should be 'strings[0].charAt(3)'
對於應該是類別名稱的識別碼:
也許您忘記導入該類別。
也許您使用了「星號」匯入,但該類別未在您匯入的任何套件中定義。
也許您忘記了一個new
,如下所示:
String s = String(); // should be 'new String()'
也許您正在嘗試匯入或以其他方式使用已在預設套件中聲明的類別;即沒有 package
語句的類別所在的位置。
提示:了解套件。您應該只對由一個類別組成的簡單應用程式使用預設套件...或至少由一個 Java 原始檔組成。
對於類型或實例似乎不具有您期望它具有的成員(例如方法或欄位)的情況:
java.awt.List
而不是 java.util.List
。 問題通常是上述問題的組合。例如,也許您「明星」導入了java.io.*
,然後嘗試使用Files
類別...它位於java.nio代码>而不是
java.io
。或者,也許您打算寫 File
...,它是 java.io
中的一個類別。
以下範例說明了不正確的變數作用域如何導致「找不到符號」錯誤:
Liststrings = ... for (int i = 0; i < strings.size(); i++) { if (strings.get(i).equalsIgnoreCase("fnord")) { break; } } if (i < strings.size()) { ... }
這將在 if
語句中為 i
提供「找不到符號」錯誤。儘管我們之前聲明了 i
,但該聲明僅for
語句及其主體範圍。 if
語句中對 i
的引用看不到 i
的宣告。它超出範圍。
(此處的適當修正可能是將 if
語句移至迴圈內部,或在迴圈開始之前宣告 i
。)
這是一個令人困惑的範例,其中拼字錯誤導致看似莫名其妙的「找不到符號」錯誤:
for (int i = 0; i < 100; i++); { System.out.println("i is " + i); }
這將在 println
呼叫中給您一個編譯錯誤,指出無法找到 i
。但是(我聽到你說)我確實宣布了!
問題在於 {
之前的分號 ( ;
)。 Java 語言語法將該上下文中的分號定義為空語句。然後,空語句將成為 for
迴圈的主體。所以該程式碼實際上意味著:
for (int i = 0; i < 100; i++); // The previous and following are separate statements!! { System.out.println("i is " + i); }
{ ... }
區塊不是for
循環的主體,因此先前在i
中的宣告code>for 語句超出區塊中的範圍。
這是另一個由拼字錯誤引起的「找不到符號」錯誤的範例。
int tmp = ... int res = tmp(a + b);
儘管有前面的聲明,tmp(...)
表達式中的 tmp
是錯誤的。編譯器將尋找名為 tmp
的方法,但找不到。先前宣告的 tmp
位於變數的命名空間中,而不是方法的命名空間。
在我遇到的範例中,程式設計師實際上遺漏了一個運算子。他本來想寫的是這樣的:
int res = tmp * (a + b);
如果從命令列編譯,編譯器可能找不到符號還有另一個原因。您可能只是忘記編譯或重新編譯其他一些類別。例如,如果您有類別 Foo
和 Bar
,其中 Foo
使用 Bar
。如果您從未編譯過 Bar
並且執行 javac Foo.java
,您很容易發現編譯器找不到符號 Bar
。簡單的答案是將 Foo
和 Bar
一起編譯;例如javac Foo.java Bar.java
或 javac *.java
。或者最好還是使用 Java 建置工具;例如Ant、Maven、Gradle 等。
還有一些其他更模糊的原因...我將在下面討論。
一般來說,您首先要找出導致編譯錯誤的原因。
然後你思考你的程式碼該說什麼。最後,您確定需要對原始程式碼進行哪些更正才能完成您想要的操作。
請注意,並非每個「更正」都是正確的。考慮一下:
for (int i = 1; i < 10; i++) { for (j = 1; j < 10; j++) { ... } }
假設編譯器對 j
提示「找不到符號」。我可以透過很多方法「修復」這個問題:
for
更改為 for (int j = 1; j < 10; j )< 10; j++)
- 可能是正確的。 for
循環或外部 for
循環之前新增一個 for j
宣告 -可能是正確的。 for
循環中將 j
更改為 i
- 可能是錯誤的! 重點是,您需要了解您的程式碼正在嘗試執行的操作,以便找到正確的修復方法。
在以下幾個案例中,「找不到符號」似乎令人費解…直到您仔細觀察。
不正確的依賴項:如果您使用的是管理建置路徑和專案依賴項的IDE 或建置工具,則您可能在依賴項方面犯了錯誤;例如遺漏了依賴項,或選擇了錯誤的版本。如果您使用建置工具(Ant、Maven、Gradle 等),請檢查專案的建置檔。如果您使用的是 IDE,請檢查專案的建置路徑配置。
找不到符號「var」:您可能正在嘗試使用較舊的版本來編譯使用局部變數類型推斷(即var
宣告)的原始程式碼編譯器或更舊的--source
等級。 var
是在 Java 10 中引入的。檢查您的 JDK 版本和建置文件,以及(如果在 IDE 中發生這種情況)IDE 設定。
您沒有編譯/重新編譯:有時,新的Java 程式設計師不了解Java 工具鏈的工作原理,或沒有實現可重複的「建置過程」;例如使用IDE、 Ant、Maven、Gradle 等。在這種情況下,程式設計師最終可能會窮追不捨地尋找一個虛幻的錯誤,而這些錯誤實際上是由於未正確重新編譯程式碼等造成的。
另一個範例是當您使用 (Java 9 ) java SomeClass.java
編譯和執行類別時。如果該類依賴您尚未編譯(或重新編譯)的另一個類,則您可能會收到涉及第二類的「無法解析符號」錯誤。其他原始檔不會自動編譯。 java
指令的新「編譯並執行」模式不適用於執行具有多個原始碼檔案的程式。
早期建置問題:早期建置可能會失敗,導致 JAR 檔案缺少類別。如果您使用建置工具,通常會注意到此類失敗。然而,如果您從其他人那裡獲取 JAR 文件,您就依賴它們的正確建置並注意到錯誤。如果您懷疑這一點,請使用 tar -tvf
列出可疑 JAR 檔案的內容。
IDE 問題:人們報告過這樣的情況:他們的 IDE 出現混亂,並且 IDE 中的編譯器找不到存在的類別…或相反的情況。
如果 IDE 配置了錯誤的 JDK 版本,可能會發生這種情況。
如果 IDE 的快取與檔案系統不同步,則可能會發生這種情況。有一些 IDE 特定的方法可以解決這個問題。
這可能是 IDE 錯誤。例如,@Joel Costigliola 描述了 Eclipse 無法正確處理 Maven「測試」樹的場景:查看此答案。 (顯然這個特定的錯誤很久以前就被修復了。)
Android 問題:當您為Android 程式設計時,如果遇到與R
相關的「找不到符號」錯誤,請注意 R
符號由context.xml
檔案定義。檢查您的 context.xml
檔案是否正確且位於正確的位置,以及是否已產生/編譯對應的 R
類別檔案。請注意,Java 符號區分大小寫,因此對應的 XML id 也區分大小寫。
Android 上的其他符號錯誤可能是由於前面提到的原因造成的;例如缺少或不正確的依賴項、不正確的套件名稱、特定API 版本中不存在的方法或欄位、拼字/輸入錯誤等等。
隱藏系統類別:我看過編譯器抱怨 substring
是未知符號的情況,如下所示
String s = ... String s1 = s.substring(1);
事實證明,程式設計師創建了他們自己的 String
版本,並且他的類別版本沒有定義 substring
方法。我見過人們使用 System
、Scanner
和其他類別來執行此操作。
教訓:不要定義與公共庫類別同名的自己的類別!
該問題也可以透過使用完全限定名稱來解決。例如,在上面的範例中,程式設計師可以寫:
java.lang.String s = ... java.lang.String s1 = s.substring(1);
同形文字:如果您對原始檔案使用UTF-8 編碼,則可能會出現看起來相同但實際上不同的識別碼因為它們包含同形文字。請參閱此頁面以了解更多資訊。
您可以透過限制自己使用 ASCII 或 Latin-1 作為原始檔案編碼,並使用 Java \uxxxx
轉義其他字元來避免這種情況。
1 - 如果您確實在執行階段異常或錯誤訊息中看到此情況,則表示您已將IDE 配置為執行帶有編譯錯誤的程式碼,或者您的應用程式正在生成並在運行時編譯程式碼。
2 - 土木工程的三個基本原理:水不往高處流、木板越面越堅固、你推不動繩子。