1. ホーム
  2. java

[解決済み] Cannot find symbol" や "Cannot resolve symbol" というエラーはどういう意味ですか?

2022-03-19 20:48:20

質問

Cannot find symbol"、Cannot resolve symbol"、Symbol not found"エラーについて教えてください(Javaの場合)。

  • これらは何を意味するのですか?
  • どのようなことが原因で起こるのですか?
  • プログラマーはどのように修正するのですか?

この質問は、Javaのこれらの一般的なコンパイルエラーに関する包括的なQ&Aを種明かしするためのものです。

解決方法は?

0. この2つのエラーに違いはあるのでしょうか?

シンボルが見つかりません」、「シンボルを解決できません」、「シンボルが見つかりません」は、すべて同じ意味です。 Javaコンパイラによって、異なる表現が使われています。

1. Cannot find symbol"エラーはどういう意味ですか?

まず第一に、それは コンパイルエラー 1 . という意味です。 どちらか Java のソースコードに問題があります。 または コンパイルの仕方に問題がある。

あなたのJavaのソースコードは、次のようなもので構成されています。

  • キーワード:のような class , while といった具合です。
  • リテラル:以下のような true , false , 42 , 'X'"Hi mum!" .
  • 演算子やその他の非英数字トークン:例えば + , = , { といった具合です。
  • 識別子:以下のようなものです。 Reader , i , toString , processEquibalancedElephants といった具合です。
  • コメントと空白。

Cannot find symbol"エラーは、識別子のことです。 コンパイル時に、コンパイラはコードに含まれる一つ一つの識別子が何を意味するのかを調べる必要があります。

Cannot find symbol"エラーは、コンパイラがこれを実行できないことを意味します。 あなたのコードは、コンパイラが理解できないものを参照しているように見えます。

2. Cannot find symbol"エラーの原因は何ですか?

第一法則として、原因は一つしかありません。 コンパイラは識別子 が必要です。 が定義されているのに、その定義が見つからなかったのです。 これは、いくつかの原因が考えられます。 一般的なものは以下の通りです。

  • 識別子全般について。

    • おそらく名前のスペルが間違っているのでしょう。 StringBiulder ではなく StringBuilder . Javaは、スペルミスやタイプミスを補正することはできませんし、補正しようともしません。
    • おそらく、大文字と小文字を間違えているのでしょう。 stringBuilder ではなく StringBuilder . Java の識別子はすべて大文字と小文字が区別されます。
    • アンダースコアが不適切に使用されている可能性があります。 mystringmy_string が違います。 (Javaのスタイルルールを守れば、この間違いからほぼ守られます.)
    • おそらく、あなたが使おうとしているものは、他の場所で宣言されたもので、コンパイラに暗黙のうちに指示した場所とは異なるコンテキストで宣言されています。 (別のクラス? 異なるスコープ? 別のパッケージ? 別のコードベース?)
  • 変数を参照すべき識別子用。

    • おそらく、変数の宣言を忘れているのでしょう。
    • 使用しようとした時点で、変数宣言がスコープ外になっている可能性があります。 (下記の例参照)
  • メソッド名やフィールド名となるべき識別子の場合。

    • おそらく、親クラスや祖先クラス、インターフェイスで宣言されていない、継承されたメソッドやフィールドを参照しようとしているのでしょう。

    • おそらく、使用している型に存在しない(つまり宣言されていない)メソッドやフィールドを参照しようとしているのでしょう; 例えば "rope".push() 2 .

    • おそらく、メソッドをフィールドとして使用しようとしているか、またはその逆でしょう。 "rope".length または someArray.length() .

    • おそらく、配列の要素ではなく、配列に対して誤って操作しているのでしょう。

          String strings[] = ...
          if (strings.charAt(3)) { ... }
          // maybe that should be 'strings[0].charAt(3)'
      
      
  • クラス名となるべき識別子の場合。

    • おそらく、クラスをインポートするのを忘れているのでしょう。

    • おそらく "star" インポートを使用しましたが、そのクラスはインポートしたどのパッケージでも定義されていないのでしょう。

    • おそらく new というように

          String s = String();  // should be 'new String()'
      
      
  • 型やインスタンスが、期待していたメンバー(メソッドやフィールドなど)を持っていないように見える場合に使用します。

    • ネストされたクラスやジェネリックパラメータを宣言した場合、そのパラメータが シャドウ を使用する予定でした。
    • おそらく、静的変数またはインスタンス変数をシャドウイングしているのでしょう。
    • IDE の補完や自動修正により、間違った型をインポートした可能性があります。 java.awt.List ではなく java.util.List .
    • 間違ったバージョンのAPIを使用している(コンパイルしている)可能性があります。
    • オブジェクトを適切なサブクラスにキャストするのを忘れている可能性があります。
    • 変数の型を、探しているメンバを持つ変数の上位型と宣言している可能性があります。

問題は、多くの場合、上記の組み合わせです。 例えば、次のような場合です。 java.io.* を使用し、その後 Files クラス ... これは java.nio ではなく java.io . あるいは、次のように書くつもりだったのかもしれません。 File ...これは のクラスです。 java.io .


変数のスコープが正しくないと、"Cannot find symbol"エラーになる例を紹介します。

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 ステートメントとそのボディを含む。 への参照は i の中にある if ステートメント 見ることができない という宣言は i . それは 範囲外 .

(ここでの適切な修正点は if ステートメントをループの中に入れるか、あるいは i をループの開始前に指定します)。


タイプミスが原因で、一見不可解な "Cannot find symbol" エラーが発生する、不可解な例を紹介します。

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 ループを使用するため、前の宣言の i の中で for ステートメントは 範囲外 をブロック内で使用します。


以下は、タイプミスが原因の "Cannot find symbol" エラーの別の例です。

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

前の宣言にもかかわらず tmp の中にある tmp(...) 式は誤りです。 コンパイラは tmp ということです。 先に宣言された tmp は、メソッドの名前空間ではなく、変数の名前空間にあります。

私が遭遇した例では、実はプログラマーが演算子を省いていたのです。 彼が書こうとしたのは、こうだ。

int res = tmp * (a + b);


コマンドラインからコンパイルする場合、コンパイラがシンボルを見つけられない理由がもう一つあります。 単に他のクラスをコンパイルし忘れたか、再コンパイルし忘れた可能性があります。 例えば FooBar ここで Foo 用途 Bar . をコンパイルしたことがない場合 Bar を実行すると javac Foo.java というシンボルがコンパイラに見つからないことがあります。 Bar . 簡単な答えは、コンパイルすることです。 FooBar を一緒に使用します。 javac Foo.java Bar.java または javac *.java . あるいは、Ant, Maven, Gradle などのJavaビルドツールを使うのがよいでしょう。

その他にも、もっとわかりにくい原因があるのですが・・・それは後述します。

3. これらのエラーを修正するにはどうすればよいですか?

一般的には、まず最初に、どのような 原因 というコンパイルエラーが発生します。

  • コンパイルエラーのメッセージで示されたファイルの行を見てください。
  • エラーメッセージがどのシンボルについて言っているのかを確認します。
  • 図解 なぜ コンパイラはそのシンボルが見つからないと言っています。

次に 考える あなたのコードが言わんとすることは何なのか。 そして最終的に 自分の望むことを実現するために ソースコードにどんな修正を加えるべきかを考えます。

ただし、すべてのquot;correction"が正しいわけではありません。これを考えてみましょう。

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. 不明確な原因

ここでは、quot;Cannot find symbol"が一見不可解に見えるケースをいくつか紹介します...よく見てみてください。

  1. 不適切な依存関係 : ビルドパスやプロジェクトの依存関係を管理するIDEやビルドツールを使用している場合、依存関係を間違えている可能性があります。例えば、依存関係を省いていたり、間違ったバージョンを選択していたりします。 ビルドツール(Ant、Maven、Gradleなど)を使用している場合、プロジェクトのビルドファイルを確認します。 IDEを使用している場合は、プロジェクトのビルドパスの設定を確認してください。

  2. シンボル 'var' が見つかりません。 : おそらく、ローカル変数の型推論を使用するソースコードをコンパイルしようとしているのでしょう(すなわち var 宣言)を、古いコンパイラや古い --source レベルになります。 また var はJava 10で導入されました。 JDKのバージョンとビルドファイル、そして(IDEで発生した場合)IDEの設定を確認してください。

  3. コンパイル/リコンパイルしていない : 新しいJavaプログラマーが、Javaツールチェーンの仕組みを理解していなかったり、IDE、Ant、Maven、Gradleなどを使って、繰り返し可能なビルドプロセスを実装していなかったりすることがあります。 このような状況では、プログラマーは、以下のような幻のエラーを探しながら、尻尾を巻いてしまうことになります。 実際に リコンパイルがうまくいっていないなど。

    もう一つの例は、(Java 9+)を使用する場合です。 java SomeClass.java を使用してクラスをコンパイルし、実行します。 そのクラスが、コンパイル(または再コンパイル)していない別のクラスに依存している場合、2番目のクラスを参照して "シンボルを解決できない"エラーが発生する可能性があります。 他のソースファイルは自動的にはコンパイルされません。 そのため java コマンドの新しいモードである "compile and run" は、複数のソース・コード・ファイルを持つプログラムを実行するために設計されたものではありません。

  4. 以前のビルドの問題 : 以前のビルドで失敗し、クラスが欠落した JAR ファイルが生成された可能性があります。 このような失敗は、ビルドツールを使っている場合、通常、気づかれるでしょう。 しかし、もしあなたが他の人から JAR ファイルを入手しているのなら、 あなたは それら が正しくビルドされ、エラーに気づくことができます。 もしこれが疑わしい場合は tar -tvf をクリックして、疑わしいJARファイルの内容をリストアップします。

  5. IDEの問題 : IDEが混乱して、IDE内のコンパイラが存在するクラスを見つけられない・・・というケースや、その逆の状況が報告されています。

    • これは、IDEが間違ったJDKのバージョンで構成されている場合に起こる可能性があります。

    • IDE のキャッシュがファイルシステムと同期していない場合に発生する可能性があります。 これを修正するIDE固有の方法があります。

    • これはIDEのバグである可能性があります。 たとえば、@Joel Costigliola は、Eclipse が Maven の "test" ツリーを正しく扱わないというシナリオを説明しました。 この回答を見る . (どうやらその特定のバグはずっと前に修正されているようです)。

  6. Androidの問題点 : Androidでプログラミングをしていて、以下のようなエラーが発生することがあります。 R を使用していることに注意してください。 R シンボルが定義されています。 context.xml ファイルを作成します。 あなたの context.xml ファイルが正しく、正しい場所にあり、対応する R クラスファイルが生成/コンパイルされました。 Java のシンボルは大文字と小文字を区別するので、対応する XML の ID も大文字と小文字を区別することに注意してください。

    Androidにおけるその他のシンボルエラーは、先に述べた理由によるものと思われます。例えば、依存関係の欠如や不正確なパッケージ名、特定のAPIバージョンに存在しないメソッドやフィールド、スペルミスやタイピングエラーなどです。

  7. システムクラスの非表示 : コンパイラが文句を言うケースを見たことがあります。 substring は未知のシンボルであり、以下のような

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

    をプログラマーが独自に作成したものであることが判明しました。 String を定義しておらず、そのクラスのバージョンは substring メソッドを使用します。 でやっている人を見たことがあります。 System , Scanner といったクラスがあります。

    レッスンです。 一般的なライブラリクラスと同じ名前で独自のクラスを定義しないようにしましょう

    この問題は、完全修飾名を使用することによっても解決することができます。 例えば、上記の例では、プログラマーが できる は書いている。

    java.lang.String s = ...
    java.lang.String s1 = s.substring(1);
    
    
  8. ホモグリフ。 ソースファイルのエンコーディングにUTF-8を使用した場合、識別子に 見る を含むため、同じでありながら、実際には異なっています。 参照 このページ をご覧ください。

    ソースファイルのエンコードをASCIIまたはLatin-1に限定し、Javaの \uxxxx は他の文字をエスケープします。


1 - もし、ひょっとして、あなたが する このような例外やエラーメッセージが表示される場合、コンパイルエラーがあるコードを実行するようにIDEが設定されているか、アプリケーションがコードを生成して実行時にコンパイルしているかのどちらかです。
2 - 土木工学の3つの基本原則:水は坂道を流れない、板は横にした方が強い、そして ロープで押してはいけない .