Java >> Java tutorial >  >> Java

Kompilationsfejlen "Kan ikke finde symbol" i Java

Når en bruger henviser til en variabel, der ikke er blevet erklæret i applikationen, opstår fejlen "kan ikke finde symbol". For at sige det på en anden måde, er compileren ikke opmærksom på variablens erklæring. For eksempel:

class HelloCodeunderscored {
    public static void main( String args[] ) {
      int x = 15;
      int y =1 4;
      // result is not declared. It will show an error.
      result = x * y;
    }
}

Hvad er mulige løsninger på dette problem?

Hvis du nogensinde støder på dette problem, bør du gennemgå koden for følgende scenarier:

  • Sørg for, at du har erklæret variablen, for eksempel int i =15;. Hvis int ikke er skrevet, vises fejlen muligvis.
  • Se også, om den definerede variabel er uden for koden, for eksempel hvis den ikke er medlem af HelloCodeunderscored-klassen.
  • Sørg for, at du bruger den rigtige sag. Hvis du erklærer en variabel som var, men får adgang til den som Var, er det et eksempel på et sådant scenario.
  • Tal, dollartegn og bindestreger er ikke tilladt i identifikationsværdier; tjek efter dem.

Fejl i kompileringstid

Kompileren undersøger og tjekker koden for forskellige ting under kompileringen, herunder referencetyper, typeafstøbninger og metodedeklarationer, for at nævne nogle få. Denne fase af kompileringsprocessen er afgørende, da det er her, vi støder på en kompileringsfejl.

Fejl ved kompilering kan opdeles i tre kategorier:

Syntaksfejl

En af de mest almindelige programmeringsfejl er at undlade at bruge et semikolon i slutningen af ​​en sætning; andre typiske fejl omfatter at glemme importer, uoverensstemmelser i parenteser og udeladelse af returneringserklæringen.

Typekontrolfejl

Dette er en metode til at sikre, at vores kode er typesikker. Med denne kontrol sørger vi for, at typerne af udtryk er konsistente. Hvis vi definerer en variabel af typen int, bør vi aldrig tildele en værdi af typen double eller String til den.

Compileren vil gå ned

I mellemtiden er der en chance for, at compileren vil gå ned. Det er usædvanligt ualmindeligt, men det sker. I dette scenarie er det godt at vide, at problemet ikke er med vores kode, men med noget andet.

Kompilere følger et sæt regler, der er specifikke for hvert sprog. Hvis en kode ikke følger disse krav, vil compileren ikke være i stand til at konvertere den, hvilket resulterer i en kompileringsfejl. Nøglen til at løse kompileringsproblemet "Kan ikke finde symbol" er at finde ud af, hvad der forårsager det.

Vi kan udlede den kodelinje, hvor problemet opstod, og hvilket element der er forkert, fra fejlmeddelelsen. At kende de mest almindelige årsager til denne fejl vil gøre det nemmere og hurtigere at løse.

Symboltabeller:En oversigt

Kompilere konstruerer og vedligeholder symboltabeller, som er væsentlige datastrukturer til lagring af information relateret til identifikatorer i kildekoden. Disse oplysninger placeres i symboltabeller under leksikalsk og syntaktisk analyse og bruges efterfølgende i kompileringsprocessen.

Identifikatorerne for klasser, grænseflader, variabler og metoder er bundet til at svare til indgange i symboltabellerne, når deklarationerne behandles. Når disse identifikatorer vises i kildekoden, slår compileren dem op i symboltabellerne. Den bruger denne information til at bekræfte, at en variabel er blevet erklæret, etablere variablens omfang og udføre typekontrol for at sikre, at et udtryk er semantisk korrekt.

Symboltabeller bruges også til oprettelse og optimering af kode. Det følgende er en forenklet repræsentation af en symboltabelpost (eller blot et symbol) i Java:

<symbol name (identifier), type, scope, [attributes]>

Den sammenlignelige notation for en global variabelerklæring, såsom endelig dobbeltforhold, ville være .

Fejl:Kan ikke finde symbol

Som navnet antyder, refererer fejlen ikke til at finde symbol til et symbol, som du ikke kan finde. Selvom der er en række forskellige årsager til dette, bunder de alle sammen til, at Java-kompileren ikke er i stand til at finde symbolet, der er forbundet med en given identifikator.

Yderligere to felter er inkluderet i compilerens meddelelse for fejlen kan ikke finde symbol:

