- PR -

NoClassDefFoundErrorが発生する条件(Java1とJava2の違い)

1
投稿者投稿内容
ヨシ
会議室デビュー日: 2006/10/06
投稿数: 2
投稿日時: 2006-10-06 22:47
Javaの基本的な質問になります。

以前Java1では掲題のエラーが発生しなかったロジックが、そのままJava2でコンパイルしなおしてJava2環境で実行すると同エラーが発生するという現象が見られます。

同ロジックを簡単に説明すると、

if(b){
ClassA a = new ClassA();
}else{
ClassB b = new ClassB();
}

のように、条件によって参照するクラスが異なるロジックとなっており、
条件文は実行する環境を判定するものとなっております。
例えば、同ロジックを実行する端末環境が@Aの二種類あって、b=trueは、端末@で実行されていることを表し、b=falseは端末Aで実行されていることを表します。

端末@で同ロジックを実行する場合、Java1環境ではClassBのデプロイを行わなくても、b=trueとなってClassBを参照するロジックを通らないためNoClassDefFoundErrorは発生しませんでしたが、Java2になると分岐として通らなくても、ClassBがないと端末@でNoClassDefFoundErrorが発生するようです。

前書きが長くなりましたが、下記についてご存知の方がいらっしゃいましたらご回答をお願いします。

Q1.上記はJava2から発生する現象という理解はあっておりますでしょうか?
Q2.同現象はコンパイル時(Javacコマンド)や、実行時(javaコマンド)のオプションを指定することによって、Java1と同様(つまり掲題のNoClassDefFoundErrorが発生しない)ようにすることは出来ますでしょうか?
さいくろう
大ベテラン
会議室デビュー日: 2005/11/19
投稿数: 170
お住まい・勤務地: 川崎市
投稿日時: 2006-10-06 23:00
「実はbがfalseなのでエラーが発生している」に1票。
想馬
大ベテラン
会議室デビュー日: 2003/05/29
投稿数: 245
お住まい・勤務地: 神奈川・東京
投稿日時: 2006-10-06 23:05
引用:

ヨシさんの書き込み (2006-10-06 22:47) より:
Javaの基本的な質問になります。

以前Java1では掲題のエラーが発生しなかったロジックが、そのままJava2でコンパイルしなおしてJava2環境で実行すると同エラーが発生するという現象が見られます。


とりあえずJava1とかJava2とかじゃなくてちゃんとjava -versionで表示される情報を書きましょう。

条件式は本当に真なんですか?
ヨシ
会議室デビュー日: 2006/10/06
投稿数: 2
投稿日時: 2006-10-06 23:11
皆様、

早速のご返答ありがとうございます。
bの条件は間違いなく”真”です。
(リテラルでソースに書いてあります)

Javaのバージョンは下記になります。
java full version "1.4.2-b28"
さいくろう
大ベテラン
会議室デビュー日: 2005/11/19
投稿数: 170
お住まい・勤務地: 川崎市
投稿日時: 2006-10-06 23:33
本当に、ClassBが無い状態で、動いていたんですか?
その場合の、Javaのバージョンはいくつです?
LinkageErrorって、JDK1.0の時からあるはずですが。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2006-10-07 11:05
実はそのif文より外のスコープで変数宣言がしてあって
クラスをロードしに行っているとか。
端的なソースだとどうしても実装の誤りを最初に疑ってしまいますね。

NoClassDefFoundErrorが発生する行はどこになるのでしょうか?
その発生行で参照しているのですよね?
ではその発生行でロードが行われているのではないのですか?
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2006-10-07 13:08
引用:

Q1.上記はJava2から発生する現象という理解はあっておりますでしょうか?


いいえ、言語仕様的にはJava1の頃からずっと発生しうる現象です。
Java1のJVM実装ではたまたま問題にならなかった、というだけの話です。

Java言語仕様では第1版のころから、NoClassDefFoundErrorがthrowされるタイミングについて
"at any point in the Java program that (directly or indirectly) uses the type"
と記述しています。
http://java.sun.com/docs/books/jls/first_edition/html/12.doc.html#44476
"at any point"ですから、ClassBが存在しない場合
ClassB b = new ClassB();
の行に処理が移る前にNoClassDefFoundErrorをthrowしても構わないということになります。

ここらへんの挙動については、"Java Puzzlers"という本に非常に面白い問題が載っていますので、
読んでみるとよいかもしれません。
http://d.hatena.ne.jp/freebeans/20060111/p2
引用:

Q2.同現象はコンパイル時(Javacコマンド)や、実行時(javaコマンド)のオプションを指定することによって、Java1と同様(つまり掲題のNoClassDefFoundErrorが発生しない)ようにすることは出来ますでしょうか?


javaコマンドの起動オプションに -noverify を付けることでNoClassDefFoundErrorの発生を
回避することができるかもしれません。
しかし、これは非標準のやり方であり、あくまで裏技の一つに過ぎません。
Sun以外のJVMや、Java6以降でも使えるかどうかについては何の保証もありません。

標準に沿った、推奨される方法は Class.forName() を使うことです。
Object b = Class.forName("ClassB").newInstance();
という処理があった場合、ClassNotFoundExceptionはこの行に処理が移るまで
絶対にthrowされることはありません。
1

スキルアップ/キャリアアップ(JOB@IT)