2010-12-31 1 views
1

Javaでサンプルコードを作成するとき、私はClassCastExceptionを見つけました。そこからStaticClassにオブジェクトをキャストしました。誰がここで何が起こったのか説明できますか?そのクラスがロードされているオブジェクトの参照を作成するときは?

public void test5() throws Exception { 

    System.out.println(StaticClass.obj); 
    Object newInstance = ClassLoader.getSystemClassLoader().loadClass("com.StaticClass").newInstance(); 
    System.out.println(newInstance.getClass().getDeclaredField("obj").get(newInstance)); 

    Object newInstance2 = new ILoader().loadClass("com//StaticClass.class").newInstance(); 
    System.out.println(newInstance2.getClass().getDeclaredField("obj").get(newInstance2)); 

    StaticClass s = (StaticClass)newInstance2; 
    System.out.println(s.obj); 

    System.out.println(newInstance.getClass().getClassLoader()); 
    System.out.println(newInstance2.getClass().getClassLoader()); 

} 

package com; 

public class StaticClass { 

    public static final Object obj = new Object(); 
} 

package com; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 

public class ILoader extends ClassLoader { 

public ILoader() { 
    super(null); 
} 

@Override 
protected Class<?> findClass(String name) throws ClassNotFoundException { 

    File file = new File(name); 

    byte[] bytes = new byte[(int)file.length()]; 

    try { 
    new FileInputStream(file).read(bytes); 
    } catch (FileNotFoundException e) { 
    e.printStackTrace(); 
    } catch (IOException e) { 
    e.printStackTrace(); 
    } 

    return super.defineClass("com.StaticClass",bytes, 0, bytes.length); 
} 
} 

コードの鋳造部分が存在しない場合、最後のSystem.outによって与えられた出力は、以下の通りです。

[email protected] 
[email protected] 
+0

なぜダブルスラッシュ? com // StaticClass.class、クラスローダーはクラス名の最後に.classを期待しません。 – MeBigFatGuy

+0

@MeBigFatGuy:私はasela38というクラスファイルへの相対パスが、ILoaderクラスで同じものを読み込んでいると思います。 – Favonius

+0

これはクラスの場所なので、classLoaderはロードすることができます。ここで私はカスタムClassLoader を使用しています(ここでは2つの別々のClassLoaderからロードされたクラスStaticClassの2つのインスタンスが存在します) .misc.Launcher $ AppClassLoader(java.class.pathからクラスをロードする))) – asela38

答えて

2

2つのクラスローダーがクラスをロードするとき、実際にクラスを2つコピーします。このような場合のシナリオでは、

StaticClass s = (StaticClass)newInstance2; 

デフォルトでは、デフォルトのシステムクラスローダーがキャスト用の画像になります。 newInstance2は別のクラスローダからロードされるため、ClassCastExceptionが発生します。これは動作しません.JVM内の2つの異なるClassオブジェクトによって表され、キャストは失敗します。詳細については

は、以下の記事やフォーラムのエントリを参照してください。

  1. http://onjava.com/pub/a/onjava/2003/11/12/classloader.html

  2. http://java.sun.com/developer/technicalArticles/Networking/classloaders/index.html

  3. http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html

  4. http://www.coderanch.com/t/380416/java/java/Loading-same-class-two-different

  5. Different classloaders cause ClassCastException when persisting data via Spring

0

クラスは、その完全修飾名と、それをロードしたクラスローダの両方によって定義されます。

2つのクラスが同じ完全修飾名を持ち、同じ場所(同じクラスローダー)で見つかった場合、2つのクラスが同じになるため、これは必要です。

2つのクラスが同じ名前のの場合は、それらが異なるクラスローダーから読み込まれた場合、それらが同じクラスファイルを表すとは限りません。

そうでなければ、Java APIクラスをスプーフィングする可能性があるため、セキュリティ上のリスクも発生します。独自のバージョンのjava.lang.Stringを作成し、別のクラスローダーでロードし、java.langの他のクラスの特権を得ることができます(例えば、パッケージのプライベートフィールドを見ることができるようにする)。

名前とクラスローダによってクラスが一意に識別されるため、他にも数多くの利点があります。コードがClassCastExceptionをスローし、クラスが同じ名前を持つ場合は少し変わっていますが。

関連する問題