Solución:
0. ¿Hay alguna diferencia entre los dos errores?
Realmente no. “No se puede encontrar el símbolo”, “No se puede resolver el símbolo” y “Símbolo no encontrado” significan lo mismo. Los diferentes compiladores de Java utilizan una fraseología diferente.
1. ¿Qué significa el error “No se puede encontrar el símbolo”?
En primer lugar, es un error de compilación1. Esto significa que cualquiera hay un problema en su código fuente de Java, o hay un problema en la forma en que lo está compilando.
Su código fuente de Java consta de las siguientes cosas:
- Palabras clave: me gusta
true
,false
,class
,while
, etcétera. - Literales: como
42
y'X'
y"Hi mum!"
. - Operadores y otros tokens no alfanuméricos: como
+
,=
,{
, etcétera. - Identificadores: como
Reader
,i
,toString
,processEquibalancedElephants
, etcétera. - Comentarios y espacios en blanco.
El error “No se puede encontrar el símbolo” se refiere a los identificadores. Cuando se compila su código, el compilador necesita averiguar qué significan todos y cada uno de los identificadores en su código.
Un error “No se puede encontrar el símbolo” significa que el compilador no puede hacer esto. Su código parece estar refiriéndose a algo que el compilador no comprende.
2. ¿Qué puede causar un error “No se puede encontrar el símbolo”?
Como primer orden, solo hay una causa. El compilador buscó en todos los lugares donde el identificador deberían definirse, y no pudo encontrar la definición. Esto podría deberse a varias cosas. Los más comunes son los siguientes:
-
Para identificadores en general:
- Quizás escribiste el nombre incorrectamente; es decir
StringBiulder
en lugar deStringBuilder
. Java no puede y no intentará compensar la mala ortografía o los errores tipográficos. - Quizás entendiste mal el caso; es decir
stringBuilder
en lugar deStringBuilder
. Todos los identificadores de Java distinguen entre mayúsculas y minúsculas. - Quizás usó guiones bajos de manera inapropiada; es decir
mystring
ymy_string
son diferentes. (Si se adhiere a las reglas de estilo de Java, estará protegido en gran medida de este error …) - Quizás esté intentando utilizar algo que se declaró “en otro lugar”; es decir, en un contexto diferente al que le ha dicho implícitamente al compilador que busque. (¿Una clase diferente? ¿Un alcance diferente? ¿Un paquete diferente? ¿Una base de código diferente?)
- Quizás escribiste el nombre incorrectamente; es decir
-
Para identificadores que deben hacer referencia a variables:
- Quizás olvidó declarar la variable.
- Quizás la declaración de variable esté fuera de alcance en el momento en que intentó usarla. (Ver ejemplo a continuación)
-
Para identificadores que deberían ser nombres de métodos o campos:
-
Quizás esté intentando hacer referencia a un método o campo heredado que no se declaró en las clases o interfaces padre / ancestro.
-
Quizás esté intentando hacer referencia a un método o campo que no existe (es decir, que no ha sido declarado) en el tipo que está utilizando; p.ej
"someString".push()
2. -
Quizás esté intentando utilizar un método como campo, o viceversa; p.ej
"someString".length
osomeArray.length()
. -
Quizás esté operando por error en una matriz en lugar de un elemento de matriz; p.ej
String strings[] = ... if (strings.charAt(3)) { ... } // maybe that should be 'strings[0].charAt(3)'
-
-
Para identificadores que deberían ser nombres de clases:
-
Quizás olvidó importar la clase.
-
Quizás usó importaciones “estrella”, pero la clase no está definida en ninguno de los paquetes que importó.
-
Quizás olvidaste un
new
como en:String s = String(); // should be 'new String()'
-
-
Para los casos en los que el tipo o la instancia no parece tener el miembro que esperaba que tuviera:
- Quizás haya declarado una clase anidada o un parámetro genérico que oscuridad el tipo que pretendía utilizar.
- Quizás esté sombreando una variable estática o de instancia.
- Quizás importó el tipo incorrecto; por ejemplo, debido a la finalización del IDE o la autocorrección.
- Quizás esté usando (compilando contra) la versión incorrecta de una API.
- Quizás olvidó enviar su objeto a una subclase apropiada.
El problema suele ser una combinación de los anteriores. Por ejemplo, tal vez “destaques” importados java.io.*
y luego traté de usar el Files
clase … que está en java.nio
no java.io
. O tal vez quisiste escribir File
… cuales es una clase en java.io
.
A continuación, se muestra un ejemplo de cómo un alcance de variable incorrecto puede provocar un error “No se puede encontrar el símbolo”:
List<String> strings = ...
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnord")) {
break;
}
}
if (i < strings.size()) {
...
}
Esto dará un error “No se puede encontrar el símbolo” para i
en el if
declaración. Aunque previamente declaramos i
, esa declaracion es solo en alcance Para el for
declaración y su cuerpo. La referencia a i
en el if
declaración no pueden ver esa declaración de i
. Está fuera del ámbito.
(Una corrección apropiada aquí podría ser mover el if
declaración dentro del bucle, o para declarar i
antes del inicio del bucle.)
Aquí hay un ejemplo que causa perplejidad donde un error tipográfico conduce a un error aparentemente inexplicable “No se puede encontrar el símbolo”:
for (int i = 0; i < 100; i++); {
System.out.println("i is " + i);
}
Esto le dará un error de compilación en el println
llama diciendo eso i
no pudo ser encontrado. Pero (te escucho decir) ¡Yo lo declaré!
El problema es el punto y coma furtivo ( ;
) antes de {
. La sintaxis del lenguaje Java define un punto y coma en ese contexto como un declaración vacía. La declaración vacía se convierte entonces en el cuerpo del for
círculo. Entonces ese código realmente significa esto:
for (int i = 0; i < 100; i++);
// The previous and following are separate statements!!
{
System.out.println("i is " + i);
}
los { ... }
El bloque NO es el cuerpo del for
loop, y por lo tanto la declaración previa de i
en el for
declaración es fuera del ámbito en el bloque.
Aquí hay otro ejemplo de error “No se puede encontrar el símbolo” causado por un error tipográfico.
int tmp = ...
int res = tmp(a + b);
A pesar de la declaración anterior, la tmp
en el tmp(...)
la expresión es errónea. El compilador buscará un método llamado tmp
y no encontrará uno. El previamente declarado tmp
está en el espacio de nombres para las variables, no en el espacio de nombres para los métodos.
En el ejemplo que encontré, el programador había omitido un operador. Lo que quiso escribir fue esto:
int res = tmp * (a + b);
Hay otra razón por la que el compilador podría no encontrar un símbolo si está compilando desde la línea de comandos. Es posible que simplemente se haya olvidado de compilar o recompilar alguna otra clase. Por ejemplo, si tienes clases Foo
y Bar
dónde Foo
usos Bar
. Si nunca ha compilado Bar
y tu corres javac Foo.java
, es probable que descubra que el compilador no puede encontrar el símbolo Bar
. La respuesta simple es compilar Foo
y Bar
juntos; p.ej javac Foo.java Bar.java
o javac *.java
. O mejor aún, use una herramienta de compilación de Java; por ejemplo, Ant, Maven, Gradle, etc.
También hay otras causas más oscuras … que trataré a continuación.
3. ¿Cómo soluciono estos errores?
En términos generales, comienzas por averiguar qué causado el error de compilación.
- Mire la línea en el archivo indicada por el mensaje de error de compilación.
- Identifique de qué símbolo se refiere el mensaje de error.
- Descubrir por qué el compilador está diciendo que no puede encontrar el símbolo; ¡véase más arriba!
Entonces tú pensar sobre lo que se supone que dice tu código. Luego, finalmente, averigua qué corrección necesita hacer en su código fuente para hacer lo que desea.
Tenga en cuenta que no todas las “correcciones” son correctas. Considera esto:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
Suponga que el compilador dice “No se puede encontrar el símbolo” para j
. Hay muchas formas en que podría “arreglar” eso:
- Podría cambiar el interior
for
parafor (int j = 1; j < 10; j++)
– probablemente correcto. - Podría agregar una declaración para
j
antes de el interiorfor
bucle, o el exteriorfor
bucle – posiblemente correcto. - Podría cambiar
j
parai
en el interiorfor
bucle – ¡probablemente mal! - etcétera.
El punto es que tu necesitar para comprender lo que su código está tratando de hacer para encontrar la solución correcta.
4. Causas oscuras
Aquí hay un par de casos en los que el símbolo “No se puede encontrar” es aparentemente inexplicable … hasta que miras más de cerca.
-
Dependencias incorrectas: Si está utilizando un IDE o una herramienta de compilación que administra la ruta de compilación y las dependencias del proyecto, es posible que haya cometido un error con las dependencias; por ejemplo, omitió una dependencia o seleccionó la versión incorrecta. Si está utilizando una herramienta de compilación (Ant, Maven, Gradle, etc.), consulte el archivo de compilación del proyecto. Si está utilizando un IDE, verifique la configuración de la ruta de compilación del proyecto.
-
No estás recompilando: A veces sucede que los nuevos programadores de Java no entienden cómo funciona la cadena de herramientas de Java, o no han implementado un “proceso de construcción” repetible; por ejemplo, utilizando un IDE, Ant, Maven, Gradle, etc. En tal situación, el programador puede terminar persiguiéndose en busca de un error ilusorio que es Realmente causado por no volver a compilar el código correctamente, y similares …
-
Un problema de construcción anterior: Es posible que una compilación anterior haya fallado de una manera que haya generado un archivo JAR con clases faltantes. Un error de este tipo normalmente se notaría si estuviera utilizando una herramienta de compilación. Sin embargo, si recibe archivos JAR de otra persona, depende de ellos construyendo correctamente y notando errores. Si sospecha esto, use
tar -tvf
para enumerar el contenido del archivo JAR sospechoso. -
Problemas de IDE: La gente ha informado casos en los que su IDE se confunde y el compilador en el IDE no puede encontrar una clase que existe … o la situación inversa.
-
Esto podría suceder si el IDE se ha configurado con la versión de JDK incorrecta.
-
Esto podría suceder si las cachés del IDE no están sincronizadas con el sistema de archivos. Hay formas específicas de IDE para solucionarlo.
-
Esto podría ser un error de IDE. Por ejemplo, @Joel Costigliola describe un escenario en el que Eclipse no maneja correctamente un árbol de “prueba” de Maven: mira esta respuesta.
-
-
Problemas de Android: Cuando está programando para Android y tiene errores “No se puede encontrar el símbolo” relacionados con
R
, tenga en cuenta que elR
los símbolos están definidos por elcontext.xml
expediente. Comprueba que tucontext.xml
archivo es correcto y en el lugar correcto, y que el correspondienteR
Se ha generado / compilado el archivo de clase. Tenga en cuenta que los símbolos de Java distinguen entre mayúsculas y minúsculas, por lo que los identificadores XML correspondientes también distinguen entre mayúsculas y minúsculas.Es probable que otros errores de símbolos en Android se deban a razones mencionadas anteriormente; por ejemplo, dependencias faltantes o incorrectas, nombres de paquetes incorrectos, métodos o campos que no existen en una versión de API en particular, errores de ortografía / escritura, etc.
-
Redefiniendo clases de sistema: He visto casos en los que el compilador se queja de que
substring
es un símbolo desconocido en algo como el siguienteString s = ... String s1 = s.substring(1);
Resultó que el programador había creado su propia versión de
String
y que su versión de la clase no definía unsubstring
métodos.Lección: ¡No defina sus propias clases con los mismos nombres que las clases de biblioteca comunes!
-
Homoglyphs: Si usa codificación UTF-8 para sus archivos fuente, es posible tener identificadores que Mira son iguales, pero de hecho son diferentes porque contienen homoglyphs. Vea esta pagina para mas informacion.
Puede evitar esto restringiéndose a ASCII o Latin-1 como codificación del archivo de origen y utilizando Java
uxxxx
escapa por otros personajes.
1 – Si, por casualidad, hacer vea esto en una excepción de tiempo de ejecución o mensaje de error, entonces ha configurado su IDE para ejecutar código con errores de compilación, o su aplicación está generando y compilando código … en tiempo de ejecución.
2 – Los tres principios básicos de la ingeniería civil: el agua no fluye cuesta arriba, una tabla es más fuerte de lado y no puedes empujar una cuerda.
También obtendrá este error si olvida un new
:
String s = String();
versus
String s = new String();
porque la llamada sin el new
palabra clave intentará buscar un método (local) llamado String
sin argumentos, y es probable que la firma del método no esté definida.
Un ejemplo más de ‘Variable está fuera de alcance’
Como ya he visto ese tipo de preguntas algunas veces, tal vez un ejemplo más de lo que es ilegal, incluso si pudiera sentir okey.
Considere este código:
if(somethingIsTrue()) {
String message = "Everything is fine";
} else {
String message = "We have an error";
}
System.out.println(message);
Ese es un código inválido. Porque ninguna de las variables nombradas message
es visible fuera de su alcance respectivo, que serían los corchetes circundantes {}
en este caso.
Podría decir: “Pero una variable llamada mensaje se define de cualquier manera, por lo que el mensaje es definido después de la if
“.
Pero estarías equivocado.
Java no tiene free()
o delete
operadores, por lo que tiene que depender del seguimiento del alcance de la variable para averiguar cuándo las variables ya no se utilizan (junto con las referencias a estas variables de causa).
Es especialmente malo si pensabas que hiciste algo bueno. He visto este tipo de error después de “optimizar” un código como este:
if(somethingIsTrue()) {
String message = "Everything is fine";
System.out.println(message);
} else {
String message = "We have an error";
System.out.println(message);
}
“Oh, hay código duplicado, saquemos esa línea común” -> y ahí está.
La forma más común de lidiar con este tipo de problema de alcance sería preasignar los valores else a los nombres de las variables en el alcance externo y luego reasignar si:
String message = "We have an error";
if(somethingIsTrue()) {
message = "Everything is fine";
}
System.out.println(message);