类加载的命名空间
每个类加载器都有自己的命名空间,命名空间由所有以此加载器为初始类加载器的类组成,不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的refrence(反射),还是可以访问另一个命名空间的类信息的。
同一个命名空间内的类是相互可见的,子加载器的命名空间包含所有父加载器的命名空间,也就是说由子加载器加载的类能看到父加载器加载的类。例如:系统类加载器加载的类能看到根类加载器加载的类(用户自定的类可以访问java.lang.*包下的信息),由父加载器加载的类不能看到子加载器加载的类。
如果两个加载器之间没有直接或者间接的父子关系,那么它们个字加载的类相互不可见。
创建用户自定义的类加载器
要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定的类的名字,返回对应的Class对象的引用。
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
我们可以按到ClassLoader里面的findClass方法的默认实现会抛出ClassNotFoundException异常,我们只需要在自定义的加载器里面重写,即可。
public class MyClassLoader extends ClassLoader
{
private String name;//类加载器的名字
private String path="";//加载类的默认路径
private String fileType=".class"; //class文件的扩展名
public MyClassLoader(String name){
super();//让系统类加载器成为该类加载器的父加载器
this.name=name;
}
public MyClassLoader(ClassLoader parent,String name){
super(parent);//显示指定该类加载器的父加载器
this.name=name;
}
@Override public String toString()
{
return this.name;
}
public String getPath()
{
return path;
}
public void setPath(String path)
{
this.path = path;
}
/**
* 抽象类ClassLoader的findClass函数默认是抛出异常的。而前面我们知道,
* loadClass在父加载器无法加载类的时候,就会调用我们自定义的类加载器中的findeClass函数,
* 因此我们必须要在loadClass这个函数里面实现将一个指定类名称转换为Class对象.
* @param name
* @return
*/
@Override protected Class<?> findClass(String name)
{
byte [] data=this.loadClassData(name);
return this.defineClass(name,data,0,data.length);
}
private byte[] loadClassData(String name)
{
InputStream is=null;
byte [] data=null;
ByteArrayOutputStream baos=null;
try
{
this.name=this.name.replace(".","\\");
is=new FileInputStream(new File(path+name+fileType));
baos=new ByteArrayOutputStream();
int ch=0;
while(-1!=(ch=is.read())){
baos.write(ch);
}
data= baos.toByteArray();
}
catch(Exception e){
e.printStackTrace();
}
finally
{
try
{
is.close();
baos.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
return data;
}
public static void main(String[] args) throws Exception
{
MyClassLoader loader1 = new MyClassLoader("loader1");//没有指定loader的父加载器,则默认的父加载器为系统类加载器
loader1.setPath("G:\\myapp\\loader1\\");
MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");//指定loader2的父加载器为loader1,这里的loader1和loader2都为MyClassLoader的实例
loader2.setPath("G:\\myapp\\loader2\\");
MyClassLoader loader3 = new MyClassLoader(null,"loader3");//bootstrap类加载器
loader3.setPath("G:\\myapp\\loader3\\");
//test(loader1);
test(loader2);
test(loader3);
}
public static void test(ClassLoader loader) throws Exception
{
Class clazz=loader.loadClass("Sample");
Object object=clazz.newInstance();
}