一、類加載器的種類
一般分爲:引導類加載器(bootstrap classloader)、擴展類加載器(extensions class loader)、應用程序類加載器(application class loader)、自定義類加載器 這4種類加載器
一、引導類加載器(bootstrap classloader)
它用來加載java核心庫的(java_home/jre/lib/rt.jar 或者sun.boot.class.path 路徑下的內容)是用來原生代碼來實現的,並不繼承java.lang.classloader,是通過C++來實現。由於引導類加載器涉及到虛擬機本地實現細節,開發者無法直接獲取到啓動類加載器的引用,所以不允許直接通過引用進行操作。
二、擴展類加載器(extensions class loader)
用來加載java的擴展(java_home/jre/ext/*.jar 或者java.ext.dirs路徑下的內容)
java與虛擬機的實現會提供一個擴展庫的目錄,該類加載器在此目錄裏面查找並加載java類
由sun.misc.Launcher$ExtClassLoader實現
三、應用程序類加載器(application class loader)
它根據java引用的類路徑(classpath java.class.path路徑
一般來說java應用的類的都是由他來來加載實現的,也就是我們經常用到的classpath路徑
package classLoader;
public class ClassLoader_test {
public static void main(String[] args) {
System.out.println(ClassLoader.getSystemClassLoader());
}
}
sun.misc.Launcher$AppClassLoader@4e25154f
通過getparent()來獲取相對應的父級
package classLoader;
public class ClassLoader_test {
public static void main(String[] args) {
System.out.println(ClassLoader.getSystemClassLoader());
//AppClassLoader的父類應該是ExtClassLoader
System.out.println(ClassLoader.getSystemClassLoader().getParent());
//而ExtClassLoader的父類應該是bootstrap classloader,但是它是由C++實現的,那麼java中是獲取不到的
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
}
}
sun.misc.Launcher$AppClassLoader@4e25154f
sun.misc.Launcher$ExtClassLoader@33909752
null
四、加載機制
代理模式
交給其他加載器來加載指定的類
雙親委託機制
就是給某個特定的類加載器在接到加載類的請求時,首先將加載任務委託給父類加載器,依次追溯,直到最高的爺爺輩的,如果父類加載器可以完成類加載額任務,就成功返回;只有父類加載器無法完成的此加載任務時,自己纔去加載
雙親委託機制是爲了保證java核心庫的類型安全
這種機制就保證不會出現用戶自己能定義java.lang.Object類的情況
類加載器處理用於加載類,也是安全的最基本的保障
雙親委託機制是代理模式的一種
並不是所有的類加載器都採用雙親委託機制
tomcat服務器的類加載器也是採用代理模式,所不同的它首先嚐試去加載某個類,如果找不到再代理給父類加載器,這與一般類加載器的順序是相反的。
舉個栗子
比如我突然naocan,定義了一個java.lang.String的類,那麼首先是從自定義類加載器開始,先傳遞給AppClassLoader,然後在傳遞給ExtClassLoader,最後傳遞給BootStrapclassLoader(加載核心包的),發現存在java.lang.String,那麼就會加載String類,那麼就會直接返回class。這樣就保證了對於外部的包進行了安全性的保障
五、 java.lang.classLoader
作用:
java.lang.classLoader的類的基本職責就是根據一個指定的類的名稱,找到或者生成其對應的字節代碼,然後從這些字節代碼中定義java類,即java.lang.Class類的一個實例
除此之外,ClassLoader還負責加載java應用所需的資源,如圖像文件和配置文件
相關方法:
getParent() 返回該類加載器的父類加載器
loadClass(String name) 加載名稱爲name的類,返回的結果是java.lang.class類的實例
Findclass(String name) 查找名稱爲name的類,返回的結果是java.lang.class的類的實例
defineClass(String name,byte[] b,int off,int lent) 把字節數組b中的 內容轉化爲java類,返回的是
Java.lang.class的類的實例,這個方法被聲明爲final的
resolveClass(Class<?> c)鏈接被指定的java類
對於以上給出的方法,表示類的名稱的name參數的值是類的二進制名稱,需要注意的是內部類的表示,如com.example.Sample$1和com.example.Sample$inner等表示方式
六、自定義加載器
package classLoader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javassist.ByteArrayClassPath;
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
//定義了文件所在的根目錄
public FileSystemClassLoader(String root)
{
this.rootDir=root;
}
@Override
protected Class<?> findClass(String name)throws ClassNotFoundException
{
Class<?> class1=findLoadedClass(name);
//如果已經被加載了
if(class1!=null)
{
return class1;
}
else
{
ClassLoader parent=this.getParent();
//讓父級進行加載,如果加載成功那麼直接返回
try
{
class1=parent.loadClass(name);
}
catch(Exception exception)
{
exception.printStackTrace();
}
if(class1!=null)
return class1;
else
{
byte[] classData = null;
try {
classData = getClassData(name);
} catch (IOException e) {
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
if(classData==null)
throw new ClassNotFoundException();
else
{System.out.println(name+""+classData.toString()+" "+classData.length);
class1=defineClass(name, classData, 0,classData.length);
}
}
}
return class1;
}
public byte[] getClassData(String classname) throws IOException
{ String path=rootDir+"/"+classname.replace('.', '/')+".class";
System.out.println(path);
InputStream is=new FileInputStream(path);
ByteArrayOutputStream byteArrayOutputStream=null;
byte[] bs=new byte[1024];
int length=0;
try
{
byteArrayOutputStream= new ByteArrayOutputStream();
while((length=is.read(bs))!=-1)
byteArrayOutputStream.write(bs,0,length);
return byteArrayOutputStream.toByteArray();
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("wo是你個");
return null;
}
finally {
byteArrayOutputStream.close();
is.close();
}
}
}
package classLoader;
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException {
FileSystemClassLoader FilesystemClassLoader=new FileSystemClassLoader("d:/myjava");
Class<?> class1= FilesystemClassLoader.loadClass("com.bjsxt.bean.HelloWorld");
System.out.println(class1);
}
}