"symbol" refererer til navnet og typen af ​​den refererede identifikator. På den anden side henviser "placering" til den klasse, hvor identifikatoren bruges.

Hvad forårsager fejlen, at symbolet ikke kan findes?

Følgende er de mest typiske årsager til, at symbolet ikke kan finde kompileringstidsfejl:

  • Variabel- og metodeerklæringer mangler,
  • Referencer til variabler og metoder, der er uden for rækkevidde
  • fejlstavede identifikatorer, og
  • udeladte importerklæringer.

Symbol ikke fundet vs. Kan ikke finde symbol vs. Kan ikke løse symbol

Problemet med kan ikke finde symboler kan også opstå under ordene symbol ikke fundet og kan ikke løse symbolet, da forskellige Java-kompilere bruger noget forskellig ordlyd. Bortset fra navnene er der ingen forskel mellem betydningen af ​​disse sætninger.

Eksempler på "Kan ikke finde symbolfejl."

Nogle af disse "Kan ikke finde symbolfejl" er som følger:

Håndtering af en ikke-deklareret variabel

Fejlen kan ikke finde symbolet opstår, når Java-kompileren støder på en identifikator, som den ikke kan finde i symboltabellen. Som følge heraf er den mest almindelige årsag til denne fejl, når der laves en reference til en ikke-erklæret variabel. I modsætning til nogle andre sprog, som ikke kræver eksplicitte variabeldeklarationer eller måske gør det muligt at deklarere en variabel, efter at den er blevet refereret (gennem hejsning ), kræver Java, at en variabel deklareres, før den bruges eller refereres til i nogen form.

Figur (a) viser, hvordan en udeklareret variabel, i dette tilfælde identifikationsgennemsnittet på linje 9, forårsager to tilfælde af, at symbolfejlen ikke kan finde på kodens placeringer. Figur (b) løser problemet ved at erklære denne variabel med dens datatype (eller udlede dens art med var nøgleordet i Java 10+).

Figur (a)

package codeunderscored;

public class CodeUndeclaredVariable {
    public static void main(String... args) {
        int x = 16;
        int y = 20;
        int z = 42;

        averageResults = (x + y + z) / 3.0; // averageResults is not declared
        System.out.println(averageResults);
    }
}

Figur (b)

package codeunderscored;

public class UndeclaredVariable {
    public static void main(String... args) {
        int x = 16;
        int y = 20;
        int z = 42;

        double averageResults = (x + y + z) / 3.0;
        System.out.println(averageResults);
    }
}

Håndtering af en variabel uden for rækkevidde

Compileren kaster fejlen kan ikke finde symbol, når en Java-applikation forsøger at få adgang til en variabel, der er erklæret i et separat (ikke-nedarvet eller ikke-overlappende) omfang. Bestræbelserne på at forsøge at få adgang til den variable tæller på linje 17 og 18 i figur (a), som kun er tilgængelig i erklæringen erklæret på linje 11, viser dette. Figur (b) viser, at flytning af tællervariablen uden for for-løkken løser problemet.

Figur (a)

package codeunderscored;

import java.util.Arrays;
import java.util.List;

public class CodeOutOfScopeVariable {
    public static void main(String... args) {
        final List<String> strings = Arrays.asList("Hello", "Codeunderscored");
        final String searchFor = "Codeunderscored";

        for (int counter = 0; counter < strings.size(); counter++) {
            if (strings.get(counter).equals(searchFor)) {
                break;
            }
        }

        if (counter < strings.size()) {
            System.out.println("The word " + searchFor + " was found at index " +    counter);
        } else {
            System.out.println("The word " + searchFor + " wasn't found");
        }
    }
}

Figur (b)

package codeunderscored;

import java.util.Arrays;
import java.util.List;

public class CodeOutOfScopeVariable {
    public static void main(String... args) {
        final List<String> strings = Arrays.asList("Hello", "Codeunderscored");
        final String searchFor = "Codeunderscored";
        int counter;

        for (counter = 0; counter < strings.size(); counter++) {
            if (strings.get(counter).equals(searchFor)) {
                break;
            }
        }

        if (counter < strings.size()) {
            System.out.println("The word " + searchFor + " was found at index " + counter);
        } else {
            System.out.println("The word " + searchFor + " wasn't found");
        }
    }
}

