標籤:
類在執行之前會執行三個步驟:載入 -> 串連 -> 初始化
1.java中類的載入
java 類的載入指的是將類的.class檔案中的位元據讀入到記憶體中,將其放在運行時資料區的方法區內,然後在堆區建立一個Class對象,用來封裝類在方法區的資料結構。可以把堆區的Class理解為方法區的一面鏡子,對應方法區的類的資料結構,通過這面鏡子實作類別的調用。
載入.class檔案的多種方式:
1.從本地系統中直接載入
2.通過網路下載.class檔案
3.從zip,jar裡載入.class檔案
4.從專有的資料庫中提取.class檔案
5.將java源檔案動態編譯為.class檔案
類載入的最終結果是產生位於堆中的Class對象,Class對象封裝了類在方法區內的資料結構,並且向java程式員提供了存取方法區內的資料結構的介面
查看源碼得到Class對象只能由java虛擬機器來建立,其建構函式私人化
2.串連
1. 驗證:確保被載入的類的正確性(主要防止噁心的class檔案被載入)
2. 準備:為類的靜態變數分配記憶體,並將其初始化為預設值
3. 解析:把類中的符合引用轉換為直接引用
3.初始化
為類的靜態變數賦予正確的初始值
所有的java虛擬機器實現必須在每一個類或介面被java程式“首次主動使用”時才初始化
java對類的使用方式分為:主動使用,被動使用
主動使用有六種:(除這6種外,其他都是被動使用)
1。建立類的執行個體
2。訪問某個類或介面的靜態變數或對該靜態變數賦值
3。調用類的靜態方法
4。反射
5。初始化類的子類
6。java虛擬機器啟動時被標註位啟動類的類
4.類載入器Classloader
類載入器類型
1.java虛擬機器內建的類載入器:
-----根類載入器Bootstrap
該類載入器沒有父類載入器,它負責載入虛擬機器的核心類庫,如java.lang.String等,根類載入器用於在啟動JVM時載入類,以使JVM能正常工作,因而它是用Native(c++)代碼實現的,最早被建立出來,處於最底層。它並沒有繼承java.lang.ClassLoader類。
-----擴充類載入器Extension
該類載入器的父類載入器是根類載入器。它從java.ext.dirs系統屬性所指定的目錄擷取載入類庫或從JDK的安裝目錄的jre\lib\ext子目錄下載入類庫。如果把jar放到這個目錄下,也會自動用擴充類載入器載入。擴充類載入器是java類,是java.lang.ClassLoader類的子類
-----系統類別載入器System
也成為應用類載入器,它的父類載入器是擴充類載入器,它將載入CLASSPATH中配置的目錄和jar檔案,它是使用者自訂類載入器的預設父類載入器,系統類別載入器是java類,是java.lang.ClassLoader類的子類
2.使用者自訂類載入器:是java.lang.ClassLoader的子類,可以定義類載入器
類載入器機制
類載入器用來把類載入到java虛擬機器中,類載入過程採用的是父親委託機制,這種機制能很好的保證java平台的安全,因為在這種機制下使用者定義的類載入器不可能載入應由父載入器載入的可靠類,如java.lang.String總是由根類載入器載入。在此委託機制中,除了java的根類載入器以外,其餘的載入器都有且只有一個父載入器。
自訂類載入器
使用者自訂類載入器需要滿足父委託機制,預設系統類別載入器為其父載入器。要實現自訂載入器,只需要整合ClassLoader類,然後覆蓋findClass(String name)方法,該方法根據參數指定載入類的名字,返回對應的Class對象的引用
自訂類載入器類: MyClassLoader
package com.longpo.classloader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
private String name; //類載入器的名字
private String path="D:\\"; //載入類的路徑
private final String type=".class"; //class檔案的副檔名
public MyClassLoader(String name)
{
super();
this.name=name;
}
//指定父類載入器
public MyClassLoader(ClassLoader parent ,String name)
{
super(parent);//顯示指定該載入器的父載入器
this.name=name;
}
//設定載入class的路徑
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
public String toString() {
return "MyClassLoader :" + name ;
}
//讀取對應class檔案的位元據---這裡簡單讀取
private byte[] loadClassData(String name)
{
//根據要載入的類名找到對應的檔案
name=name.replace(".", "\\");//com.longpo.test目錄結構是\\
File file=new File(path+name+type);
//根據檔案大小來建立位元組數組
byte[]bytes=new byte[(int)file.length()] ;
try {
InputStream is = new FileInputStream(file);
int len=is.read(bytes);//返回讀取位元組的長度
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
//一定要重寫該方法
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
//得到class檔案的位元據
byte[]data=loadClassData(name);
return this.defineClass(name, data, 0,data.length);//返回class對象的引用
}
}
定義一個測試載入類:Simple
package com.longpo.classloader;
public class Simple {
public Simple( )
{
System.out.println("Simple的類載入器的名字是:"+this.getClass().getClassLoader());
}
}
測試自訂載入類:Test
package com.longpo.classloader;
public class Test {
public static void main(String[] args) throws Exception{
//loader1的父載入器預設是系統載入器--上面還有系統載入器,擴充載入器,根載入器
MyClassLoader loader1=new MyClassLoader("loader1");
loader1.setPath("D:\\lib\\loader1\\");//loader1載入路徑
//loader2的父載入器為loader1--上面有loader1載入器,系統載入器,擴充載入器,根載入器
MyClassLoader loader2=new MyClassLoader(loader1,"loader2");
loader2.setPath("D:\\lib\\loader2\\");//loader2載入路徑
//loader3的父載入器為null,即根載入器--上面只有根載入器
MyClassLoader loader3=new MyClassLoader(null,"loader3");
loader3.setPath("D:\\lib\\loader3\\");//loader3載入路徑
test(loader2);
test(loader3);
}
public static void test(ClassLoader loader)throws Exception{
Class clazz=loader.loadClass("com.longpo.classloader.Simple");//loadClas會自動調用findClass方法
Object object=clazz.newInstance();
}
}
此時把編譯好的class檔案發到對應載入器目錄的檔案夾裡面,我用的是Eclipse,可在項目的目錄的bin目錄下找到.class檔案
在Eclipse運行Test,得結果:
各個載入器的關係為
使用loader2載入Simple時,根據父親委託機制,會從根載入器開始嘗試載入,一直往下載入,之道系統類別載入器載入成功。使用loader3載入Simple,根據父親委託機制,先由根載入器載入,載入失敗後有loader3自己載入
原文地址 http://techfoxbbs.com/blog-1-2.html
java的類載入器ClassLoader