Que signifie une erreur «Impossible de trouver le symbole» ou «Impossible de résoudre le symbole»?

395

Veuillez expliquer ce qui suit concernant les erreurs «Impossible de trouver le symbole» et «Impossible de résoudre le symbole»:

  • Que signifient-ils?
  • Quelles choses peuvent les provoquer?
  • Comment le programmeur procède-t-il pour les réparer?

Cette question est conçue pour amorcer un Q&A complet sur ces erreurs de compilation courantes en Java.

Stephen C
la source

Réponses:

417

0. Y a-t-il une différence entre les deux erreurs?

Pas vraiment. "Impossible de trouver le symbole" et "Impossible de résoudre le symbole" signifient la même chose. Certains compilateurs Java utilisent une phrase, et certains l'autre.

1. Que signifie une erreur "Symbole introuvable"?

Tout d'abord, il s'agit d'une erreur de compilation 1 . Cela signifie soit qu'il y a un problème dans votre code source Java, soit qu'il y a un problème dans la façon dont vous le compilez.

Votre code source Java se compose des éléments suivants:

  • Mots - clés: comme true, false, class, whileet ainsi de suite.
  • Littéraux: comme 42et 'X'et "Hi mum!".
  • Les opérateurs et autres jetons non alphanumériques: comme +, =, {et ainsi de suite.
  • Identifiants: comme Reader, i, toString, processEquibalancedElephantset ainsi de suite.
  • Commentaires et espaces.

Une erreur "Impossible de trouver le symbole" concerne les identificateurs. Lorsque votre code est compilé, le compilateur doit déterminer ce que signifie chaque identifiant dans votre code.

Une erreur "Impossible de trouver le symbole" signifie que le compilateur ne peut pas le faire. Votre code semble faire référence à quelque chose que le compilateur ne comprend pas.

2. Qu'est-ce qui peut provoquer une erreur "Symbole introuvable"?

En premier ordre, il n'y a qu'une seule cause. Le compilateur a recherché tous les endroits où l'identifiant devait être défini et il n'a pas pu trouver la définition. Cela pourrait être dû à un certain nombre de choses. Les plus courants sont les suivants:

  • Pour les identifiants en général:
    • Vous avez peut-être mal orthographié le nom; c'est à dire StringBiulderau lieu de StringBuilder. Java ne peut pas et ne tentera pas de compenser les erreurs d'orthographe ou de frappe.
    • Vous vous êtes peut-être trompé; c'est à dire stringBuilderau lieu de StringBuilder. Tous les identificateurs Java sont sensibles à la casse.
    • Vous avez peut-être utilisé des soulignements de manière inappropriée; c'est à dire mystringet my_stringsont différents. (Si vous respectez les règles de style Java, vous serez largement protégé contre cette erreur ...)
    • Vous essayez peut-être d'utiliser quelque chose qui a été déclaré «ailleurs»; c'est-à-dire dans un contexte différent de celui où vous avez implicitement demandé au compilateur de regarder. (Une classe différente? Une portée différente? Un package différent? Une base de code différente?)
  • Pour les identificateurs qui doivent faire référence à des variables:
    • Vous avez peut-être oublié de déclarer la variable.
    • Peut-être que la déclaration de variable est hors de portée au moment où vous avez essayé de l'utiliser. (Voir l'exemple ci-dessous)
  • Pour les identificateurs qui doivent être des noms de méthode ou de champ:

    • Vous essayez peut-être de faire référence à une méthode ou un champ hérité qui n'a pas été déclaré dans les classes ou interfaces parent / ancêtre.
    • Vous essayez peut-être de faire référence à une méthode ou à un champ qui n'existe pas (c'est-à-dire qui n'a pas été déclaré) dans le type que vous utilisez; par exemple "someString".push()2 .
    • Vous essayez peut-être d'utiliser une méthode comme champ, ou vice versa; par exemple "someString".lengthou someArray.length().
    • Vous opérez peut-être par erreur sur un tableau plutôt que sur un élément de tableau; par exemple

      String strings[] = ...
      if (strings.charAt(3)) { ... }
      // maybe that should be 'strings[0].charAt(3)'
      
  • Pour les identificateurs qui doivent être des noms de classe:

    • Vous avez peut-être oublié d'importer la classe.
    • Vous avez peut-être utilisé des importations "étoiles", mais la classe n'est définie dans aucun des packages que vous avez importés.
    • Vous avez peut-être oublié un newcomme dans:

      String s = String();  // should be 'new String()'
  • Pour les cas où le type ou l'instance ne semble pas avoir le membre que vous attendiez qu'il ait:

    • Vous avez peut-être déclaré une classe imbriquée ou un paramètre générique qui associe le type que vous vouliez utiliser.
    • Vous observez peut-être une variable statique ou d'instance.
    • Vous avez peut-être importé le mauvais type; par exemple en raison de l'achèvement de l'IDE ou de la correction automatique.
    • Peut-être que vous utilisez (compilez) la mauvaise version d'une API.
    • Vous avez peut-être oublié de transposer votre objet dans une sous-classe appropriée.

