Co oznacza błąd kompilacji "nie można znaleźć symbolu"?

Proszę wyjaśnić, co następuje na temat błędu "nie można znaleźć symbolu":

  • co oznacza ten błąd?
  • Jakie rzeczy mogą spowodować ten błąd?
  • Jak programista naprawia ten błąd?

to pytanie ma być kompleksowym pytaniem o błędy kompilacji "nie można znaleźć symbolu" w Javie.

Author: Taryn, 2014-09-07

10 answers

1. Co oznacza błąd "nie można znaleźć symbolu"?

Po pierwsze, jest to błąd kompilacji 1. Oznacza to, że albo{[85] } jest problem w kodzie źródłowym Javy, albo jest problem w sposobie kompilacji.

Twój kod źródłowy Javy składa się z następujących rzeczy:]}

  • słowa kluczowe: jak true, false, class, while, i tak dalej.
  • literały: jak 42 i 'X' i "Hi mum!".
  • operatory i inne niealfanumeryczne tokeny: 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. Gdy kod jest kompilowany, 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ę, że odnosi się do czegoś, czego kompilator nie rozumie.

2. Co może spowodować błąd "nie można znaleźć symbolu"?

Jako pierwszy porządek, jest tylko jedna przyczyna. Kompilator szukał we wszystkich miejscach, w których powinien być zdefiniowany identyfikator i nie mógł znaleźć definicji. Może to być spowodowane przez wiele rzeczy. Najczęściej spotykane są następujące:

  • ogólnie o identyfikatorach:
    • być może napisałeś imię nieprawidłowo; tzn. StringBiulder zamiast StringBuilder. Oprogramowanie Java nie może i nie będzie próbowało zrekompensować błędów ortograficznych lub typowych.
    • być może źle zrozumiałeś sprawę, tzn. stringBuilder zamiast StringBuilder. Wszystkie identyfikatory Java uwzględniają wielkość liter.
    • być może niewłaściwie użyłeś podkreślników, tzn. mystring i my_string są różne. (Jeśli zachowasz zasady stylu Java, będziesz w dużej mierze chroniony przed tym błędem ...)
    • być może próbujesz użyć czegoś, co było zadeklarowane "gdzie indziej"; tzn. w innym kontekście niż tam, gdzie domyślnie poleciłeś kompilatorowi szukać. (Inna klasa? Inny zakres? Inny pakiet? Inna baza kodów?)
  • dla 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 momencie, w którym próbowałeś jej użyć. (Patrz przykład poniżej)
  • dla identyfikatorów, które powinny być nazwy metod lub pól:
    • być może próbujesz odnieść się do odziedziczonej metody lub pola, które nie zostały zadeklarowane w klasach lub interfejsach rodzica / przodka.
    • być może próbujesz użyć metody jako pola, lub odwrotnie; np. "someString".length lub someArray.length().
  • Dla identyfikatorów, które powinny być nazwami klas:

    • być może zapomniałeś zaimportować klasę.
    • być może użyłeś importu "star", ale klasa nie jest zdefiniowana w żadnym z paczek, które zaimportowałeś.
    • Być może zapomniałeś new jak w:

      String s = String();  // should be 'new String()'
      
  • Dla przypadków, w których typ lub instancja nie wydaje się mieć członka, którego oczekujesz:

    • być może zadeklarowałeś klasę zagnieżdżoną lub parametr ogólny, który cieniuje Typ, którego chciałeś użyć.
    • być może cieniujesz zmienną statyczną lub instancyjną.
    • być może zaimportowałeś zły typ; np. z powodu uzupełniania IDE lub auto-korekcji.
    • być może używasz (kompilujesz przeciwko) złej wersji API.
    • być może zapomniałeś wrzucić swój obiekt do odpowiedniej podklasy.

Problem jest często kombinacją powyższych. Na przykład, może" gwiazdka " zaimportowała java.io.*, a następnie próbowała użyć klasy Files... który jest w java.nio Nie java.io. A może chciałeś napisać File... która jest klasą w java.io.


Poniżej przedstawiono przykład, w jaki sposób niepoprawne przeszukiwanie zmiennych może prowadzić do błędu "nie można znaleźć symbolu":]}
for (int i = 0; i < strings.size(); i++) {
    if (strings.get(i).equalsIgnoreCase("fnoord")) {
        break;
    }
}
if (i < strings.size()) {
    ...
}
W instrukcji

Pojawi się błąd "nie można znaleźć symbolu" dla i. Chociaż wcześniej zadeklarowaliśmy i, deklaracja ta jest tylko w zakresie dla for oświadczenia i jego ciała. Odniesienie do i w deklaracji if nie może zobaczyć tej deklaracji i. Jest to poza zakresem .

(An poprawą może być przeniesienie instrukcji if do pętli lub zadeklarowanie i przed rozpoczęciem pętli.)


Jest to przykład, który powoduje zagadkę, w której 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 wywołaniu println mówiący, że i nie można znaleźć. Ale (słyszę, jak mówisz) zadeklarowałem to!