Figur (a) &(b):Fejl og opløsning for ikke at kunne opdage et symbol for en variabel uden for rækkevidde.

Metodenavn stavet forkert

En fejl, der ikke kan finde symbol, skyldes stavefejl af en eksisterende metode eller en gyldig identifikator. Fordi Java-id'er er store og små bogstaver, vil enhver ændring af en eksisterende variabel, metode, klasse, grænseflade eller pakkenavn, som vist i figur (b), resultere i denne fejl.

Figur (a)

package codeunderscored;

public class CodeMisspelledMethodName {

    static int fibonacci(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        return fibonacci(n - 1) + fibonacci(n - 2);
    }

    public static void main(String... args) {
        int fibResult = Fibonacci(20); // Fibonacci ≠ fibonacci
        System.out.println(fibResult);
    }
}

Figur (b)

package codeunderscored;

public class CodeMisspelledMethodName {
    static int fibonacci(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        return fibonacci(n - 1) + fibonacci(n - 2);
    }

    public static void main(String... args) {
        int fibResult = fibonacci(20);
        System.out.println(fibResult);
    }
}

Fejlfigur (a) og løsning Figur (b):Kan ikke finde symbolet for et forkert stavet metodenavn

Der mangler en importerklæring

Brug af klasser, hvad enten det er fra Java-platformen eller et bibliotek, kræver korrekt import af dem ved hjælp af import-sætningen. Hvis du ikke gør det, vil Java-kompileren klage over et symbol, der ikke kan findes. Java.util-pakken bruges i kodeeksemplet i figur (a). Problemet med symbolet kan ikke lokaliseres, fordi listeklassen blev oprettet uden at angive den nødvendige import. Problemet løses ved at tilføje den manglende importerklæringslinje 4 i figur (b).

Figur (a)

package codeunderscored;

import java.util.Arrays;

public class CodeMissingImportList {
    private static final List<String> CONSTANTS = Arrays.asList("A", "B", "C");

    public static void main(String... args) {
        System.out.println(CONSTANTS);
    }
}

Figur (b)

package codeunderscored;

import java.util.Arrays;
import java.util.List;

public class CodeMissingImportList {
    private static final List<String> CONSTANTS = Arrays.asList("A", "B", "C");

    public static void main(String... args) {
        System.out.println(CONSTANTS);
    }
}

Figur (a) Fejl og løsning (b):Kan ikke finde symbolet for manglende import

Eksempler, der ikke er så almindelige

Den grundlæggende årsag til Java-fejlen kan ikke lokalisere symbolet, som nogle gange findes i uventede eller skjulte områder. Det er tilfældet, når en sætning afsluttes for tidligt af et utilsigtet semikolon, figur (a), eller når objektoprettelse forsøges uden en korrekt konstruktorankaldelse, som skal indeholde det nye nøgleord, figur 6.

Figur (a)

package codeunderscored;

public class CodeLoopScope {

public static void main(String... args) {
        int start = 1, end = 10;
        for (int i = start; i <= end; i++); {
            System.out.print(i == end ? i : i + ", ");
        }
    }
}

Figur (b)

package codeunderscored;

public class CodeLoopScope {
    public static void main(String... args) {
        int start = 1, end = 10;
        for (int i = start; i <= end; i++) {
            System.out.print(i == end ? i : i + ", ");
        }
    }
}

Ude af stand til at finde et symbol for en for tidligt stoppet sløjfe Figur (a) fejl og figur (b) opløsning

Figur (a)

package codeunderscored;

public class CodeObjectCreation {
    public static void main(String... args) {
        String s = String("Hello Codeunderscored!");
        System.out.println(s);
    }
}

Figur (b)

package codeunderscored;

public class CodeObjectCreation {
    public static void main(String... args) {
        String s = new String("Hello Codeunderscored!");
        System.out.println(s);
    }
}

Figur (a) Fejl og Figur (b) Opløsning for kan ikke finde symbolkonstruktøropkald

Andre årsager til problemet "kan ikke finde symbol" omfatter:

Her er et par tilfælde, hvor "Kan ikke registrere symbol" forekommer uforklarligt, indtil du undersøger nærmere.

Umulighed for at finde symbolet 'var':

Du forsøger formentlig at kompilere kildekode med en ældre compiler eller et ældre kildeniveau, der anvender lokal variabeltypeinferens (dvs. en var-erklæring). I Java 10 blev varen introduceret. Tjek din JDK-version, build-filer og IDE-indstillinger (hvis dette sker i en IDE).