Le problème est souvent une combinaison de ce qui précède. Par exemple, vous avez peut-être importé une "étoile" java.io.*, puis essayé d'utiliser la Filesclasse ... qui ne l'est java.niopas java.io. Ou peut-être que vous vouliez écrire File... qui est une classe java.io.


Voici un exemple de la façon dont une portée de variable incorrecte peut conduire à une erreur «Symbole introuvable»:

List<String> strings = ...

for (int i = 0; i < strings.size(); i++) {
    if (strings.get(i).equalsIgnoreCase("fnord")) {
        break;
    }
}
if (i < strings.size()) {
    ...
}

Cela donnera une erreur "Impossible de trouver le symbole" pour idans l' ifinstruction. Bien que nous l'ayons déjà déclaré i, cette déclaration n'a de portée que pour la fordéclaration et son corps. La référence à idans la ifdéclaration ne peut pas voir cette déclaration de i. C'est hors de portée .

(Une correction appropriée ici pourrait être de déplacer l' ifinstruction à l'intérieur de la boucle ou de la déclarer iavant le début de la boucle.)


Voici un exemple qui provoque la perplexité où une faute de frappe conduit à une erreur apparemment inexplicable "Symbole introuvable":

for (int i = 0; i < 100; i++); {
    System.out.println("i is " + i);
}

Cela vous donnera une erreur de compilation dans l' printlnappel disant que iintrouvable. Mais (je vous entends dire) je l'ai déclaré!

