『昨日探し当てた場所に 今日もジャンプしてみるけれど なぜか NOT FOUND 今日は NOT FOUND~♪(「NOT FOUND:Mr.Children」)』
はい、どうも~。ボクです。
というわけで、Java のお話です。
奇しくも、404記事目という...Not Found~♪、レッツトライ~。
java.lang.ClassNotFoundException ってよく分かってなかった
まぁ、何て言うか、これまで、あんまり考えたこと無かったんだけど、今さらながら、java.lang.ClassNotFoundException って何で起こるのか?ってことを、職場の同僚の方に教えていただいたので、整理をば。
ズバリ、java.lang.ClassNotFoundException っ何で起きるのか?
Oracle の Java API のドキュメントによりますと、
public class ClassNotFoundException extends ReflectiveOperationException
- クラス
Class
のforName
メソッド。 - クラス
ClassLoader
のfindSystemClass
メソッド。 - クラス
ClassLoader
のloadClass
メソッド。
1.4 リリースでは、この例外は汎用的な例外チェーンメカニズムに適合するように改良されています。「クラスのロード時に生じたオプション例外」 (構築時にスローされ、getException()
メソッドを介してアクセス可能) は、cause メソッドと呼ばれるようになり、前述の「レガシーメソッド」に加えて Throwable.getCause()
メソッドを介してアクセス可能です。
- 導入されたバージョン:
- JDK1.0
⇧ 説明によると、いずれもクラスが見つからない時に起きる現象のようですが、
- Class
- forName メソッド
- ClassLoader
- findSystemClass メソッド
- loadClass メソッド
の3パターンのいずれかで、クラス が見つからなかった場合でしか起こりえないと。
あくまで、「上記のメソッドが正常に実施され、かつ、クラス が見つからなかった 」っていう場合にのみ発生するんだと。
「forName」「findSystemClass」「loadClass」って、3つのメソッドの違いはよく分かりませんが、いずれも、役割的には、「クラスの文字列名をキーにクラスを見つける」ってことをやっているらしいと。
Java の仕組み
ここで、Java の仕組みに繋がると。
どういうことかと言いますと、
⇧ っていうか、ほとんどっていうのがどうにも気になるな...。
んで、説明が、抽象的なんですが、1つのファイルを処理するで考えた場合、
ファイルの拡張子 | 内容 |
---|---|
.java | ソースコード |
.class | 中間言語(またの名を、バイトコード) |
ってファイルが最低限、必要なんだと。
「.jar」「.war」「.ear」なんかについては、
⇧ 上記サイト様が詳しいです。
JVM(Java Virtual Machine:Java仮想マシン)が、.class ファイルを実行することで、Java のプログラムが実行されるということらしい。
上記の図で分かる通り、JRE(Java Runtime Environment)は、
という構成になっているので、JavaやPythonのコンパイラーは含まれていない。
つまり、実際に、Javaアプリケーションを配布ってなった場合は、「中間言語」となっている状態にしておく必要があると。
なので、コンパイル済にしておく必要があるんじゃと。
ちなみに、JDK(Java Development Kit)は、「JRE」+ 「α」 っていう構成になると思うので、コンパイラーなんかが含まれるであろうと。
ビルド と コンパイル の違いって、何だ?
「ビルド」と「コンパイル」の違いって何なのさ?って疑問を持たれた方は、安心してください、私と同じく情弱(情報弱者)の仲間入りです、一緒にがんばって参りましょう(涙)。
⇧ 上記サイト様が詳しいです。
つまり、Javaの標準API以外に、何かしら外部のAPIなんかを使いたい場合は、ビルドしてあげないと、駄目ってことみたい。
コンパイルは、あくまで、「ソースコードから中間言語への変換」のみを行い、それ以外のことについては一切何も行わないということらしい。
結局、java.lang.ClassNotFoundExceptionって?
ここまでの流れで、コンパイルエラーが原因で、.class ファイルが作成されないのが原因かと思ってたんですが、
一部の関連するクラスファイルが残っていると、コンパイルは通るのに
実行時にクラスファイルがないというエラーが起きます。
⇧ 上記サイト様によりますと、コンパイルは正常に終了しても、中間言語である .class ファイルが見つからない状態が起こりえて、
- Class
- forName メソッド
- ClassLoader
- findSystemClass メソッド
- loadClass メソッド
で、クラスを参照しに行った際に、クラスが見つからずに起こる現象であると。
厄介なところは、大規模プロジェクトなんかだと、クラスの数が膨大になるため、何が影響してクラスファイルが作成されなかったのかが分かりにくいということでしょうか。
フレームワークなんかを使っている場合は、さらに原因が分かりにくくなる感じでしょうか。
「SVN」や「Git」などのバージョン管理システムなどを使っている場合は、プロジェクト内で状況を説明したりして、不具合の起きている事象への対応をお願いしている間は、全体のリビジョンを戻したりして対応する感じになるんですかね?
⇧ 上記サイト様によりますと、ビルドが正常に終了して、.class ファイルが生成されている状態でも、クラスパスの問題で、.class ファイルが見つからんと怒られる場合があるのだと。
なので、
- .classファイルが生成されていない
- .classファイルは生成されているけど、クラスパスが解決できない
のどっちかによって、ClassNotFoundException が起こっているってことなんすかね?
結局、ClassNotFoundException が、具体的にどういう時に起こりえるのかはよく分からんのだけれども、ビルド、ないしは、コンパイルがすべてのファイルに対して行われていない、または、クラスパスを解決できない場合に起こりえるんだと。
⇧「クラスパス」は自動で設定してくれるそうなので、「ビルドパス」ってものを意識していけば良いそうな。
「ビルドパス」の確認をすることで、生成された .class ファイルがどこに格納されるか分かるらしいです。
・http://www.hot-surprise.org/IntroEclipse/Operation/N01/3_4.html
というわけで、Eclipseで適当なプロジェクトを選択し、右クリックで、「ビルド・パス(B)」>「ビルド・パスの構成(C)...」で。
「Java のビルド・パス」の「ソース」タブで、「デフォルト出力フォルダー(T):」ってところに、.class ファイルが格納されるらしい。
そんなフォルダ表示され取らんやん...
どうやら、フィルターがかかってしまっているらしい。
⇧ 上記のサイト様を参考にするも、そもそも、「ビューのカスタマイズ...」が選択肢にないんですよね。
仕方ないので、「ナビゲーター」のほうで、「フィルター(F)...」を選択します。
「ナビゲーター」が表示されていない場合は、「ウィンドウ(W)」>「ビューの表示(V)」>「ナビゲーター」で表示させます。
⇧ 「*.class」にフィルターがかかってないことを確認。
「FunctionIFTest/bin」に、.class ファイルが生成されてることが確認できました。
すみません...、「ビューのカスタマイズ...」は「Filters and Customization(F)...」に該当するようです。
「Java 出力フォルダー」にチェックが付いてしまっているので、
チェックを外し、「OK」で。
「プロジェクト・エクスプローラー」でも「bin」フォルダが表示されました。
見つからないクラスファイルの名前が分かっている場合は、.classファイルの出力先のフォルダを確認し、.class ファイルが生成されているか確認するのも1つの手ですかね?クラスファイルの数が多い場合は厳しいでしょうけど。
あと、Eclipse経由でGC(ガベージコレクター)を実施できるってことも職場の同僚の方に教えていただきました。
「一般」>「ヒープ・ステータスを表示(W)」にチェックを入れればOKらしい。
チェックで。
Eclipse の右下に、「ヒープ・ステータス」が表示されました。
をクリックすると、ガベージコレクターが実行されるようです。
ログとかを可視化してくれるプラグインとかも存在するそうな。
というわけで、今回も本当に知りたい部分については分からいままとなってしまいモヤモヤ感が半端ない...
今回はこのへんで。