Du kompilerer eller genkompilerer ikke noget

Nye Java-programmører forstår af og til ikke, hvordan Java-værktøjskæden fungerer, eller har ikke opsat en gentagelig "byggeproces", såsom at bruge en IDE, Ant, Maven, Gradle osv. I dette tilfælde kan programmøren ende med at jagte hans hale, på udkig efter en imaginær fejl, der er forårsaget af ukorrekt genkompilering af koden, og så videre.

Et andet eksempel er, når du kompilerer og kører en klasse med (Java 9+) java SomeClass.java. Du vil sandsynligvis få "Kan ikke løse symbol"-fejl, der henviser til 2. klasse, hvis klassen afhænger af en anden klasse, som du ikke har kompileret (eller genkompileret). De andre kildefiler kompileres ikke automatisk. Derudover er den nye "kompiler og udfør"-tilstand for java-kommandoen ikke egnet til at starte programmer med flere kildekodefiler.

Forkerte afhængigheder

Hvis du bruger en IDE eller et byggeværktøj, der administrerer byggestien og projektafhængigheder, har du muligvis lavet en fejl med afhængighederne; for eksempel kan du have udeladt en afhængighed eller valgt den forkerte version. Tjek projektets byggefil, hvis du bruger et byggeværktøj (Ant, Maven, Gradle osv.). Undersøg yderligere projektets byggestiopsætning, hvis du bruger en IDE.

Et problem med en tidligere build

Det er muligt, at en tidligere build mislykkedes, så en JAR-fil blev oprettet med manglende klasser. Du ville normalt bemærke en sådan fejl, hvis du brugte et byggeværktøj. Hvis du erhverver JAR-filer fra en anden, bliver du nødt til at stole på, at de konstruerer korrekt og fanger fejl.

Brug tar -tvf, når du har brug for at liste indholdet af de formodede JAR-filer, hvis du har mistanke om dette.

Problemer med Android

Når du programmerer til Android og ser "Kan ikke opdage symbol"-problemer knyttet til R, skal du huske på, at filen context.xml definerer R-symbolerne. Kontroller, at din context.xml-fil er gyldig og på den rigtige placering, og at R-klassefilen til den er blevet genereret og kompileret. Fordi Java-symboler skelner mellem store og små bogstaver, er de tilsvarende XML-id'er også det.

Andre symbolproblemer på Android er oftest forårsaget af ovennævnte faktorer, såsom manglende eller unøjagtige afhængigheder, forkerte pakkenavne, metoder eller felter, der ikke findes i en specifik API-version, stave-/indtastningsproblemer og så videre.

Problemer med IDE

Folk har rapporteret tilfælde, hvor deres IDE bliver forvirret, og compileren i IDE'en kan ikke registrere en klasse, der allerede eksisterer ... eller omvendt. Hvis IDE er sat op med den forkerte JDK-version, kan det ske.

Hvis IDE's caches bliver ude af synkronisering med filsystemet, kan det ske.

Der findes IDE-specifikke løsninger til dette. Sidstnævnte kan være et problem i IDE. For eksempel er der et typisk tilfælde af, hvordan Eclipse forkert håndterede et Maven "test" træ. Den særlige fejl, ser det ud til, blev rettet for lang tid siden.

Homoglyffer

Det er muligt at have identifikatorer, der ser ens ud, men er det ikke, fordi de indeholder homoglyffer, hvis du bruger UTF-8-kodning til dine kildefiler. Du kan omgå dette ved at begrænse kildefilens kodning til ASCII eller Latin-1 og bruge Java \uxxxx escapes til yderligere tegn.

Skjulte systemklasser

Vi har set situationer, hvor compileren klager over, at understrengen er et ukendt symbol, såsom dette.

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

Det viser sig, at programmøren havde skrevet deres version af String, som manglede substring-operationer. Det er blevet gjort med System, Scanner og andre klasser tidligere.

Generelt, brug ikke de samme navne som almindelige biblioteksklasser, når du definerer dine klasser! Du kan også bruge fuldt kvalificerede navne til at afhjælpe situationen. I det foregående eksempel kan programmøren have skrevet:

java.lang.String s = ...

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

