深入java虚拟机学习 -- 类的加载机制(四)

时间:2022-12-27 12:29:24

类加载的命名空间

每个类加载器都有自己的命名空间,命名空间由所有以此加载器为初始类加载器的类组成,不同命名空间的两个类是不可见的,但只要得到类所对应的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();
}