Le problème est le point-virgule sournois ( ;) avant le {. La syntaxe du langage Java définit un point-virgule dans ce contexte comme une instruction vide . L'instruction vide devient alors le corps de la forboucle. Donc, ce code signifie en fait ceci:

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

// The previous and following are separate statements!!

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

Le { ... }bloc n'est PAS le corps de la forboucle, et par conséquent la déclaration précédente de idans l' forinstruction est hors de portée dans le bloc.


Voici un autre exemple d'erreur «Impossible de trouver le symbole» provoquée par une faute de frappe.

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

Malgré la déclaration précédente, tmpl' tmp(...)expression est erronée. Le compilateur recherchera une méthode appelée tmpet n'en trouvera pas. Le précédemment déclaré se tmptrouve dans l'espace de noms pour les variables, pas dans l'espace de noms pour les méthodes.

Dans l'exemple que j'ai rencontré, le programmeur avait en fait omis un opérateur. Ce qu'il voulait écrire était le suivant:

int res = tmp * (a + b);

Il existe une autre raison pour laquelle le compilateur peut ne pas trouver de symbole si vous compilez à partir de la ligne de commande. Vous pourriez simplement avoir oublié de compiler ou recompiler une autre classe. Par exemple, si vous avez des classes Fooet Baroù les Fooutilise Bar. Si vous n'avez jamais compilé Baret que vous exécutez javac Foo.java, vous risquez de constater que le compilateur ne peut pas trouver le symbole Bar. La réponse simple est de compiler Fooet Barensemble; par exemple javac Foo.java Bar.javaou javac *.java. Ou mieux encore, utilisez un outil de construction Java; par exemple Ant, Maven, Gradle et ainsi de suite.

Il y a aussi d'autres causes plus obscures ... que je traiterai ci-dessous.

3. Comment puis-je corriger ces erreurs?

D'une manière générale, vous commencez par déterminer la cause de l'erreur de compilation.

  • Regardez la ligne du fichier indiquée par le message d'erreur de compilation.
  • Identifiez le symbole dont parle le message d'erreur.
  • Découvrez pourquoi le compilateur dit qu'il ne peut pas trouver le symbole; voir au dessus!

Ensuite, vous pensez à ce que votre code est censé dire. Enfin, vous déterminez quelle correction vous devez apporter à votre code source pour faire ce que vous voulez.

Notez que toutes les «corrections» ne sont pas correctes. Considère ceci:

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

Supposons que le compilateur indique "Impossible de trouver le symbole" pour j. Il y a plusieurs façons de "corriger" cela:

  • Je pouvais changer le intérieur forà for (int j = 1; j < 10; j++)- probablement correct.
  • Je pourrais ajouter une déclaration pour j avant la forboucle interne ou la forboucle externe - peut-être correcte.
  • Je pouvais changer jà ila intérieur forboucle - probablement faux!
  • etc.

Le fait est que vous devez comprendre ce que votre code essaie de faire afin de trouver le bon correctif.

4. Causes obscures

Voici quelques cas où le "Symbole introuvable" est apparemment inexplicable ... jusqu'à ce que vous regardiez de plus près.

  1. Dépendances incorrectes : si vous utilisez un IDE ou un outil de génération qui gère le chemin de génération et les dépendances du projet, vous avez peut-être fait une erreur avec les dépendances; par exemple, laissé de côté une dépendance ou sélectionné la mauvaise version. Si vous utilisez un outil de construction (Ant, Maven, Gradle, etc.), vérifiez le fichier de construction du projet. Si vous utilisez un IDE, vérifiez la configuration du chemin de génération du projet.

  2. Vous n'êtes pas en train de recompiler : il arrive parfois que les nouveaux programmeurs Java ne comprennent pas comment fonctionne la chaîne d'outils Java ou n'ont pas mis en œuvre un "processus de construction" reproductible; par exemple en utilisant un IDE, Ant, Maven, Gradle et ainsi de suite. Dans une telle situation, le programmeur peut finir par courir après sa queue à la recherche d'une erreur illusoire qui est en fait causée par la non-recompilation correcte du code, etc.

  3. Un problème de version antérieure : il est possible qu'une version antérieure ait échoué d'une manière qui a donné un fichier JAR avec des classes manquantes. Un tel échec serait généralement remarqué si vous utilisiez un outil de construction. Cependant, si vous obtenez des fichiers JAR de quelqu'un d'autre, vous dépendez de leur construction correcte et de la détection d'erreurs. Si vous suspectez cela, utilisez tar -tvfpour répertorier le contenu du fichier JAR suspect.

  4. Problèmes liés à l'IDE : des personnes ont signalé des cas où leur IDE est confus et le compilateur de l'EDI ne peut pas trouver une classe qui existe ... ou la situation inverse.

    • Cela peut se produire si l'IDE a été configuré avec la mauvaise version de JDK.

    • Cela peut se produire si les caches de l'EDI sont désynchronisés avec le système de fichiers. Il existe des moyens spécifiques à l'IDE pour résoudre ce problème.

    • Cela pourrait être un bogue IDE. Par exemple, @Joel Costigliola décrit un scénario où Eclipse ne gère pas correctement une arborescence de "test" Maven: voir cette réponse .

  5. Problèmes Android : lorsque vous programmez pour Android et que vous rencontrez des erreurs "Impossible de trouver le symbole" R, sachez que les Rsymboles sont définis par le context.xmlfichier. Vérifiez que votre context.xmlfichier est correct et au bon endroit, et que le Rfichier de classe correspondant a été généré / compilé. Notez que les symboles Java sont sensibles à la casse, donc les identifiants XML correspondants sont également sensibles à la casse.

    D'autres erreurs de symbole sur Android sont probablement dues à des raisons précédemment mentionnées; par exemple, des dépendances manquantes ou incorrectes, des noms de packages, des méthodes ou des champs incorrects qui n'existent pas dans une version particulière de l'API, des fautes d'orthographe / de frappe, etc.

  6. Redéfinir les classes système : j'ai vu des cas où le compilateur se plaint que substringc'est un symbole inconnu dans quelque chose comme ce qui suit

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

    Il s'est avéré que le programmeur avait créé sa propre version de Stringet que sa version de la classe n'avait pas défini de substringméthode.

    Leçon: Ne définissez pas vos propres classes avec les mêmes noms que les classes de bibliothèque courantes!

  7. Homoglyphes: si vous utilisez le codage UTF-8 pour vos fichiers source, il est possible d'avoir des identifiants qui se ressemblent , mais qui sont en fait différents car ils contiennent des homoglyphes. Consultez cette page pour plus d'informations.

    Vous pouvez éviter cela en vous limitant à ASCII ou Latin-1 comme codage du fichier source et en utilisant des \uxxxxéchappements Java pour d'autres caractères.


1 - Si, par hasard, vous ne voyez cela à une exception d'exécution ou un message d'erreur, soit vous avez configuré votre IDE pour exécuter du code avec des erreurs de compilation, ou votre application génère et la compilation du code .. lors de l' exécution.

2 - Les trois principes de base du génie civil: l'eau ne coule pas en amont, une planche est plus solide sur le côté et vous ne pouvez pas pousser sur une corde .

Stephen C
la source
J'ai eu une autre situation où cette erreur de compilation s'est produite alors qu'eclipse ne voyait pas le problème: deux classes avec des dépendances définies dans l'autre classe respectivement. Dans mon cas, j'avais une énumération, implémentant une interface, définie dans une classe où j'avais déjà follement utilisé l'énumération.
Jogi
De façon assez similaire au commentaire ci-dessus, lorsque je compile et exécute mon programme à partir d'Eclipse, cela ne fonctionne pas. Le compiler à partir de la console soulève un tas de ces erreurs "Impossible de trouver le symbole" souvent liées au dernier élément d'une importation. Je n'ai aucune idée de ce qui cause cela car il n'y a vraiment rien de mal dans le code.
Andres Stadelmann
Un autre problème est que les IDE peuvent "interpréter" d'autres erreurs dans cette catégorie. Par exemple printlndans le System.out.printlncas placé au niveau de la classe sous compilateur standard nous donnerait <identifier> expected( démo ) mais IntelliJ nous verrons Cannot resolve symbol 'println'( démo ).
Pshemo
Sensationnel. J'appellerais cela un bug du compilateur.
Stephen C
23

Vous obtiendrez également cette erreur si vous oubliez new:

String s = String();

contre

String s = new String();

car l'appel sans le newmot clé essaiera de rechercher une méthode (locale) appelée Stringsans arguments - et cette signature de méthode n'est probablement pas définie.

réflexion
la source
14

Un autre exemple de «Variable est hors de portée»

Comme j'ai déjà vu ce genre de questions à plusieurs reprises, peut-être un autre exemple de ce qui est illégal même si cela peut sembler correct.

Considérez ce code:

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

C'est un code invalide. Parce qu'aucune des variables nommées messagen'est visible en dehors de leur portée respective - qui serait les crochets environnants {}dans ce cas.

Vous pourriez dire: "Mais une variable nommée message est définie de toute façon - donc le message est défini après le if".

Mais tu aurais tort.

Java n'a pas d' opérateurs free()ou delete, donc il doit s'appuyer sur le suivi de la portée des variables pour savoir quand les variables ne sont plus utilisées (ainsi que les références à ces variables de cause).

C'est particulièrement mauvais si vous pensiez avoir fait quelque chose de bien. J'ai vu ce genre d'erreur après avoir "optimisé" du code comme ceci:

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

"Oh, il y a du code en double, retirons cette ligne commune" -> et là, c'est tout.

La façon la plus courante de gérer ce type de problème de portée serait de pré-affecter les valeurs else aux noms de variables dans la portée extérieure, puis de les réaffecter si:

String message = "We have an error";
if(somethingIsTrue()) {
  message = "Everything is fine";
} 
System.out.println(message);
Jan
la source
4
"Java n'a pas d'opérateurs free () ou delete, il doit donc s'appuyer sur le suivi de la portée des variables pour savoir quand les variables ne sont plus utilisées (ainsi que les références à ces variables de cause)." - Bien que cela soit vrai, cela n'est pas pertinent. C et C ++ ont des opérateurs free / delete respectivement, et pourtant le code C / C ++ équivalent à vos exemples serait illégal. Les blocs C et C ++ limitent la portée des variables comme en Java. En fait, cela est vrai pour la plupart des langages "structurés en blocs".
Stephen C
1
La meilleure solution pour le code qui attribue une valeur différente à chaque branche est d'utiliser une déclaration de variable videfinal .
Daniel Pryden
10

Une façon d'obtenir cette erreur dans Eclipse:

  1. Définissez une classe Adans src/test/java.
  2. Définir une autre classe Bdans src/main/javacette classe utilisations A.

Résultat: Eclipse compilera le code, mais maven donnera "Symbole introuvable".

Cause sous-jacente: Eclipse utilise un chemin de génération combiné pour les arborescences principale et de test. Malheureusement, il ne prend pas en charge l'utilisation de chemins de génération différents pour différentes parties d'un projet Eclipse, ce dont Maven a besoin.

Solution :

  1. Ne définissez pas vos dépendances de cette façon; c'est à dire ne faites pas cette erreur.
  2. Créez régulièrement votre base de code à l'aide de Maven afin de détecter cette erreur tôt. Une façon de le faire est d'utiliser un serveur CI.
Joel Costigliola
la source
Quelle est la solution à celle-ci?
2
tout ce que vous utilisez dans src / main / java doit être défini dans src / main / java ou dans toutes les dépendances de compilation / d'exécution (pas les dépendances de test).
Joel Costigliola
5

"Impossible de trouver" signifie que, compilateur qui ne peut pas trouver la variable, la méthode, la classe etc ... si vous avez obtenu ce massage d'erreur, tout d'abord vous voulez trouver la ligne de code où obtenir le massage d'erreur .. Et puis vous capable de trouver quelle variable, méthode ou classe n'a pas défini avant de l'utiliser. Après confirmation, initialisez cette variable, méthode ou classe pour une utilisation ultérieure ... Considérez l'exemple suivant.

Je vais créer une classe de démonstration et imprimer un nom ...

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

Regardez maintenant le résultat ..

entrez la description de l'image ici

Cette erreur indique "le nom de la variable ne peut pas être trouvé". La définition et l'initialisation de la valeur de la variable "nom" peuvent être supprimées. En fait, comme ceci,

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

             String name="smith";

             System.out.print(name);
      }
}