Hvad skal jeg gøre ved disse fejl?

  • Generelt bør du starte med at bestemme, hvad der udløste kompileringsfejlen.
  • Undersøg linjen i filen, som kompileringsfejlmeddelelsen henviser til.
  • Afgør, hvilket symbol fejlmeddelelsen henviser til.
  • Find ud af, hvorfor compileren siger, at den ikke kan finde symbolet; tjek afsnittet ovenfor!
  • Så overvejer du, hvad din kode forsøger at kommunikere.
  • Prøv derefter at finde ud af, hvilke ændringer du skal foretage i din kildekode for at få den til at gøre, hvad du vil.

Det er værd at bemærke, at ikke enhver "korrektion" er nøjagtig. Overvej følgende:

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

Antag, at compileren siger for j, "Kan ikke finde symbol." Der er flere måder, vi kan "rette" dette på:

  • Vi formoder, at vi kunne redigere den indre for to for (int j =1; j<10; j++) – hvilket ville være korrekt.
  • Alternativt kunne vi sætte en erklæring for j før den indre eller ydre for sløjfer, hvilket sandsynligvis ville være korrekt.
  • I den indre for-løkke kunne vi også ændre j til i, og det ville være forkert! og så videre. For at finde det rigtige middel, skal du først forstå, hvad din kode forsøger at opnå.

Eksempel:hvordan fejlagtig variabel scoping kan resultere i fejlen "Kan ikke finde symbol"

List<String> stringsVar = ...

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

For i i if-sætningen vil dette resultere i et "Kan ikke finde symbol"-problem. Selvom vi tidligere har erklæret i, gælder det kun for for-erklæringen og dens krop. If-erklæringens henvisning til i kan ikke se den erklæring fra I, fordi den ikke er inden for projektets rammer. En passende rettelse ville være at placere if-sætningen i løkken eller erklære I, før løkken begynder.)

Eksempel:et tilsyneladende mærkeligt "Kan ikke finde symbol"-problem forårsaget af en tastefejl

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

Det vil resultere i en kompileringsfejl i println-kaldet, hvilket indikerer, at i mangler. Men (som du påpeger), vi erklærede det!

Problemet er semikolonet (;), der vises før {. I dette tilfælde er et semikolon en tom sætning i henhold til Java-sprogets syntaks. For-løkkens krop består derfor af det tomme udsagn. Så her er, hvad den kode faktisk betyder:

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

// The previous and following are separate statements!!

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

Den foregående erklæring af i i for-sætningen er uden for rækkevidde i blokken. Det er fordi {...}-blokken ikke er kroppen af ​​for-løkken.

Eksempel:Fejlen "Kan ikke finde symbol" forårsaget af en tastefejl

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

tmp i tmp(...)-sætningen er forkert på trods af den tidligere erklæring. Compileren vil lede efter en tmp-metode, men den vil ikke finde en. Den tidligere angivne tmp er i variablernes navneområde, ikke metodernes navneområde. I et af de eksempler, vi så, havde programmøren glemt at inkludere en operatør. Dette er, hvad han ville skrive:

int res = tmp * (a + b);

Hvis du kompilerer fra kommandolinjen, er der en anden grund til, at compileren muligvis ikke opdager et symbol. Det er muligt, at du lige har forsømt at bygge eller omkompilere en anden klasse.

Antag for eksempel, at du har to klasser, Secondary og Primary, og Secondary bruger Primary. Hvis du aldrig har kompileret Primary før og kørt javac Secondary.java, vil compileren sandsynligvis mislykkes, fordi den ikke kan finde symbolet Primary.

Kompiler Secondary og Primary sammen, for eksempel med javac Secondary.java Primary.java eller javac *.java. Endnu bedre, brug et Java-byggeværktøj som Ant, Maven, Gradle osv.

Konklusion

Symbolet kan ikke finde symbolet, også kendt som et symbol ikke fundet og kan ikke løse symbolet, er en Java-kompileringsfejl, der opstår, når compileren ikke kan finde ud af, hvad en identifikator i kildekoden refererer til. Som med enhver anden kompilationsfejl er det vigtigt at finde ud af, hvad der forårsager det, isolere problemet og rette det effektivt.

Denne fejl skyldes hovedsageligt at henvise til ikke-deklarerede variabler og metoder, såsom ved at stave forkert eller undlade at importere deres tilknyttede pakke. Som det fremgår af denne artikel, er det relativt nemt at løse det, når først et problem er blevet identificeret.


Java tag