類加載的命名空間
每個類加載器都有自己的命名空間,命名空間由所有以此加載器為初始類加載器的類組成,不同命名空間的兩個類是不可見的,但隻要得到類所對應的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();
}
開開心心編碼,快快樂樂生活。