Regardez maintenant la nouvelle sortie ...

entrez la description de l'image ici

Ok Résolu cette erreur avec succès .. En même temps, si vous pouviez obtenir quelque chose "ne peut pas trouver la méthode" ou "ne peut pas trouver la classe", dans un premier temps, définissez une classe ou une méthode et après utilisation cela ..

GT_hash
la source
3

Si vous obtenez cette erreur dans la build ailleurs, alors que votre IDE dit que tout va parfaitement bien, vérifiez que vous utilisez les mêmes versions de Java aux deux endroits.

Par exemple, Java 7 et Java 8 ont des API différentes, donc appeler une API inexistante dans une ancienne version Java provoquerait cette erreur.

Jonathan Lin
la source
2

Moi aussi, je recevais cette erreur. (pour lequel j'ai googlé et j'ai été dirigé vers cette page)

Problème: j'appelais une méthode statique définie dans la classe d'un projet A à partir d'une classe définie dans un autre projet B. J'obtenais l'erreur suivante:

error: cannot find symbol

Solution: J'ai résolu ce problème en créant d'abord le projet où la méthode est définie, puis le projet d'où la méthode était appelée.

Divya Jose
la source
Oui, cela peut se produire si vous décidez de déplacer une fonction réutilisable de votre package actuel vers votre package d'utilitaires communs, par exemple, mais vous oubliez ensuite de compiler votre package commun avant d'appeler la fonction à partir de votre package actuel.
buildingKofi
2

