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
, while
et ainsi de suite.
- Littéraux: comme
42
et 'X'
et "Hi mum!"
.
- Les opérateurs et autres jetons non alphanumériques: comme
+
, =
, {
et ainsi de suite.
- Identifiants: comme
Reader
, i
, toString
, processEquibalancedElephants
et 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
StringBiulder
au 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
stringBuilder
au 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
mystring
et my_string
sont 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:
Pour les identificateurs qui doivent être des noms de classe:
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 Files
classe ... qui ne l'est java.nio
pas 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 i
dans l' if
instruction. Bien que nous l'ayons déjà déclaré i
, cette déclaration n'a de portée que pour la for
déclaration et son corps. La référence à i
dans la if
dé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' if
instruction à l'intérieur de la boucle ou de la déclarer i
avant 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' println
appel disant que i
introuvable. 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 for
boucle. 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 for
boucle, et par conséquent la déclaration précédente de i
dans l' for
instruction 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, tmp
l' tmp(...)
expression est erronée. Le compilateur recherchera une méthode appelée tmp
et n'en trouvera pas. Le précédemment déclaré se tmp
trouve 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 Foo
et Bar
où les Foo
utilise Bar
. Si vous n'avez jamais compilé Bar
et 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 Foo
et Bar
ensemble; par exemple javac Foo.java Bar.java
ou 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 for
boucle interne ou la for
boucle externe - peut-être correcte.
- Je pouvais changer
j
à i
la intérieur for
boucle - 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.
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.
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.
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 -tvf
pour répertorier le contenu du fichier JAR suspect.
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 .
Problèmes Android : lorsque vous programmez pour Android et que vous rencontrez des erreurs "Impossible de trouver le symbole" R
, sachez que les R
symboles sont définis par le context.xml
fichier. Vérifiez que votre context.xml
fichier est correct et au bon endroit, et que le R
fichier 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.
Redéfinir les classes système : j'ai vu des cas où le compilateur se plaint que substring
c'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 String
et que sa version de la classe n'avait pas défini de substring
méthode.
Leçon: Ne définissez pas vos propres classes avec les mêmes noms que les classes de bibliothèque courantes!
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 .