Co oznacza błąd „Nie można znaleźć symbolu” lub „Nie można rozwiązać symbolu”?

Sep 07 2014

Wyjaśnij następujące kwestie dotyczące błędów „Nie można znaleźć symbolu”, „Nie można rozwiązać symbolu” lub „Nie znaleziono symbolu”:

  • Co mieli na myśli?
  • Jakie rzeczy mogą je powodować?
  • Jak programista je naprawia?

To pytanie ma na celu zapoczątkowanie obszernego pytania i odpowiedzi na temat tych typowych błędów kompilacji w Javie.

Odpowiedzi

441 StephenC Sep 07 2014 at 08:12

0. Czy jest jakaś różnica między tymi dwoma błędami?

Nie całkiem. „Nie można znaleźć symbolu”, „Nie można znaleźć symbolu” i „Nie znaleziono symbolu” - wszystkie oznaczają to samo. Różne kompilatory języka Java używają różnych frazeologii.

1. Co oznacza błąd „Nie można znaleźć symbolu”?

Po pierwsze, jest to błąd kompilacji 1 . Oznacza to, że albo jest problem w kodzie źródłowym Java, albo jest problem w sposobie 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.
  • Literały: jak 42i '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 spacje.

Błąd „Nie można znaleźć symbolu” dotyczy identyfikatorów. Kiedy Twój kod jest kompilowany, kompilator musi dowiedzieć się, co oznacza każdy identyfikator w Twoim 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 spowodować błąd „Nie można znaleźć symbolu”?

