クラス・ロードの問題

4784 ワード

コード1:
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に戻ります