java虛擬機中,有一個類加載子系統,它包括了四種類加載器
1、根裝載器(啓動類裝載器)2、擴展類裝載器3、系統類裝載器4、用戶自定義類加載器
根加載器負責加載API裏面的類,例如java.lang.object
擴展類裝載器複製加載jre中ext包中的類,如C:\Program Files\Java\jdk1.6.0_21\jre\lib\ext
系統類裝載器加載classpath中的類,記得我們配置JDK環境變量的時候如何配置classpath的嗎?.;C:\Program Files\Java\jdk1.5.0_06\lib\tools.jar; C:\Program Files\Java\jdk1.5.0_06\lib\rt.jar,這些就是classpath裏面的類,你程序中的類,也是由它加載的,因爲你程序屬於當前路徑,classpath中有個“.”
補充個知識點(摘至百度):
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------
rt.jar是JAVA基礎類庫,dt.jar是關於運行環境的類庫,tools.jar是工具類庫
設置在classpath裏是爲了讓你 import *
---------------------------------------------------------------
web系統都用到tool.jar
你用winrar看看裏面是什麼內容啦
---------------------------------------------------------------
1.
rt.jar 默認就在 根classloader的加載路徑裏面 放在claspath是多此一舉
不信你可以去掉classpath裏面的rt.jar
然後用 java -verbose XXXX 的方式運行一個簡單的類 就知道 JVM的系統根Loader的路徑裏面
不光rt.jar jre\lib下面的大部分jar 都在這個路徑裏
2.
tools.jar 是系統用來編譯一個類的時候用到的 也就是javac的時候用到
javac XXX.java
實際上就是運行
java -Calsspath=%JAVA_HOME%\lib\tools.jar xx.xxx.Main XXX.java
javac就是對上面命令的封裝 所以tools.jar 也不用加到classpath裏面
3.
dt.jar是關於運行環境的類庫,主要是swing的包 你要用到swing時最好加上
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
類裝載器是如何裝載類的呢?
類裝載器採用了父親委派模式來進行加載,父親委派模式是這樣的,要加載一個類的時候,首先叫負責加載該類的類裝載器的父裝載器去嘗試加載,如果加載不了,再往上拋,一直拋到根加載器,如果根加載器還加載不了,那麼就讓負責加載該類的類裝載器來加載。
根裝載器沒有父裝載器,它是C實現的,所以在程序中獲取不到它,擴展類裝載器的父裝載器是根裝載器,系統類裝載器的父裝載器是擴展類裝載器,而用戶自定義的類裝載器,默認情況下是系統類裝載器,當然,在自定義類裝載器的時候,是可以指定父裝載器的。
講完了加載的順序,那麼我們就來嘗試着寫一個類裝載器,讓它裝載固定某個地方的類
首先寫一個自己的類加載器,MyClassLoader.java,繼承ClassLoader類,然後重寫findClass方法:
package com.wyp12.myClassLoader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* 自己寫一個類加載器 ,去加載"d:\myclass\com\wyp12\*.class"
*
* @author prince
*
*/
public class MyClassLoader extends ClassLoader {
private String name;
public MyClassLoader(String name) {
super(); // 通過這個構造方法生成的類加載器,它的父加載器是系統類加載器
this.name = name;
}
public MyClassLoader(String name, ClassLoader loader) {
super(loader); // 通過這個這個構造方法生成的類加載器,該加載器的父加載器是loader,如果爲空,則父加載器爲根加載器
// 子類繼承父類,如果不顯式寫出調用父類的哪個構造方法,那麼就默認調用父類的無參構造函數
this.name = name;
}
public String toString()
{
return this.name;
}
// 要重寫findclass這個方法,loadclass會調用它
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
byte[] data = null;
FileInputStream fis = null;
try {
fis = new FileInputStream("d:\\myclass\\com\\wyp12\\myClassLoader\\"+name+".class");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
ByteArrayOutputStream abos = new ByteArrayOutputStream();
int ch = 0;
try {
while (-1!=(ch=fis.read()))
{
abos.write(ch); //把字節一個一個寫到輸出流中
}
} catch (IOException e) {
e.printStackTrace();
}
data = abos.toByteArray(); //把輸出流中的字節弄成一個字節數組
return this.defineClass("com.wyp12.myClassLoader."+name,data, 0, data.length,null);
}
}
這個類加載器我讓它默認加載d:\myclass\com\wyp12\myClassLoader
路徑下的class文件,具體文件名到時候我們構造實例的時候再給定,下面是測試類:import com.wyp12.myClassLoader.MyClassLoader;
public class TestLoader {
public static void main(String[] args) throws Exception {
MyClassLoader l1 = new MyClassLoader("loader1");
Class dogC = l1.loadClass("Dog");
dogC.newInstance();
/*MyClassLoader l2 = new MyClassLoader("loader2",l1); //把L1作爲它的父加載器
Class doccc = l2.loadClass("Dog");
doccc.newInstance(); */
}
}
下面是要加載的類的源代碼,很簡答,就是讓它打印出是誰加載了他
package com.wyp12.myClassLoader;
public class Dog {
public Dog()
{
System.out.println(this.getClass().getClassLoader());
}
}
運行結果:
loader1
下面貼上ClassLoader的主要源代碼:
它的幾個構造函數
protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}
通過幾個函數,把字節碼數組轉換成一個CLASS實例
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain)
throws ClassFormatError
{
return defineClassCond(name, b, off, len, protectionDomain, true);
}
// Private method w/ an extra argument for skipping class verification
private final Class<?> defineClassCond(String name,
byte[] b, int off, int len,
ProtectionDomain protectionDomain,
boolean verify)
throws ClassFormatError
{
protectionDomain = preDefineClass(name, protectionDomain);
Class c = null;
String source = defineClassSourceLocation(protectionDomain);
try {
c = defineClass1(name, b, off, len, protectionDomain, source,
verify);
} catch (ClassFormatError cfe) {
c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,
source, verify);
}
postDefineClass(c, protectionDomain);
return c;
}
下面這個是loadClass()
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
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 = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
下面是我們要重寫的方法:
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
基本就這樣了,其實還很多細節,由於自己的文筆也不是很好,就不寫出來了,只是做個mark,以後便於複習