加載類的工具.
2,類加載器有什么作用?
當程序需要的某個類,那么需要通過類加載器把類的二進制加載到內存中.
類加載器也是Java類
3,類加載器之間的父子關系和管轄范圍.
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); while (classLoader != null) {
System.out.println(classLoader.getClass().getName());
classLoader = classLoader.getParent();
}
System.out.println(classLoader);

4,類加載器的委托機制:
1>當Java虛擬機要加載一個類時,到底派出哪個類加載器去加載呢?
①首先當前線程的類加載器去加載線程中的第一個類.
②如果類A中引用了類B,Java虛擬機將使用加載類A的類加載器加載類B
③還可以直接調用ClassLoader.loadClass()方法來指定某個類加載器去加載某個類.
2>每個類加載器加載類時,又先委托給其上級類加載器.
①當所有祖宗類加載器沒有加載到類
,回到發起者類加載器,如果還加載不了,則拋出ClassNotFoundException異常,它不會 去找發起者類加載器的兒子,因為沒有getChild()方法,即使有,有那么多的兒子交給那一個呢?所以干錯就不叫給兒子處理了.
委托機制有什么好處?集中管理,如果我們寫了幾個類加載器,都去加載某個類,那么內存中就有多份這個類的字節碼
能不能自己寫一個類叫java.lang.System?
為了不讓我們寫System類,類加載采用委托機制,這樣可以保證爸爸優先,也就是使用的永遠是爸爸的(系統的)
System類,而不是我們寫的System類.
5,編寫自己的類加載器
public static void main(String[] args) throws Exception { String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir + "\\" + destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis,fos);
fis.close();
fos.close();
}
/**
* 加密方法,同時也是解密方法
* @param ips
* @param ops
* @throws Exception
*/
private static void cypher(InputStream ips ,OutputStream ops) throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b ^ 0xff);//如果是1就變成0,如果是0就變成1
}
} 然后在新建一個類,通過上面的方法將新建的類的字節碼進行加密:
public class ClassLoaderAttachment extends Date { //為什么要繼承Date待會再說? public String toString(){
return "hello,itcast";
}
} 并在工程里新建一個文件夾,用來保存加密后的class文件.

那么這就需要使用我們自己的類加載器來進行解密了.
public class MyClassLoader extends ClassLoader{
public static void main(String[] args) throws Exception {
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir + "\\" + destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis,fos);
fis.close();
fos.close();
}
/**
* 加密方法,同時也是解密方法
* @param ips
* @param ops
* @throws Exception
*/
private static void cypher(InputStream ips ,OutputStream ops) throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b ^ 0xff);//如果是1就變成0,如果是0就變成1
}
}
private String classDir;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) + ".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
fis.close();
System.out.println("aaa");
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public MyClassLoader(){
}
public MyClassLoader(String classDir){
this.classDir = classDir;
}
} 測試運行代碼:
Class clazz = new MyClassLoader("myClass").loadClass("ClassLoaderAttachment"); //此處不能在使用ClassLoaderAttachment因為一旦用了之后,
//系統的類加載器就會去加載,導致失敗,所以該類就繼承了Date類了.
Date date = (Date)clazz.newInstance();
System.out.println(date); 運行結果:

6,一個類加載器的高級問題:
我們知道tomcat服務器,是一個大大的java程序,那么它就必須在JVM上運行.
這個大大的java程序內部也寫了很多類加載器,它用這些類加載器去加載一些特定的類.注入servlet類.
下面我們新建一個javaweb工程,新建一個servlet程序.
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
ClassLoader classload = this.getClass().getClassLoader();
while (classload != null) {
out.println(classload.getClass().getName()+"<br>");
classload = classload.getParent();
}
out.println();
out.close();
} 然后配置服務器,部署應用程序,啟動tomcat服務器.在頁面訪問我們這個servlet,在頁面打印的
結果如下圖所示:
這是從小到大排序的.
現在呢?我想把該servlet打成jar包,放在ExtClassLoad類加載器加載的路徑.
通過Eclipse即可完成