Problemem jest podstępny średnik przed {. Język Java definiuje to jako empty statement. Więc ten kod faktycznie oznacza to:

for (int i = 0; i < 100; i++); 

{
    System.out.println("i is " + i);
}

Blok { ... } nie jest ciałem pętli for, więc deklaracja i nie jest w zakresie 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, tmp w wyrażeniu tmp(...) jest błędna. Kompilator będzie szukał metody nazywa się tmp, i nie znajdzie żadnego. Poprzednio zadeklarowana tmp znajduje się w przestrzeni nazw dla zmiennych, a nie w przestrzeni nazw dla metod.

W przykładzie, na który się natknąłem, programista faktycznie pominął operatora. To co chciał napisać to było to:

int res = tmp * (a + b);

Jest jeszcze jeden powód, dla którego kompilator może nie znaleźć symbolu, jeśli kompilujesz z linii poleceń. Możesz po prostu zapomnieć 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 uruchomisz javac Foo.java, możesz stwierdzić, że kompilator nie może znaleźć symbolu Bar. Prosta odpowiedź to Foo i Bar razem; np. javac Foo.java Bar.java lub javac *.java. Albo jeszcze lepiej użyć narzędzia Java build; np. Ant, Maven, Gradle i tak dalej.

Są też inne bardziej niejasne przyczyny ... którą 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 linię w pliku wskazaną przez Komunikat o błędzie kompilacji.
  • Określ, o którym symbolu mówi komunikat o błędzie.
  • dowiedzieć się dlaczego kompilator mówi, że nie może znaleźć symbolu; patrz powyżej!

Następnie pomyśl o tym, co twój kod ma mówić. Potem w końcu wymyślisz, jakiej korekty potrzebujesz wykonaj kod źródłowy, aby robić to, co chcesz.

Zauważ, że nie każda "korekta" jest poprawna. Rozważmy 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, aby to "naprawić": {]}

  • mógłbym zmienić wewnętrzny for na for (int j = 1; j < 10; j++) - prawdopodobnie poprawny.
  • mógłbym dodać deklarację dla j przed pętlą wewnętrzną for, lub zewnętrzną for pętlą-ewentualnie poprawną.
  • mógłbym zmienić j na i w wewnętrznej for pętli-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. Niejasne przyczyny

Oto kilka przypadków, w których "nie można znaleźć symbolu" jest pozornie niewytłumaczalne ... dopóki nie przyjrzysz się bliżej.

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

  2. Nie rekompilujesz: czasami zdarza się, że nowi Programiści Javy nie rozumieją, jak działa Łańcuch narzędzi Javy, lub nie zaimplementowali powtarzalnego "proces budowania"; np. za pomocą IDE, Ant, Maven, Gradle i tak dalej. W takiej sytuacji programista może uganiać się za swoim ogonem w poszukiwaniu iluzorycznego błędu, który jest w rzeczywistości spowodowany niewłaściwą rekompilacją kodu i tym podobne ...

  3. Problem wcześniejszego budowania: możliwe, że wcześniejsze budowanie nie powiodło się w sposób, który dawał plik JAR z brakującymi klasami. Taka awaria zwykle zostanie zauważona, jeśli używasz narzędzia do budowania. Jednakże jeśli otrzymujesz pliki JAR od kogoś innego, jesteś uzależniony od ich poprawnego budowania i zauważania błędów. Jeśli podejrzewasz to, użyj tar -tvf, aby wyświetlić zawartość pliku suspect jar.

  4. Problemy z IDE: ludzie zgłaszali przypadki, w których ich IDE się myli i kompilator w IDE nie może znaleźć klasy, która istnieje ... albo odwrotnie.

    • Może się to zdarzyć, jeśli pamięci podręczne IDE zostaną zsynchronizowane z plikiem system. Istnieją specyficzne dla IDE sposoby, aby to naprawić.

    • To może 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ź.

  5. Przedefiniowanie klas systemowych : widziałem przypadki, w których kompilator skarży się, że substring jest nieznanym symbolem 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 metody substring.

    Lekcja: nie Definiuj własnych klas o takich samych nazwach jak zwykłe klasy biblioteczne!

  6. Homoglify: jeśli używasz kodowania UTF-8 dla swoich plików źródłowych, możliwe jest posiadanie identyfikatorów, które wyglądają tak samo, ale w rzeczywistości różnią się, ponieważ zawierają homoglify. Zobacz ta strona aby uzyskać więcej informacji.

    Można tego uniknąć, ograniczając się do ASCII lub Latin - 1 jako kodowania plików źródłowych i używając Java \uxxxx escapes dla innych znaków.


1 - jeśli, możliwe, widzisz to w wyjątku uruchomieniowym lub komunikacie o błędzie, to albo skonfigurowałeś IDE tak, aby uruchamiało kod z błędami kompilacji, albo Twoja aplikacja generuje i kompiluje kod .. w czasie wykonywania.

 301
Author: Stephen C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 12:06:45

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

String s = String();

Kontra

String s = new String();
 19
Author: thinkterry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-17 08:50:13

Jeszcze jeden przykład "zmienna jest poza zakresem"

