[java] “기호를 찾을 수 없음”또는 “기호를 확인할 수 없음”오류는 무엇을 의미합니까?

“기호를 찾을 수 없음”및 “기호를 확인할 수 없음”오류에 대해 다음을 설명하십시오.

  • 그들은 무엇을 의미합니까?
  • 어떤 일이 그들을 일으킬 수 있습니까?
  • 프로그래머는 그것들을 어떻게 고치나요?

이 질문은 Java에서 이러한 일반적인 컴파일 오류에 대한 포괄적 인 Q & A를 제공하기 위해 고안되었습니다.



답변

0. 두 오류간에 차이가 있습니까?

실제로는 아닙니다. “기호를 찾을 수 없습니다”와 “기호를 확인할 수 없습니다”는 같은 의미입니다. 일부 Java 컴파일러는 하나의 문구를 사용하고 일부는 다른 문구를 사용합니다.

1. “기호를 찾을 수 없음”오류는 무엇을 의미합니까?

먼저 컴파일 오류 1 입니다. 그것은 것을 의미 중 하나를 자바 소스 코드에 문제가, 또는 당신이 그것을 컴파일하는 방식에 문제가있다.

Java 소스 코드는 다음으로 구성됩니다.

  • 키워드 : 같은 true, false, class, while, 등.
  • 리터럴 : like 42and 'X'and "Hi mum!".
  • 연산자 및 기타 영숫자가 아닌 토큰 (예 : +,, ={)
  • 식별자 : 같은 Reader, i, toString,processEquibalancedElephants , 등.
  • 주석과 공백.

“심볼을 찾을 수 없음”오류는 식별자에 관한 것입니다. 코드가 컴파일되면 컴파일러는 코드의 각 식별자가 의미하는 바를 해결해야합니다.

“기호를 찾을 수 없음”오류는 컴파일러가이를 수행 할 수 없음을 의미합니다. 코드가 컴파일러가 이해하지 못하는 것을 나타내는 것으로 보입니다.

2. “기호를 찾을 수 없음”오류의 원인은 무엇입니까?

첫 번째 주문은 원인이 하나뿐입니다. 컴파일러는 식별자 정의 해야하는 모든 위치를 조사했지만 정의를 찾을 수 없습니다. 여러 가지가 원인 일 수 있습니다. 일반적인 것은 다음과 같습니다.

  • 일반적으로 식별자의 경우 :
    • 아마도 당신은 이름의 철자를 잘못 입력했을 것입니다; 즉 StringBiulder대신StringBuilder . Java는 잘못된 철자 나 타이핑 오류를 보상하려고 시도하지 않습니다.
    • 아마도 당신은 사건이 잘못되었을 것입니다. 즉 stringBuilder대신 StringBuilder. 모든 Java 식별자는 대소 문자를 구분합니다.
    • 아마도 밑줄을 부적절하게 사용했을 것입니다. 즉 mystring와는 my_string다르다. (자바 스타일 규칙을 고수하면이 실수로부터 크게 보호됩니다 …)
    • 아마도 당신은 “다른 곳”으로 선언 된 것을 사용하려고 할 것입니다. 즉, 컴파일러가 암시 적으로 보도록 지시 한 다른 컨텍스트에서. (다른 클래스? 다른 범위? 다른 패키지? 다른 코드 기반?)
  • 변수를 참조해야하는 식별자 :
    • 변수 선언을 잊었을 수 있습니다.
    • 아마도 변수 선언이 사용하려고 한 시점에서 범위를 벗어났습니다. (아래 예 참조)
  • 메소드 또는 필드 이름이어야하는 식별자의 경우 :

    • 부모 / 조상 클래스 나 인터페이스에서 선언되지 않은 상속 된 메서드 나 필드를 참조하려고 시도했을 수 있습니다.
    • 사용중인 유형에 존재하지 않는 (즉, 선언되지 않은) 메소드 또는 필드를 참조하려고합니다. 예를 들어 "someString".push()2 .
    • 아마도 메소드를 필드로 사용하려고하거나 그 반대의 경우도 있습니다. 예를 들어 "someString".length또는 someArray.length().
    • 아마도 배열 요소가 아닌 배열에서 실수로 작동하고있을 것입니다. 예 :

      String strings[] = ...
      if (strings.charAt(3)) { ... }
      // maybe that should be 'strings[0].charAt(3)'
  • 클래스 이름이어야하는 식별자의 경우 :

    • 클래스를 가져 오는 것을 잊었을 수 있습니다.
    • “star”가져 오기를 사용했지만 가져온 패키지에 클래스가 정의되어 있지 않습니다.
    • 아마도 당신은 다음 new과 같이 a를 잊어 버렸습니다 .

      String s = String();  // should be 'new String()'
  • 유형 또는 인스턴스에 예상 한 멤버가없는 것으로 보이는 경우 :

    • 아마도 사용하려는 유형 을 가리는 중첩 클래스 또는 일반 매개 변수를 선언했을 것 입니다.
    • 아마도 당신은 정적 변수 나 인스턴스 변수를 가리고있을 것입니다.
    • 아마도 잘못된 유형을 가져 왔을 것입니다. 예를 들어 IDE 완료 또는 자동 수정으로 인해.
    • 아마도 잘못된 버전의 API를 사용하고 있습니다 (컴파일).
    • 아마도 객체를 적절한 서브 클래스로 캐스팅하는 것을 잊었을 것입니다.

문제는 종종 위의 조합입니다. 예를 들어, “star”를 가져 와서 클래스가 아닌 … java.io.*를 사용하려고했습니다 . 아니면 당신이 쓰는 의미 하는 … 입니다 클래스가에 .Filesjava.niojava.ioFilejava.io


잘못된 변수 범위 지정으로 인해 “기호를 찾을 수 없음”오류가 발생하는 예는 다음과 같습니다.

List<String> strings = ...

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

명령문 i에서 “기호를 찾을 수 없음”오류가 발생 if합니다. 우리가 이전에 선언했지만 i, 그 선언은 진술과 그 본문에 대해서만 적용 됩니다 for. 에 대한 참조 iif문을 볼 수 의 선언 i. 그것은이다 범위 밖으로 .

(여기서 if루프 내에서 명령문 을 이동 하거나 루프 i시작 전에 선언 하는 것이 적절할 수 있습니다 .)


다음은 오타가 설명 할 수없는 “기호를 찾을 수 없음”오류로 이어지는 당황스러운 예입니다.

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

println호출 에서 i찾을 수 없다는 컴파일 오류가 발생합니다 . 그러나 나는 당신이 그것을 선언했다!

문제는 이전의 부적절한 세미콜론 ( ;) {입니다. Java 언어 구문은 해당 컨텍스트에서 세미콜론을 빈 명령문으로 정의합니다 . 그런 다음 빈 명령문은 for루프 의 본문이됩니다 . 그래서 그 코드는 실제로 이것을 의미합니다 :

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

// The previous and following are separate statements!!

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

{ ... }블록의 몸이 아니다 for루프, 그리고 따라서 이전 선언 ifor문이 범위를 벗어나 블록에.


다음은 오타로 인한 “기호를 찾을 수 없음”오류의 다른 예입니다.

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

이전의 선언에도 불구하고, tmptmp(...)표현은 잘못된 것입니다. 컴파일러는이라는 메소드를 tmp찾고 찾지 않습니다. 이전에 선언 된 tmp것은 메서드의 네임 스페이스가 아니라 변수의 네임 스페이스에 있습니다.

내가 본 예제에서 프로그래머는 실제로 연산자를 생략했습니다. 그가 쓰려고 한 것은 이것입니다.

int res = tmp * (a + b);

명령 행에서 컴파일하는 경우 컴파일러가 기호를 찾지 못하는 또 다른 이유가 있습니다. 다른 클래스를 컴파일하거나 다시 컴파일하는 것을 잊었을 수 있습니다. 예를 들어, 클래스가 Foo있고 Barwhere가 Foo사용 되는 경우 Bar. 컴파일 한 적이없고 Bar실행 javac Foo.java한 경우 컴파일러가 심볼을 찾을 수 없다는 것을 알게 Bar됩니다. 간단한 대답은 컴파일 Foo하고 Bar함께하는 것입니다. 예를 들어 javac Foo.java Bar.java또는 javac *.java. 또는 여전히 Java 빌드 도구를 사용하는 것이 좋습니다. 예를 들어 Ant, Maven, Gradle 등.

다른 더 모호한 원인도 있습니다 … 아래에서 다루겠습니다.

3.이 오류를 어떻게 해결합니까?

일반적으로 컴파일 오류의 원인 을 파악하여 시작합니다 .

  • 컴파일 오류 메시지로 표시된 파일의 행을보십시오.
  • 오류 메시지가 말하는 기호를 식별하십시오.
  • 그림 밖으로 이유는 컴파일러가 심볼을 찾을 수없는 것을 말하고, 위 참조!

그럼 당신은 생각 코드를 말하는 것으로 예상되는 것에 대해. 그런 다음 마지막으로 원하는 것을 수행하기 위해 소스 코드를 수정해야하는 문제를 해결합니다.

모든 “수정”이 올바른 것은 아닙니다. 이걸 고려하세요:

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

컴파일러에 대해 “기호를 찾을 수 없음”이라고 가정합니다 j. 내가 “수정”할 수있는 방법은 여러 가지가 있습니다.

  • 내부 for를 바꿀 수 있습니다 for (int j = 1; j < 10; j++)-아마도 맞습니다.
  • 나는에 대한 선언을 추가 할 수 있습니다 j 전에 내부 for루프, 또는 외부for 루프 .
  • 내가 바꿀 수 ji내부에서 for루프 – 잘못된 아마!
  • 등등.

요점은 당신이 있다는 것입니다 필요한 코드가 올바른 수정을 찾기 위해 어떻게 노력하고 이해하는.

4. 모호한 원인

다음은 “심볼을 찾을 수 없음”이 더 이상 보이지 않을 때까지 설명 할 수없는 몇 가지 경우입니다.

  1. 잘못된 종속성 : 빌드 경로 및 프로젝트 종속성을 관리하는 IDE 또는 빌드 도구를 사용하는 경우 종속성에 실수가있을 수 있습니다. 예를 들어 종속성을 제거하거나 잘못된 버전을 선택했습니다. 빌드 도구 (Ant, Maven, Gradle 등)를 사용하는 경우 프로젝트의 빌드 파일을 확인하십시오. IDE를 사용하는 경우 프로젝트의 빌드 경로 구성을 확인하십시오.

  2. 재 컴파일 하지 않는 경우 : 새로운 Java 프로그래머가 Java 툴 체인의 작동 방식을 이해하지 못하거나 반복 가능한 “빌드 프로세스”를 구현하지 않은 경우가 있습니다. 예를 들어 IDE, Ant, Maven, Gradle 등을 사용합니다. 이러한 상황에서 프로그래머가되는 환상 오류를 찾고 자신의 꼬리를 쫓는 끝낼 수 실제로 제대로 코드를 재 컴파일하지 않음으로써 발생하는 등 …

  3. 초기 빌드 문제 : 클래스가 누락 된 JAR 파일을 제공하는 방식으로 이전 빌드가 실패했을 수 있습니다. 빌드 도구를 사용하는 경우 일반적으로 이러한 실패가 나타납니다. 그러나 다른 사람으로부터 JAR ​​파일을 얻는 경우 파일을 올바르게 빌드하고 오류를 확인 하는 데 의존 합니다. 의심되는 경우 tar -tvf의심스러운 JAR 파일의 내용을 나열하는 데 사용 하십시오.

  4. IDE 문제 : 사람들은 IDE가 혼란스러워 IDE의 컴파일러가 존재하는 클래스를 찾을 수없는 경우 또는 반대 상황을보고했습니다.

    • IDE가 잘못된 JDK 버전으로 구성된 경우 발생할 수 있습니다.

    • IDE의 캐시가 파일 시스템과 동기화되지 않으면 이런 일이 발생할 수 있습니다. 이를 해결하는 IDE 특정 방법이 있습니다.

    • 이것은 IDE 버그 일 수 있습니다. 예를 들어 @Joel Costigliola는 Eclipse가 Maven “테스트”트리를 올바르게 처리하지 않는 시나리오를 설명합니다 ( 이 답변 참조) .

  5. Android 문제 : Android 용 으로 프로그래밍 할 때와 관련된 “기호를 찾을 수 없습니다”오류가 발생 R하면 R기호가 context.xml파일에 의해 정의 된다는 점에 유의 하십시오. 당신 있는지 확인 context.xml파일이 정확하고 올바른 위치에 있고, 대응하는 R클래스 파일이 생성 된 / 컴파일. Java 기호는 대소 문자를 구분하므로 해당 XML ID도 대소 문자를 구분합니다.

    Android의 다른 기호 오류는 이전에 언급 한 이유 때문일 수 있습니다. 예 : 누락되거나 잘못된 종속성, 잘못된 패키지 이름, 특정 API 버전에 존재하지 않는 메소드 또는 필드, 철자 / 입력 오류 등

  6. 시스템 클래스 재정의 : 컴파일러 substring가 다음과 같은 알 수없는 기호 라고 불평하는 경우를 보았습니다.

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

    프로그래머가 자신의 버전을 String만들고 클래스 버전이 substring메소드를 정의하지 않은 것으로 나타났습니다 .

    레슨 : 공통 라이브러리 클래스와 이름이 같은 클래스를 직접 정의하지 마십시오!

  7. 호모 글리프 : 당신이 당신의 소스 파일을 UTF-8 인코딩을 사용하는 경우,이 식별자를 가질 수 있습니다 보면 같은, 그러나 호모 글리프 포함되어 있기 때문에 사실 다른에 있습니다. 자세한 내용은 이 페이지 를 참조하십시오.

    소스 파일 인코딩으로 ASCII 또는 Latin-1로 제한 \uxxxx하고 다른 문자에 Java 이스케이프를 사용하면이를 피할 수 있습니다 .


1 – 경우, 아마, 당신은 다음 중 하나를 사용하면 컴파일 오류와 실행 코드로 IDE를 구성하거나 응용 프로그램이 실행시에 .. 생성하고 코드를 컴파일, 런타임 예외 또는 오류 메시지에이를 참조하십시오.

2-토목 공학의 세 가지 기본 원칙 : 물이 오르막으로 흐르지 않고 널빤지가 더 강해져 끈을 밀 수 없습니다 .


답변

다음을 잊어 버린 경우에도이 오류가 발생합니다 new.

String s = String();

String s = new String();

new키워드가 String없는 호출 은 인수없이 호출 된 (로컬) 메소드를 찾으려고 시도 하므로 해당 메소드 서명이 정의되지 않았을 수 있습니다.


답변

‘가변이 범위를 벗어났습니다’의 또 다른 예

내가 몇 번이나 그런 종류의 질문을 보았 듯이, 그것이 기분좋지 않더라도 불법적 인 것에 대한 또 다른 예일 입니다.

이 코드를 고려하십시오.

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

유효하지 않은 코드입니다. 명명 된 변수 중 어느 것도 message해당 범위 밖에서 볼 수 없기 {}때문에이 경우 주변 괄호가 됩니다.

“하지만 message라는 변수는 어느 쪽이든 정의되어 있으므로 메시지 if ” 뒤에 정의됩니다 .

그러나 당신은 틀릴 것입니다.

Java에는 free()또는 delete연산자 가 없으므로 변수가 더 이상 사용되지 않는시기를 찾으려면 변수 범위를 추적해야합니다 (이러한 원인 변수에 대한 참조와 함께).

좋은 일을했다고 생각하면 특히 나쁩니다. 다음과 같은 코드를 “최적화”한 후에 이런 종류의 오류가 발생했습니다.

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

“오, 중복 된 코드가 있습니다. 공통 라인을 뽑아 봅시다”-> 그리고 거기에 있습니다.

이러한 종류의 범위 문제를 처리하는 가장 일반적인 방법은 else-values를 외부 범위의 변수 이름에 미리 할당 한 다음 다음과 같은 경우에 다시 할당하는 것입니다.

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


답변

이클립스 에서이 오류를 얻는 한 가지 방법 :

  1. 에 클래스 A를 정의하십시오 src/test/java.
  2. class 를 사용하는 다른 클래스 B를 정의하십시오 .src/main/javaA

결과 : Eclipse는 코드를 컴파일하지만 maven은 “기호를 찾을 수 없음”을 표시합니다.

기본 원인 : Eclipse는 기본 트리와 테스트 트리에 대해 빌드 경로를 결합하여 사용합니다. 불행히도 Maven이 요구하는 Eclipse 프로젝트의 다른 부분에 대해 다른 빌드 경로 사용을 지원하지 않습니다.

해결책 :

  1. 그런 식으로 의존성을 정의하지 마십시오. 즉,이 실수를하지 마십시오.
  2. Maven을 사용하여 정기적으로 코드베이스를 구축하여이 실수를 조기에 해결하십시오. 이를 수행하는 한 가지 방법은 CI 서버를 사용하는 것입니다.

답변

“찾을 수 없음”은 적절한 변수, 메소드, 클래스 등을 찾을 수없는 컴파일러를 의미합니다. 오류 마사지를 받으면 먼저 오류 마사지를받는 코드 줄을 찾으십시오. 사용하기 전에 정의하지 않은 변수, 메소드 또는 클래스를 찾을 수 있습니다. 확인 후 해당 변수, 메소드 또는 클래스를 초기화 한 후 나중에 요구할 수 있습니다 … 다음 예제를 고려하십시오.

데모 클래스를 만들고 이름을 인쇄하겠습니다.

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

이제 결과를보십시오 ..

여기에 이미지 설명을 입력하십시오

“변수 이름을 찾을 수 없습니다”라는 오류가 표시됩니다.

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

             String name="smith";

             System.out.print(name);
      }
}

이제 새로운 출력을보십시오 …

여기에 이미지 설명을 입력하십시오

Ok는 성공적으로 그 에러를 해결했다.


답변

IDE에서 모든 것이 완벽하다고 말하면서 빌드 에서이 오류가 발생하면 두 곳에서 동일한 Java 버전을 사용하고 있는지 확인하십시오.

예를 들어, Java 7과 Java 8의 API는 서로 다르므로 이전 Java 버전에서 존재하지 않는 API를 호출하면이 오류가 발생합니다.


답변

나도이 오류가 발생했습니다. (내가 Google에 접속하여이 페이지로 연결됨)

문제점 : 다른 프로젝트 B에 정의 된 클래스에서 프로젝트 A의 클래스에 정의 된 정적 메소드를 호출했습니다. 다음 오류가 발생했습니다.

error: cannot find symbol

솔루션 : 먼저 메소드가 정의 된 프로젝트를 빌드 한 다음 메소드가 호출 된 프로젝트를 빌드하여이 문제를 해결했습니다.