0. Czy jest jakaś różnica między tymi dwoma błędami?
Nie całkiem. „Nie można znaleźć symbolu” i „Nie można rozwiązać symbolu” oznaczają to samo. Niektóre kompilatory Java używają jednej frazy, a niektóre drugiej.
1. Co oznacza błąd „Nie można znaleźć symbolu”?
Po pierwsze, jest to błąd kompilacji 1 . Oznacza to, że albo występuje problem w kodzie źródłowym Java, albo jest problem ze sposobem jego kompilacji.
Twój kod źródłowy Java składa się z następujących rzeczy:
- Słowa kluczowe: jak
true
, false
, class
, while
, i tak dalej.
- Literówki: jak
42
i 'X'
i "Hi mum!"
.
- Operatorów i inne tokeny niealfanumeryczne: jak
+
, =
, {
i tak dalej.
- Identyfikatory: jak
Reader
, i
, toString
, processEquibalancedElephants
, i tak dalej.
- Komentarze i białe znaki.
Błąd „Nie można znaleźć symbolu” dotyczy identyfikatorów. Po skompilowaniu kodu kompilator musi ustalić, co oznacza każdy identyfikator w kodzie.
Błąd „Nie można znaleźć symbolu” oznacza, że kompilator nie może tego zrobić. Twój kod wydaje się odnosić do czegoś, czego kompilator nie rozumie.
2. Co może powodować błąd „Nie można znaleźć symbolu”?
Jako pierwsze zamówienie istnieje tylko jedna przyczyna. Kompilator szukał we wszystkich miejscach, w których należy zdefiniować identyfikator , i nie mógł znaleźć definicji. Może to być spowodowane wieloma rzeczami. Najczęstsze z nich są następujące:
- W przypadku identyfikatorów ogólnie:
- Być może wpisałeś to imię niepoprawnie; tj.
StringBiulder
zamiast StringBuilder
. Java nie może i nie będzie próbowała kompensować błędów pisowni lub pisania.
- Być może źle zrozumiałeś sprawę; tj.
stringBuilder
zamiast StringBuilder
. Wszystkie identyfikatory Java uwzględniają wielkość liter.
- Być może niewłaściwie użyłeś podkreślenia; tj.
mystring
i my_string
są różne. (Jeśli będziesz przestrzegać zasad stylu Java, będziesz w dużej mierze chroniony przed tym błędem ...)
- Być może próbujesz użyć czegoś, co zostało zadeklarowane „gdzie indziej”; tzn. w innym kontekście niż to, w którym niejawnie powiedziałeś kompilatorowi, aby szukał. (Inna klasa? Inny zakres? Inny pakiet? Inna baza kodu?)
- W przypadku identyfikatorów, które powinny odnosić się do zmiennych:
- Być może zapomniałeś zadeklarować zmienną.
- Być może deklaracja zmiennej jest poza zakresem w punkcie, w którym próbujesz jej użyć. (Patrz przykład poniżej)
W przypadku identyfikatorów, które powinny być nazwami metod lub pól:
- Być może próbujesz odwołać się do odziedziczonej metody lub pola, które nie zostało zadeklarowane w klasach lub interfejsach nadrzędnych / przodków.
- Być może próbujesz odwołać się do metody lub pola, które nie istnieją (tj. Nie zostały zadeklarowane) w typie, którego używasz; np .
"someString".push()
2 .
- Być może próbujesz użyć metody jako pola lub odwrotnie; np .
"someString".length
lub someArray.length()
.
Być może omyłkowo operujesz na tablicy, a nie na elemencie tablicy; na przykład
String strings[] = ...
if (strings.charAt(3)) { ... }
// maybe that should be 'strings[0].charAt(3)'
W przypadku identyfikatorów, które powinny być nazwami klas:
W przypadkach, gdy typ lub instancja nie wydaje się mieć członka, którego się spodziewałeś, że ma:
- Być może zadeklarowałeś zagnieżdżoną klasę lub parametr ogólny, który zaciemnia typ, którego zamierzałeś użyć.
- Być może przesłaniasz zmienną statyczną lub instancję.
- Być może zaimportowałeś zły typ; np. z powodu zakończenia IDE lub autokorekty.
- Być może używasz (kompilujesz przeciwko) niewłaściwej wersji interfejsu API.
- Być może zapomniałeś rzucić obiekt na odpowiednią podklasę.
Problem jest często kombinacją powyższych. Na przykład może „zaimportowałeś” gwiazdkę, java.io.*
a następnie próbowałeś użyć Files
klasy ... której java.nio
nie ma java.io
. A może chciałeś napisać File
... w której jest klasa java.io
.
Oto przykład, w jaki sposób niepoprawne określanie zakresu zmiennych może prowadzić do błędu „Nie można znaleźć symbolu”:
List<String> strings = ...
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnord")) {
break;
}
}
if (i < strings.size()) {
...
}
To spowoduje błąd „Nie można znaleźć symbolu” i
w if
instrukcji. Choć wcześniej oświadczył i
, że deklaracja jest tylko w zakresie do for
rachunku i jego ciała. Odwołanie i
w if
oświadczeniu nie widzi tej deklaracji i
. To jest poza zakresem .
(Odpowiednią poprawką może być tutaj przeniesienie if
instrukcji do pętli lub zadeklarowanie i
przed rozpoczęciem pętli).
Oto przykład, który powoduje zdziwienie, w którym literówka prowadzi do pozornie niewytłumaczalnego błędu „Nie można znaleźć symbolu”:
for (int i = 0; i < 100; i++); {
System.out.println("i is " + i);
}
Spowoduje to błąd kompilacji w println
wywołaniu, mówiąc, że i
nie można go znaleźć. Ale (słyszę, jak mówisz) ogłosiłem to!
Problemem jest sprytny średnik ( ;
) przed {
. Składnia języka Java definiuje w tym kontekście średnik jako pustą instrukcję . Pusta instrukcja staje się wówczas ciałem for
pętli. Ten kod w rzeczywistości oznacza to:
for (int i = 0; i < 100; i++);
// The previous and following are separate statements!!
{
System.out.println("i is " + i);
}
{ ... }
Blok nie jest ciało for
pętli, a więc poprzednia deklaracja i
w for
stwierdzenie jest poza zakresem w bloku.
Oto kolejny przykład błędu „Nie można znaleźć symbolu” spowodowanego literówką.
int tmp = ...
int res = tmp(a + b);
Pomimo wcześniejszego zgłoszenia, tmp
w tmp(...)
wyrażeniu jest błędna. Kompilator wyszuka metodę o nazwie tmp
i jej nie znajdzie. Poprzednio zadeklarowany tmp
jest w przestrzeni nazw dla zmiennych, a nie w przestrzeni nazw dla metod.
W przykładzie, z którym się spotkałem, programista faktycznie pominął operatora. Chciał on napisać tak:
int res = tmp * (a + b);
Jest inny powód, dla którego kompilator może nie znaleźć symbolu, jeśli kompilujesz z wiersza poleceń. Być może po prostu zapomniałeś skompilować lub przekompilować inną klasę. Na przykład, jeśli masz klasy Foo
i Bar
gdzie Foo
używa Bar
. Jeśli nigdy nie skompilowałeś Bar
i nie uruchomiłeś javac Foo.java
, możesz stwierdzić, że kompilator nie może znaleźć symbolu Bar
. Prostą odpowiedzią jest skompilowanie Foo
i Bar
połączenie; np . javac Foo.java Bar.java
lub javac *.java
. Lub lepiej nadal używać narzędzia do budowania Java; np. Ant, Maven, Gradle i tak dalej.
Są też inne niejasne przyczyny ... z którymi zajmę się poniżej.
3. Jak naprawić te błędy?
Ogólnie rzecz biorąc, zaczynasz od ustalenia, co spowodowało błąd kompilacji.
- Spójrz na wiersz w pliku wskazany w komunikacie o błędzie kompilacji.
- Określ symbol, o którym mówi komunikat o błędzie.
- Dowiedz się, dlaczego kompilator mówi, że nie może znaleźć symbolu; patrz wyżej!
Następnie pomyśl o tym, co powinien powiedzieć Twój kod. Następnie w końcu zastanawiasz się, jaką korektę musisz wprowadzić w kodzie źródłowym, aby zrobić to, co chcesz.
Pamiętaj, że nie każda „korekta” jest poprawna. Rozważ to:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
Załóżmy, że kompilator mówi „Nie można znaleźć symbolu” dla j
. Istnieje wiele sposobów na „naprawienie” tego:
- Mógłbym zmienić wewnętrzny
for
na for (int j = 1; j < 10; j++)
- prawdopodobnie poprawny.
- Mógłbym dodać deklarację
j
przed wewnętrzną for
pętlą lub zewnętrzną for
- być może poprawną.
- Mógłbym zmienić
j
się i
w wewnętrzną for
pętlę - prawdopodobnie źle!
- i tak dalej.
Chodzi o to, że musisz zrozumieć, co twój kod próbuje zrobić, aby znaleźć właściwą poprawkę.
4. Niewyraźne przyczyny
Oto kilka przypadków, w których „Nie można znaleźć symbolu” wydaje się niewytłumaczalny ... dopóki nie przyjrzysz się bliżej.
Niepoprawne zależności : jeśli używasz IDE lub narzędzia do budowania, które zarządza ścieżką kompilacji i zależnościami projektu, być może pomyliłeś się z zależnościami; np. pominął zależność lub wybrał niewłaściwą wersję. Jeśli używasz narzędzia kompilacji (Ant, Maven, Gradle itp.), Sprawdź plik kompilacji projektu. Jeśli używasz IDE, sprawdź konfigurację ścieżki kompilacji projektu.
Nie rekompilujesz : Czasami zdarza się, że nowi programiści Java nie rozumieją, jak działa łańcuch narzędzi Java lub nie wdrożyli powtarzalnego „procesu budowania”; np. używając IDE, Ant, Maven, Gradle i tak dalej. W takiej sytuacji programista może gonić za ogonem, szukając iluzorycznego błędu, który jest faktycznie spowodowany niewłaściwą rekompilacją kodu i tym podobne ...
Wcześniejszy problem z kompilacją : Możliwe, że wcześniejsza kompilacja zakończyła się niepowodzeniem w sposób, który dał plik JAR z brakującymi klasami. Taka awaria byłaby zwykle zauważalna, gdybyś używał narzędzia do kompilacji. Jednak jeśli otrzymujesz pliki JAR od kogoś innego, jesteś zależny od ich poprawnego budowania i zauważania błędów. Jeśli podejrzewasz to, użyj, tar -tvf
aby wyświetlić listę podejrzanego pliku JAR.
Problemy z IDE : ludzie zgłaszali przypadki, w których ich IDE jest mylone, a kompilator w IDE nie może znaleźć klasy, która istnieje ... lub odwrotnie.
Może się to zdarzyć, jeśli IDE zostało skonfigurowane z niewłaściwą wersją JDK.
Może się to zdarzyć, jeśli pamięci podręczne IDE nie zsynchronizują się z systemem plików. Istnieją specyficzne sposoby rozwiązania tego problemu przez IDE.
Może to być błąd IDE. Na przykład @Joel Costigliola opisuje scenariusz, w którym Eclipse nie obsługuje poprawnie drzewa „testowego” Mavena: zobacz tę odpowiedź .
Problemy z Androidem : Gdy programujesz dla Androida i występują błędy „Nie można znaleźć symbolu” R
, pamiętaj, że R
symbole są zdefiniowane w context.xml
pliku. Sprawdź, czy context.xml
plik jest poprawny i we właściwym miejscu oraz czy odpowiedni R
plik klasy został wygenerowany / skompilowany. Zauważ, że w symbolach Java rozróżniana jest wielkość liter, więc w odpowiednich identyfikatorach XML rozróżniana jest również wielkość liter.
Inne błędy symboli w Androidzie prawdopodobnie wynikają z wcześniej wymienionych przyczyn; np. brakujące lub niepoprawne zależności, niepoprawne nazwy pakietów, metody lub pola, które nie istnieją w określonej wersji interfejsu API, błędy w pisowni / pisaniu itd.
Przedefiniowanie klas systemowych : Widziałem przypadki, w których kompilator narzeka, że substring
jest to nieznany symbol w czymś takim, jak poniżej
String s = ...
String s1 = s.substring(1);
Okazało się, że programista stworzył własną wersję String
i że jego wersja klasy nie zdefiniowała substring
metod.
Lekcja: Nie definiuj własnych klas o takich samych nazwach jak wspólne klasy biblioteczne!
Homoglyphs: Jeśli używasz kodowania UTF-8 dla swoich plików źródłowych, możliwe jest, że identyfikatory wyglądają tak samo, ale w rzeczywistości są różne, ponieważ zawierają homoglyphy. Zobacz tę stronę, aby uzyskać więcej informacji.
Można tego uniknąć, ograniczając się do ASCII lub Latin-1 jako kodowania pliku źródłowego i używając \uxxxx
znaków zmiany znaczenia Java dla innych znaków.
1 - Jeśli przypadkiem, to nie patrz w ten wyjątek czasu wykonywania lub komunikat o błędzie, a następnie albo skonfigurowaniu IDE do wykonywania kodu z błędami kompilacji, czy aplikacja jest generowanie kodu i kompilacji .. przy starcie.
2 - Trzy podstawowe zasady inżynierii lądowej: woda nie płynie pod górę, deska jest silniejsza na boku i nie można naciskać na sznurek .
println
wSystem.out.println
razie umieszczone na poziomie klasy ramach standardowego kompilatora dałoby nam<identifier> expected
( demo ), ale w IntelliJ ujrzymyCannot resolve symbol 'println'
( demo ).Ten błąd również pojawi się, jeśli zapomnisz
new
:przeciw
ponieważ wywołanie bez
new
słowa kluczowego będzie szukało metody (lokalnej) wywołanejString
bez argumentów - a sygnatura tej metody prawdopodobnie nie jest zdefiniowana.źródło
Jeszcze jeden przykład „Zmienna jest poza zakresem”
Jak już kilka razy widziałem tego rodzaju pytania, może jeszcze jeden przykład tego, co jest nielegalne, nawet jeśli mogłoby się wydawać porządku.
Rozważ ten kod:
To jest nieprawidłowy kod. Ponieważ żadna z wymienionych zmiennych nie
message
jest widoczna poza ich odpowiednim zakresem -{}
w tym przypadku byłyby to otaczające nawiasy .Możesz powiedzieć: „Ale zmienna o nazwie wiadomość jest definiowana w obie strony - więc wiadomość jest definiowana po
if
”.Ale mylisz się.
Java nie ma
free()
lubdelete
operatorów , więc musi polegać na śledzeniu zakresu zmiennych, aby dowiedzieć się, kiedy zmienne nie są już używane (wraz z odniesieniami do tych zmiennych przyczyny).Jest to szczególnie złe, jeśli uważasz, że zrobiłeś coś dobrego. Widziałem tego rodzaju błąd po „zoptymalizowaniu” kodu w następujący sposób:
„Och, jest zduplikowany kod, wyciągnijmy tę wspólną linię” -> i gotowe.
Najczęstszym sposobem radzenia sobie z tego rodzaju problemami z zakresem jest wstępne przypisanie wartości else do nazw zmiennych w zakresie zewnętrznym, a następnie ponowne przypisanie, jeśli:
źródło
final
deklaracji zmiennej.Jednym ze sposobów uzyskania tego błędu w środowisku Eclipse:
A
wsrc/test/java
.B
wsrc/main/java
tej klasie zastosowańA
.Wynik: Eclipse skompiluje kod, ale maven wyświetli komunikat „Cannot find symbol”.
Podstawowa przyczyna: Eclipse używa połączonej ścieżki kompilacji dla drzewa głównego i drzewa testowego. Niestety nie obsługuje używania różnych ścieżek kompilacji dla różnych części projektu Eclipse, czego wymaga Maven.
Rozwiązanie :
źródło
„Nie można znaleźć” oznacza, że kompilator, który nie może znaleźć odpowiedniej zmiennej, metody, klasy itp. ... jeśli uzyskasz ten błąd masażu, przede wszystkim chcesz znaleźć wiersz kodu, w którym uzyskasz masę błędów .. A potem w stanie znaleźć zmienną, metodę lub klasę, które nie zostały zdefiniowane przed użyciem. Po potwierdzeniu zainicjuj zmienną, metodę lub klasę, której można użyć w późniejszym czasie ... Rozważ następujący przykład.
Stworzę klasę demo i wydrukuję imię ...
Teraz spójrz na wynik ..
Ten błąd mówi: „nazwa zmiennej nie może znaleźć”. Zdefiniowanie i zainicjowanie wartości zmiennej „nazwa” może zostać zniesione przez ten błąd. Właściwie w ten sposób,
Teraz spójrz na nowe wyjście ...
Ok Pomyślnie rozwiązałem ten błąd .. Jednocześnie, jeśli możesz dostać coś „nie można znaleźć metody” lub „nie można znaleźć klasy”, najpierw zdefiniuj klasę lub metodę, a po użyciu to ...
źródło
Jeśli ten błąd pojawia się w kompilacji gdzieś indziej, podczas gdy IDE twierdzi, że wszystko jest w porządku, sprawdź, czy używasz tych samych wersji Java w obu miejscach.
Na przykład Java 7 i Java 8 mają różne interfejsy API, więc wywołanie nieistniejącego interfejsu API w starszej wersji Java spowoduje ten błąd.
źródło
Ja też otrzymywałem ten błąd. (dla którego przejrzałem Google i zostałem przekierowany na tę stronę)
Problem: Wywołałem metodę statyczną zdefiniowaną w klasie projektu A z klasy zdefiniowanej w innym projekcie B. Otrzymałem następujący błąd:
Rozwiązanie: Rozwiązałem ten problem, najpierw budując projekt, w którym metoda jest zdefiniowana, a następnie projekt, z którego metoda została wywołana.
źródło
Jeśli ścieżka kompilacji Java Eclipse jest odwzorowana na 7, 8 i we właściwościach projektu pom.xml Maven nazwa java.version jest wymieniona na wyższą wersję Java (9,10,11 itd.) Niż 7,8, musisz zaktualizować w pom. plik XML.
W Eclipse, jeśli Java jest mapowane na Javę w wersji 11, a w pom.xml jest mapowane na Java w wersji 8. Zaktualizuj obsługę Eclipse do Java 11, wykonując poniższe kroki w pomocy Eclipse IDE -> Zainstaluj nowe oprogramowanie ->
Wklej następujący link http://download.eclipse.org/eclipse/updates/4.9-P-builds at Work With
lub
Dodaj (otworzy się okno podręczne) ->
Name:
Obsługa Java 11Location:
http://download.eclipse.org/eclipse/updates/4.9-P-buildsnastępnie zaktualizuj wersję Java we właściwościach Maven pliku pom.xml , jak poniżej
Na koniec kliknij prawym przyciskiem myszy projekt Debuguj jako -> Oczyść Maven, kroki kompilacji Maven
źródło
ROZWIĄZANY
Wybierz Build -> Rebuild Project rozwiąże go
źródło
Mogą istnieć różne scenariusze, jak wspomniano powyżej. Kilka rzeczy, które pomogły mi rozwiązać ten problem.
Jeśli używasz IntelliJ
File -> 'Invalidate Caches/Restart'
LUB
Klasa, do której się odwoływano, była w innym projekcie i ta zależność nie została dodana do pliku kompilacji Gradle mojego projektu. Dodałem więc zależność za pomocą
compile project(':anotherProject')
i zadziałało. HTH!
źródło
skompilowałeś swój kod za pomocą kompilacji maven, a następnie użyłeś testu maven, aby go uruchomić. Teraz, jeśli zmieniłeś coś w kodzie, a następnie bez kompilacji go uruchomisz, pojawi się ten błąd.
Rozwiązanie: Ponownie skompiluj go, a następnie uruchom test. Dla mnie to działało w ten sposób.
źródło
W moim przypadku - musiałem wykonać poniższe operacje:
context.xml
plik zsrc/java/package
doresource
katalogu (IntelliJ IDE)target
katalog.źródło
Aby uzyskać wskazówki, przyjrzyj się bliżej nazwie klasy, która generuje błąd i numer linii, przykład: Błąd kompilacji [BŁĄD] \ application \ xxxxx.java: [44,30] błąd: nie można znaleźć symbolu
Inną przyczyną jest nieobsługiwana metoda wersji java, powiedzmy jdk7 vs 8. Sprawdź% JAVA_HOME%
źródło