2012-02-29 6 views
0

実行時に利用できない他のクラスを参照するクラスファイルをロードするとき、非常に奇妙なJavaクラスパスの動作があります。奇妙なJavaクラスパス/クラスローダーの振る舞い

パラメータのクラスを継承するクラスにキャストされたパラメータを持つ別のクラスのコンストラクタを呼び出す(実行時に手を触れないメソッドを持つ)クラスをロードすると、クラスが見つかりませんif if paramter class ifロードするクラスのみが、そのクラスのメソッドで参照される他のクラスはクラスパスにありません。

私は次のJavaを使用しています:ここで

java version "1.6.0_18" 
Java(TM) SE Runtime Environment (build 1.6.0_18-b07) 
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode) 
(Windows Server 2008 R2) 

はサンプルです:

public class A 
{ 
    public static void main(String[] args) 
    { 
    System.out.println("it works"); 
    } 

    public void foo() 
    { 
    new B((D)null); 
    } 
} 

public class B 
{ 
    public B(C c) { 
    } 
} 

public class C 
{ 
} 


public class D extends C 
{ 
} 

は、今私は、クラスをコンパイルし、私はクラスパス内のすべてのクラスファイルとクラスAを実行した場合それは「それは働く」ことをもたらす。私はすべてのクラスがクラスパスからクラスAをexcepet削除する場合

は、次のエラーが発生します。クラスCは、実行時に必要とするべきではありません

Exception in thread "main" java.lang.NoClassDefFoundError: C 
Caused by: java.lang.ClassNotFoundException: C 
     at java.net.URLClassLoader$1.run(Unknown Source) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at java.net.URLClassLoader.findClass(Unknown Source) 
     at java.lang.ClassLoader.loadClass(Unknown Source) 
     at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) 
     at java.lang.ClassLoader.loadClass(Unknown Source) 
Could not find the main class: A. Program will exit. 

が。星座後

は(クラスAで置き換え、 "新B((D)ヌル)")作品:

public class A 
{ 
    public static void main(String[] args) 
    { 
    System.out.println("it works"); 
    } 

    public void foo() 
    { 
    D d = (D)null; 
    d.toString(); 
    B b = (B)null; 
    b.toString(); 
    new B(null); 
    } 
} 

public class B 
{ 
    public B(C c) { 
    } 
} 

public class C 
{ 
} 


public class D extends C 
{ 
} 

星座後も、(CではなくDにキャスト; Cは、任意のクラスを継承していない)動作します

public class A 
{ 
    public static void main(String[] args) 
    { 
    System.out.println("it works"); 
    } 

    public void foo() 
    { 
    new B((C)null); 
    } 
} 

public class B 
{ 
    public B(C c) { 
    } 
} 

public class C 
{ 
} 


public class D extends C 
{ 
} 

これは予期しない動作またはJavaのバグですか?

+0

「実行時にクラスCは決して必要ではありませんが、実行時には必ず必要です。 DはCなので、Cが必要ないと言うのは論理的に不可能です。 – Woot4Moo

+0

これは当てはまりますが、Cに明示的にキャストしても実行時には利用できない場合は動作します。 クラスB、クラスC、クラスDは、mainメソッドはprintlnしか持たず、fooは決して呼び出されないように読み込まれるべきではありません。 – dominik

+0

これはIDEかコマンドラインで行いますか?両方の環境で試してみてください。時にはEclipseが "役立つ"のが好きです。 – Woot4Moo

答えて

0

私はJSRをまだ経験していませんが、インタープリタがクラスファイルを解釈するときに必要なメソッドだけを実行すると、すべてのことが行われることになります。この場合、Aが必要であり、foo()も解釈される場合は、Cが必要です。これはすべて、Aがロードされた時点で起こっているはずです。したがって、エラーが発生しました。

+0

私はCが間接的に必要であることを知っています。なぜD d =(D)nullであるのか? 'd.toString(); B b =(B)ヌル; b.toString(); ' と '新しいB((C)ヌル); ' 作品?これらのすべてのバージョンでは、クラスB、C、およびDも必要です。 – dominik

+0

セクション5.5を参照してください。「実行時の値がnullの場合、キャストは許可されています」http://java.sun。com/docs/books/jls/second_edition/html/conversions.doc.html – kosa

1

refer section 5.5「実行時の値がnullの場合、キャストは許可されています。

+0

それはすべての場合.. – Kashyap

+0

nullキャスティングは常に動作している、それについて説明します。問題はnullをキャストすることではありません。私の主な質問は、fooが実行時に呼び出されることはありませんが、クラスローダーがクラスCをロードする必要があると考える理由です。なぜクラスCをロードするのですか?引数**を渡すとクラスCがロードされますが、クラスCは直接クラスCではありません。 'public void foo(){新しいB(新しいC())}' ALSO WORKS; 'public void foo(){new B(new D()}}'はうまくいきません – dominik