Po pierwsze, jest tylko jedna przyczyna. Kompilator przeszukał wszystkie miejsca, w których powinien zostać zdefiniowany identyfikator , i nie mógł znaleźć definicji. Może to być spowodowane wieloma czynnikami. Typowe są następujące:

  • Ogólnie dla identyfikatorów:

    • Być może niepoprawnie przeliterowałeś nazwę; tj. StringBiulderzamiast StringBuilder. Java nie może i nie będzie próbować rekompensować błędów ortograficznych lub literówek.
    • Być może źle zrozumiałeś sprawę; tj. stringBuilderzamiast StringBuilder. We wszystkich identyfikatorach Java jest rozróżniana wielkość liter.
    • Być może niewłaściwie użyłeś podkreśleń; ie mystringi my_stringsą 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”; tj. w innym kontekście niż ten, w którym niejawnie nakazałeś kompilatorowi szukać. (Inna klasa? Inny zakres? Inny pakiet? Inna baza kodu?)
  • Identyfikatory, które powinny odnosić się do zmiennych:

    • Być może zapomniałeś zadeklarować zmienną.
    • Być może deklaracja zmiennej jest poza zakresem w momencie, gdy próbowałeś jej użyć. (Zobacz 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 dziedziczonej metody lub pola, które nie zostało zadeklarowane w klasach lub interfejsach rodzica / przodka.

    • Być może próbujesz odwołać się do metody lub pola, które nie istnieje (tj. Nie zostało 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".lengthlub someArray.length().

    • Być może omyłkowo operujesz na tablicy zamiast 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:

    • Być może zapomniałeś zaimportować klasy.

    • Być może użyłeś importu „star”, ale klasa nie jest zdefiniowana w żadnym z importowanych pakietów.

    • Być może zapomniałeś newjak w:

          String s = String();  // should be 'new String()'
      
  • W przypadkach, gdy typ lub instancja nie wydaje się mieć członka, którego się spodziewałeś:

    • Być może ogłoszony zagnieżdżone klasy lub ogólny parametr cienie typ nosisz się z zamiarem użycia.
    • Być może śledzisz zmienną statyczną lub instancji.
    • Być może zaimportowałeś niewłaściwy typ; np. ze względu na zakończenie IDE lub autokorektę.
    • Być może używasz (kompilujesz przeciwko) niewłaściwej wersji API.
    • Być może zapomniałeś rzucić swój obiekt na odpowiednią podklasę.

Problem jest często połączeniem powyższych. Na przykład, być może zaimportowałeś "gwiazdkę", java.io.*a następnie próbowałeś użyć Filesklasy ... której java.nionie ma java.io. A może chodziło o pisanie File... który jest klasą w java.io.


Oto przykład tego, jak 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()) {
    ...
}

Spowoduje to wyświetlenie błędu „Nie można znaleźć symbolu” iw ifinstrukcji. Choć wcześniej oświadczył i, że deklaracja jest tylko w zakresie do forrachunku i jego ciała. Odniesienie do iw ifoświadczeniu nie może zobaczyć tego oświadczenia i. To jest poza zakresem .

(Odpowiednią poprawką może być tutaj przeniesienie ifinstrukcji wewnątrz pętli lub zadeklarowanie iprzed rozpoczęciem pętli).


Oto przykład, który powoduje zdziwienie, gdy 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 wyświetlenie błędu kompilacji w printlnwywołaniu, informującego, że inie można znaleźć. Ale (słyszę, jak mówisz) ogłosiłem to!

Problem polega na tym, że podstępny średnik ( ;) przed {. Składnia języka Java definiuje średnik w tym kontekście jako instrukcję pustą . Pusta instrukcja staje się wówczas treścią forpętli. Więc ten kod faktycznie 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 forpętli, a więc poprzednia deklaracja iw forstwierdzenie jest poza zakresem w bloku.


Oto kolejny przykład błędu „Nie można znaleźć symbolu”, który jest spowodowany literówką.

int tmp = ...
int res = tmp(a + b);

Pomimo poprzedniej deklaracji wyrażenie tmpw tmp(...)wyrażeniu jest błędne. Kompilator będzie szukał wywoływanej metody tmp, ale jej nie znajdzie. Poprzednio zadeklarowana tmpznajduje się w przestrzeni nazw dla zmiennych, a nie w przestrzeni nazw dla metod.

W przykładzie, z którym się spotkałem, programista właściwie pominął operatora. Miał zamiar napisać tak:

int res = tmp * (a + b);

Jest jeszcze jeden powód, dla którego kompilator może nie znaleźć symbolu, jeśli kompilujesz z wiersza poleceń. Mogłeś po prostu zapomnieć o skompilowaniu lub ponownej kompilacji innej klasy. Na przykład, jeśli masz klasy Fooi Bargdzie Fooużywa Bar. Jeśli nigdy nie kompilowałeś Bari uruchamiasz javac Foo.java, możesz stwierdzić, że kompilator nie może znaleźć symbolu Bar. Prosta odpowiedź to kompilacja Fooi Barrazem; np . javac Foo.java Bar.javalub javac *.java. Lub lepiej nadal używać narzędzia do budowania języka Java; np. Ant, Maven, Gradle i tak dalej.

Są też inne, bardziej niejasne przyczyny ... 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.
  • Zidentyfikuj symbol, o którym mowa w komunikacie o błędzie.
  • Dowiedz się, dlaczego kompilator mówi, że nie może znaleźć symbolu; patrz wyżej!

Następnie myślisz o tym, co ma mówić Twój kod. Następnie w końcu ustalasz, jaką korektę musisz wprowadzić w swoim kodzie źródłowym, aby zrobić to, co chcesz.

Zauważ, ż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. Jest wiele sposobów, w jakie mogę to „naprawić”:

  • Mógłbym zmienić wewnętrzne forna for (int j = 1; j < 10; j++)- prawdopodobnie poprawne.
  • Mógłbym dodać deklarację j przedfor pętlą wewnętrzną lub forpętlą zewnętrzną - prawdopodobnie poprawna.
  • Mogę zmienić jsię iw wewnętrznej forpętli - prawdopodobnie źle!
  • i tak dalej.

Chodzi o to, że musisz zrozumieć, co próbuje zrobić twój kod, aby znaleźć właściwą poprawkę.

4. Niejasne przyczyny

Oto kilka przypadków, w których „Nie można znaleźć symbolu” wydaje się niewytłumaczalne ... dopóki nie przyjrzysz się bliżej.

  1. Nieprawidłowe zależności : jeśli używasz IDE lub narzędzia do budowania, które zarządza ścieżką budowania i zależnościami projektu, być może popełniono błąd z zależnościami; np. pominięto zależność lub wybrano złą wersję. Jeśli używasz narzędzia do kompilacji (Ant, Maven, Gradle itp.), Sprawdź plik kompilacji projektu. Jeśli używasz IDE, sprawdź konfigurację ścieżki kompilacji projektu.

  2. Nie rekompilujesz : czasami zdarza się, że nowi programiści Java nie rozumieją, jak działa łańcuch narzędzi Java, lub nie zaimplementowali powtarzalnego „procesu budowania”; np. używając IDE, Ant, Maven, Gradle i tak dalej. W takiej sytuacji programista może skończyć goniąc za swoim ogonem, szukając iluzorycznego błędu, który w rzeczywistości jest spowodowany niepoprawną rekompilacją kodu i tym podobne ...

  3. Problem z wcześniejszą kompilacją : Możliwe, że wcześniejsza kompilacja nie powiodła się w sposób, który spowodował utworzenie pliku JAR z brakującymi klasami. Taka awaria byłaby zwykle zauważana, gdybyś używał narzędzia do kompilacji. Jeśli jednak otrzymujesz pliki JAR od kogoś innego, jesteś zależny od tego , czy poprawnie budują i zauważają błędy. Jeśli podejrzewasz to, użyj, tar -tvfaby wyświetlić zawartość podejrzanego pliku JAR.

  4. Problemy z IDE : ludzie zgłaszali przypadki, w których ich IDE jest zdezorientowane, a kompilator w IDE nie może znaleźć klasy, która istnieje ... lub sytuacja odwrotna.

  • 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 stracą synchronizację z systemem plików. Istnieją specyficzne dla IDE sposoby, aby to naprawić.

  • 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ź .

  1. Problemy z Androidem : Kiedy programujesz dla Androida i masz błąd „Nie można znaleźć symbolu” R, pamiętaj, że Rsymbole są zdefiniowane w context.xmlpliku. Sprawdź, czy context.xmlplik jest poprawny i znajduje się we właściwym miejscu oraz czy odpowiedni Rplik klasy został wygenerowany / skompilowany. Zauważ, że w symbolach Java jest rozróżniana wielkość liter, więc odpowiednie identyfikatory XML również uwzględniają wielkość liter.

    Inne błędy symboli w systemie Android prawdopodobnie wynikają z wcześniej wymienionych powodów; np. brakujące lub niepoprawne zależności, nieprawidłowe nazwy pakietów, metody lub pola, których nie ma w określonej wersji API, błędy ortograficzne / pisarskie i tak dalej.

  2. Przedefiniowanie klas systemowych : widziałem przypadki, w których kompilator narzeka, że substringjest to nieznany symbol w czymś podobnym do następującego

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

    Okazało się, że programista stworzył własną wersję Stringi że jego wersja klasy nie definiuje substringmetod.

    Lekcja: Nie definiuj własnych klas o takich samych nazwach, jak zwykłe klasy biblioteczne!

  3. Homoglify: jeśli używasz kodowania UTF-8 dla plików źródłowych, możesz mieć identyfikatory, które wyglądają tak samo, ale w rzeczywistości są różne, ponieważ zawierają homoglify. Więcej informacji znajdziesz na tej stronie .

    Możesz tego uniknąć, ograniczając się do ASCII lub Latin-1 jako kodowania pliku źródłowego i używając znaków specjalnych Java \uxxxxdla 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 mocniejsza na boku i nie można pchać sznurka .

26 thinkterry Apr 17 2015 at 15:50

Otrzymasz również ten błąd, jeśli zapomnisz new:

String s = String();

przeciw

String s = new String();

ponieważ wywołanie bez newsłowa kluczowego będzie próbowało szukać (lokalnej) metody wywoływanej Stringbez argumentów - a ta sygnatura metody prawdopodobnie nie jest zdefiniowana.

14 Jan Dec 06 2015 at 16:19

Jeszcze jeden przykład „Zmienna poza zakresem”

Jak już kilka razy widziałem tego rodzaju pytania, może jeszcze jeden przykład tego, co jest nielegalne, nawet jeśli może wydawać się w porządku.

Rozważ ten kod:

if(somethingIsTrue()) {
  String message = "Everything is fine";
} else {
  String message = "We have an error";
}
System.out.println(message);

To nieprawidłowy kod. Ponieważ żadna z wymienionych zmiennych nie messagejest widoczna poza swoim zakresem - {}w tym przypadku byłyby to otaczające nawiasy .

Możesz powiedzieć: „Ale zmienna o nazwie message jest zdefiniowana tak czy inaczej - więc wiadomość jest definiowana po znaku if”.

Ale mylisz się.

Java nie ma operatorów free()lub delete, więc musi polegać na zakresie zmiennych śledzenia, aby dowiedzieć się, kiedy zmienne nie są już używane (wraz z odwołaniami do tych zmiennych przyczyny).

Jest to szczególnie złe, jeśli myślisz, że zrobiłeś coś dobrego. Widziałem tego rodzaju błąd po „optymalizacji” kodu w następujący sposób:

if(somethingIsTrue()) {
  String message = "Everything is fine";
  System.out.println(message);
} else {
  String message = "We have an error";
  System.out.println(message);
}

„Och, jest zduplikowany kod, wyciągnijmy tę wspólną linię” -> i gotowe.

Najczęstszym sposobem radzenia sobie z tego rodzaju problemami z zakresem byłoby wstępne przypisanie wartości-else do nazw zmiennych w zakresie zewnętrznym, a następnie ponowne przypisanie, jeśli:

String message = "We have an error";
if(somethingIsTrue()) {
  message = "Everything is fine";
} 
System.out.println(message);
10 JoelCostigliola May 13 2016 at 17:09

Jeden ze sposobów uzyskania tego błędu w Eclipse:

  1. Zdefiniuj klasę Aw src/test/java.
  2. Zdefiniowanie innej klasy Bw src/main/javatej klasie zastosowań A.

Wynik: Eclipse skompiluje kod, ale maven poda „Nie można znaleźć symbolu”.

Podstawowa przyczyna: Eclipse używa połączonej ścieżki budowania 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 :

  1. Nie definiuj w ten sposób swoich zależności; tj. nie popełniaj tego błędu.
  2. Regularnie buduj bazę kodu za pomocą Mavena, aby wcześnie wykryć ten błąd. Jednym ze sposobów jest użycie serwera CI.
5 GT_hash Jun 30 2018 at 18:09

„Nie można znaleźć” oznacza, że ​​kompilator, który nie może znaleźć odpowiedniej zmiennej, metody, klasy itp.… Jeśli otrzymałeś komunikat o błędzie, najpierw chcesz znaleźć wiersz kodu, w którym zostanie wyświetlony komunikat o błędzie. w stanie znaleźć, która zmienna, metoda lub klasa nie zostały zdefiniowane przed jej użyciem. Po potwierdzeniu zainicjuj tę zmienną, metodę lub klasę, aby później wymagać ... Rozważ następujący przykład.

Utworzę klasę demonstracyjną i wydrukuję nazwę ...

class demo{ 
      public static void main(String a[]){
             System.out.print(name);
      }
}

Teraz spójrz na wynik ...

Ten błąd mówi: „Nie można znaleźć nazwy zmiennej” .. Definiowanie i inicjowanie wartości dla zmiennej „nazwa” może zostać zniesione. Tak naprawdę,

class demo{ 
      public static void main(String a[]){

             String name="smith";

             System.out.print(name);
      }
}

Teraz spójrz na nowe wyjście ...

Ok Pomyślnie rozwiązałem ten błąd ... Jednocześnie, jeśli udało Ci się uzyskać coś „nie można znaleźć metody” lub „nie można znaleźć klasy”, najpierw zdefiniuj klasę lub metodę, a następnie użyj jej.

3 JonathanLin Mar 08 2016 at 12:58

Jeśli otrzymujesz ten błąd podczas kompilacji w innym miejscu, a twoje IDE mówi, ż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 spowodowałoby ten błąd.

3 Ajay Oct 10 2019 at 19:07

ROZWIĄZANY

Korzystanie z IntelliJ

Wybierz Build -> Rebuild Project rozwiąże to

2 DivyaJose Sep 28 2016 at 21:59

Ja też otrzymywałem ten błąd. (dla którego wyszukałem w 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:

error: cannot find symbol

Rozwiązanie: rozwiązałem ten problem, najpierw budując projekt, w którym zdefiniowano metodę, a następnie projekt, z którego metoda została wywołana.

2 UdayKiranPulipati Jan 24 2019 at 18:18

Jeśli ścieżka budowania środowiska Java zaćmienia jest odwzorowana na 7, 8, a we właściwościach Mavena projektu pom.xml o nazwie java.version wspomniana jest wyższa wersja Java (9,10,11 itd.) Niż 7,8, należy zaktualizować w pom. xml plik.

W Eclipse, jeśli Java jest odwzorowana na Javę w wersji 11, aw pom.xml, na wersję Java 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ę wyskakujące okienko) ->

Name:Obsługa języka Java 11 Location: http://download.eclipse.org/eclipse/updates/4.9-P-builds

następnie zaktualizuj wersję Java we właściwościach Maven pliku pom.xml , jak poniżej

<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>

Na koniec kliknij prawym przyciskiem myszy projekt Debuguj jako -> Maven wyczyść, kroki kompilacji Maven

1 avp Aug 18 2018 at 08:45

Mogą istnieć różne scenariusze, jak wspomniano powyżej. Kilka rzeczy, które pomogły mi rozwiązać ten problem.

  1. Jeśli używasz IntelliJ

    File -> 'Invalidate Caches/Restart'

LUB

  1. Klasa, do której się odwołujemy, znajdowała się w innym projekcie i ta zależność nie została dodana do pliku kompilacji Gradle mojego projektu. Więc dodałem zależność za pomocą

    compile project(':anotherProject')

i zadziałało. HTH!

1 ANILKUMAR Aug 07 2019 at 11:59

skompilowałeś swój kod za pomocą kompilacji maven, a następnie użyłeś maven test do uruchomienia, działał dobrze. Teraz, jeśli zmieniłeś coś w swoim kodzie, a następnie bez kompilacji go uruchamiasz, otrzymasz ten błąd.

Rozwiązanie: ponownie skompiluj go, a następnie uruchom test. U mnie to zadziałało w ten sposób.

1 VIPINKUMAR Sep 08 2019 at 14:50

W moim przypadku - musiałem wykonać poniższe operacje:

  1. Przenieś context.xmlplik z src/java/packagedo resourcekatalogu (IntelliJ IDE)
  2. Czysty targetkatalog.
Striker Sep 06 2017 at 19:47

Aby uzyskać wskazówki, przyjrzyj się bliżej nazwie klasy, która zgłasza błąd, i numerowi linii, na przykład: Błąd kompilacji [BŁĄD] \ applications \ xxxxx.java: [44,30] błąd: nie można znaleźć symbolu

Inną przyczyną jest nieobsługiwana metoda dla wersji Java, na przykład jdk7 vs 8. Sprawdź% JAVA_HOME%

sakra Jul 20 2020 at 19:31

Wystąpił błąd w projekcie Java, który jest skonfigurowany jako kompilacja wielu projektów Gradle. Okazało się, że w jednym z podprojektów brakowało wtyczki Gradle Java Library . Dzięki temu pliki klas podprojektu nie były widoczne dla innych projektów w kompilacji.

Po dodaniu wtyczki biblioteki Java do podprojektu build.gradlew następujący sposób błąd zniknął:

plugins {
    ...
    id 'java-library'
}
FelipeFranco Nov 20 2020 at 04:03

Rozwiązałem ten błąd w ten sposób ... Szaleństwo Androida. Miałem nazwę pakietu jako Adapter, a ja przerobiłem nazwę na adapter z „a” zamiast „A” i rozwiązałem błąd.