Jak już widziałem tego typu pytania kilka razy, może jeszcze jeden przykład na to, co jest nielegalne, nawet jeśli może to czuć 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 ze zmiennych o nazwie {[3] } nie jest widoczna poza ich zakresem-czyli w tym przypadku otaczającymi nawiasami {}.

Można powiedzieć: "ale zmienna o nazwie message jest zdefiniowana tak czy inaczej - więc wiadomość jest zdefiniowana po if".

Ale się mylisz.

Java nie ma operatorów free() ani delete, 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 szczególnie źle, jeśli myślisz, że zrobiłeś coś dobrego. Widziałem taki błąd po "optymalizacji" kodu w ten sposób:
if(somethingIsTrue()) {
  String message = "Everything is fine";
  System.out.println(message);
} else {
  String message = "We have an error";
  System.out.println(message);
}

"Oh, There' s duplicated code, let ' s wyciągnij tę wspólną linię " - > I oto ona.

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

String message = "We have an error";
if(somethingIsTrue()) {
  message = "Everything is fine";
} 
System.out.println(message);
 13
Author: Jan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-01 03:42:55

Jeden sposób, aby uzyskać ten błąd w Eclipse:

  1. Zdefiniuj klasę A W src/test/java.
  2. Zdefiniuj inną klasę B w src/main/java, która używa klasy A.

Wynik: Eclipse skompiluje kod, ale maven Da "nie można znaleźć symbolu".

Przyczyna : Eclipse używa połączonej ścieżki budowania dla drzewa głównego i testowego. Niestety, nie obsługuje używania różnych ścieżek budowania dla różnych części projektu Eclipse, co jest tym, co Maven wymaga.

Rozwiązanie:

  1. nie Definiuj swoich zależności w ten sposób; tzn. nie popełniaj tego błędu.
  2. regularnie buduj swoją bazę kodową używając Mavena, abyś wcześnie zauważył ten błąd. Jednym ze sposobów na to jest użycie serwera CI.
 8
Author: Joel Costigliola,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-30 01:09:42

Jeśli pojawia się ten błąd w kompilacji gdzie indziej, podczas gdy twoje IDE mówi, że wszystko jest w porządku, sprawdź, czy używasz tych samych wersji Javy w obu miejscach.

Na przykład Java 7 i Java 8 mają różne API, więc wywołanie nieistniejącego API w starszej wersji Javy spowodowałoby ten błąd.

 2
Author: Jonathan Lin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-08 05:58:27

"Can not find" oznacza, że kompilator, który nie może znaleźć odpowiedniej zmiennej, metody, klasy itp...jeśli masz ten masaż błędu, przede wszystkim chcesz znaleźć linię kodu, w której uzyskasz Masaż błędu..Następnie będziesz w stanie znaleźć , która zmienna, metoda lub klasa nie zostały zdefiniowane przed jej użyciem.Po potwierdzeniu initialize że zmienna, metoda lub klasa mogą być użyte do późniejszego require...Rozważ poniższy przykład.

Stworzę klasę demo i wydrukuję nazwę...

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

Teraz spójrz na wynik..

Tutaj wpisz opis obrazka

Ten błąd mówi, "nazwa zmiennej nie może znaleźć"..Definiowanie i inicjalizacja wartości zmiennej 'name' może być zniesiony ten błąd..Właściwie tak,

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

             String name="smith";

             System.out.print(name);
      }
}

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

Tutaj wpisz opis obrazka

Ok pomyślnie rozwiązałem to error..At w tym samym czasie, jeśli można uzyskać " nie można znaleźć metody "lub" nie można znaleźć klasy " coś, na początku, zdefiniować klasę lub metodę, a po użyciu tego..

 2
Author: GT_hash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-01 03:09:43

Ja też miałem ten błąd. (za co wygooglowałem i zostałem przekierowany na tą stronę)

Problem: wołałem statyczną metodę 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 to, budując najpierw projekt, w którym jest zdefiniowana metoda, a następnie projekt, z którego została wywołana metoda.

 0
Author: Maria,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-07 14:09:44

Aby uzyskać podpowiedzi, przyjrzyj się bliżej nazwie klasy, która rzuca błąd i numer linii, przykład: Niepowodzenie kompilacji [ERROR] \ applications \ xxxxx.nie można znaleźć symbolu

Inną przyczyną jest nieobsługiwana metoda dla wersji Javy powiedzmy jdk7 vs 8. Sprawdź swój % JAVA_HOME %

 0
Author: Striker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-06 12:47:21

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

  1. Jeśli używasz IntelliJ

    File -> 'Invalidate Caches/Restart'

Lub

  1. Odwołująca się klasa była w innym projekcie i ta zależność nie została dodana do pliku Gradle mojego projektu. Więc dodałem zależność używając

    compile project(':anotherProject')

I zadziałało. HTH!
 0
Author: avp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-18 01:50:48

Możesz również uzyskać ten błąd, jeśli deklarujesz niewłaściwy typ, na przykład:

Boolean zamiast boolean

Integer zamiast int

String zamiast String

 -2
Author: BlaCk HoLe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 08:22:50