クラス・ロードの問題
4784 ワード
コード1:
コード2:
クラス・ローダのエージェント・モードについて説明したとき、クラス・ローダはまず他のクラス・ローダにエージェントしてクラスをロードしようとします.これは、クラスのロード作業を本当に完了するクラスローダと、このロードプロセスを開始するクラスローダが同じではない可能性があることを意味します.本当にクラスを完了するロード作業は、
ClassLoaderのloadClassメソッドのソースコード
parentソース:
getSystemClassLoaderメソッド:
コード1は、2つのクラスローダをインスタンス化したが、最終的には同じsclインスタンスを使用してdefineClassメソッドを呼び出すため、trueを返す
コード2は2つの異なるクラスのローダのdefineClassを使用してクラスをロードするのでfalseに戻ります
package org.fenixsoft.clazz;
public class Test
{
public static void main(String[] args) throws ClassNotFoundException
{
ClassLoader cls1 = new ClassLoader()
{
};
ClassLoader cls2 = new ClassLoader()
{
};
Class a = cls1.loadClass("org.fenixsoft.clazz.Test");
Class b = cls2.loadClass("org.fenixsoft.clazz.Test");
System.out.println(a == b);//true
System.out.println(a == Test.class);//true
}
}
コード2:
package org.fenixsoft.clazz;
import java.io.IOException;
import java.io.InputStream;
public class Test2
{
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
ClassLoader cls1 = new ClassLoader()
{
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
{
try
{
String filename = name.substring(name.lastIndexOf(".") + 1) + ".class";
InputStream is = getClass().getResourceAsStream(filename);
if (is == null)
{
return super.loadClass(name);
}
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b.length);
}
catch (IOException e)
{
throw new ClassNotFoundException(name);
}
}
};
ClassLoader cls2 = new ClassLoader()
{
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
{
try
{
String filename = name.substring(name.lastIndexOf(".") + 1) + ".class";
InputStream is = getClass().getResourceAsStream(filename);
if (is == null)
{
return super.loadClass(name);
}
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b.length);
}
catch (IOException e)
{
throw new ClassNotFoundException(name);
}
}
};
Class a = cls1.loadClass("org.fenixsoft.clazz.Test2");
Class b = cls2.loadClass("org.fenixsoft.clazz.Test2");
System.out.println(a == Test2.class);// false
System.out.println(a == b);// false
}
}
クラスをロードするプロセス
クラス・ローダのエージェント・モードについて説明したとき、クラス・ローダはまず他のクラス・ローダにエージェントしてクラスをロードしようとします.これは、クラスのロード作業を本当に完了するクラスローダと、このロードプロセスを開始するクラスローダが同じではない可能性があることを意味します.本当にクラスを完了するロード作業は、
defineClass
を呼び出すことによって実現される.起動クラスのロードプロセスは、loadClass
を呼び出すことによって実現される.前者をクラスの定義ローダ(defining loader)と呼び、後者を初期ローダ(initiating loader)と呼ぶ.Java仮想マシンが2つのクラスが同じかどうかを判断する場合、クラスの定義ローダが使用されます.ClassLoaderのloadClassメソッドのソースコード
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
parentソース:
protected ClassLoader() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
this.parent = getSystemClassLoader();
initialized = true;
}
getSystemClassLoaderメソッド:
// The class loader for the system
private static ClassLoader scl;
public static ClassLoader getSystemClassLoader() {
initSystemClassLoader();
if (scl == null) {
return null;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader ccl = getCallerClassLoader();
if (ccl != null && ccl != scl && !scl.isAncestor(ccl)) {
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
return scl;
}
コード1は、2つのクラスローダをインスタンス化したが、最終的には同じsclインスタンスを使用してdefineClassメソッドを呼び出すため、trueを返す
コード2は2つの異なるクラスのローダのdefineClassを使用してクラスをロードするのでfalseに戻ります