Si le chemin de construction de l'éclipse Java est mappé à 7, 8 et dans le projet pom.xml, les propriétés Maven java.version sont mentionnées dans une version Java supérieure (9,10,11, etc.) à 7,8, vous devez mettre à jour dans pom. fichier xml.

Dans Eclipse, si Java est mappé à Java version 11 et dans pom.xml, il est mappé à Java version 8. Mettez à jour la prise en charge d'Eclipse vers Java 11 en suivant les étapes ci-dessous dans l'aide IDE eclipse -> Installer un nouveau logiciel ->

Collez le lien suivant http://download.eclipse.org/eclipse/updates/4.9-P-builds au travail avec

ou

Ajouter (une fenêtre contextuelle s'ouvrira) ->

Name:Prise en charge de Java 11 Location: http://download.eclipse.org/eclipse/updates/4.9-P-builds

puis mettez à jour la version Java dans les propriétés Maven du fichier pom.xml comme ci-dessous

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

Enfin, faites un clic droit sur le projet Debug as -> Maven clean, Maven build steps

UdayKiran Pulipati
la source
2

RESOLU

Sélectionnez Build -> Rebuild Project le résoudra

Ajay
la source
1
Cela dépend beaucoup et ce n'est généralement pas le cas.
Maarten Bodewes
1

Il peut y avoir différents scénarios comme les gens l'ont mentionné ci-dessus. Un couple de choses qui m'ont aidé à résoudre ce problème.

  1. Si vous utilisez IntelliJ

    File -> 'Invalidate Caches/Restart'

OU

  1. La classe référencée se trouvait dans un autre projet et cette dépendance n'a pas été ajoutée au fichier de génération Gradle de mon projet. J'ai donc ajouté la dépendance en utilisant

    compile project(':anotherProject')

et ça a marché. HTH!

avp
la source
1

vous avez compilé votre code à l'aide de la compilation maven, puis utilisé le test maven pour l'exécuter a bien fonctionné. Maintenant, si vous avez modifié quelque chose dans votre code et que sans le compiler, vous l'exécutez, vous obtiendrez cette erreur.

Solution: compilez-le à nouveau, puis exécutez le test. Pour moi, cela a fonctionné de cette façon.

ANIL KUMAR
la source
1

Dans mon cas - j'ai dû effectuer les opérations ci-dessous:

  1. Déplacer le context.xmlfichier de src/java/packagevers le resourcerépertoire (IntelliJ IDE)
  2. targetRépertoire propre .
VIPIN KUMAR
la source
Déplacer un fichier sans se soucier des références peut provoquer cette erreur. Je l'ai déjà rencontré. Réinitialisez simplement sur Git et déplacez-vous à nouveau avec précaution, la résolution de l'erreur.
Huy Hóm Hỉnh
0

Pour obtenir des conseils, examinez de plus près le nom du nom de classe qui génère une erreur et le numéro de ligne, par exemple: Échec de la compilation [ERREUR] \ applications \ xxxxx.java: [44,30] erreur: impossible de trouver le symbole

Une autre cause est la méthode non prise en charge de la version java, par exemple jdk7 vs 8. Vérifiez votre% JAVA_HOME%

Le buteur
la source
Cela dit simplement la même chose que les autres réponses disent.
Stephen C