天天看點

jvm---類加載器(1)

文章目錄

  • ​​1.jvm虛拟機記憶體模型​​
  • ​​2.類加載過程​​
  • ​​3.類加載器:​​
  • ​​4. 檢視jvm位元組碼執行情況​​
  • ​​5. 自定義類加載器 和類加載器不生效的處理​​

1.jvm虛拟機記憶體模型

類加載子系統
    運作時資料區:  堆
                  棧
                  本地方法棧
                  方法區(元空間):常量+靜态變量+類元資訊
                  程式計數器
    位元組碼執行引擎
      

2.類加載過程

加載; 在硬碟上查找并通過IO讀入位元組碼檔案,使用類時才會加載,例如調用類的main()方法,new對象等等
 驗證: 校驗位元組碼檔案的正确性
 準備: 給類的靜态變量配置設定記憶體,并賦予預設值
 解析: 将符号引用替換為直接引用,該階段會把一些靜态方法(符号引用,比如main()方法)替換為指向資料所存記憶體的指針,
      或句柄等(直接引用),這是所謂的靜态連接配接過程(類加載期間完成),動态連結是在程式運作期間完成的将符号引用替換為
      直接引用
 初始化: 對類的靜态變量初始化為指定的值,執行靜态代碼塊      
public class Tuling {
   public static void main(String[] args) {
       System.out.println(String.class.getClassLoader());
       System.out.println(com.sun.crypto.provider.DESedeKeyFactory.class.getClassLoader().getClass().getName());
       System.out.println(Tuling.class.getClassLoader().getClass().getName());
       System.out.println(ClassLoader.getSystemClassLoader().getClass().getName());
   }      

運作結果:

null

sun.misc.Launcher$ExtClassLoader

sun.misc.Launcher$AppClassLoader

sun.misc.Launcher$AppClassLoader

3.類加載器:

啟動類加載器: jvm運作的位于jre/lib 目錄下的核心類庫 比如:rt.jar, charsets.jar等

擴充類加載器: 負責加載 位于jie的lib目錄下的ext擴充目錄中的jar類包

應用程式類加載器: 負責加載classPath路徑下的類包,主要就是加載你自己寫的那些類

自定義加載器:負責加載使用者自定義路徑下的類包

4. 檢視jvm位元組碼執行情況

  • javap -c Tuling.class

5. 自定義類加載器 和類加載器不生效的處理

  • 自定義類加載器
package com.tuling;

/**
 * Title: User
 * Description: TODO
 *
 * @author hfl
 * @version V1.0
 * @date 2020-11-23
 */
public class User {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("關閉資源,user " + name + "即将回收");
    }

    public void sout(){
        System.out.println("=============自己的加載器加載類調用方法============");
    }

}      
package com.tuling;

import java.io.FileInputStream;
import java.lang.reflect.Method;

/**
 * Title: MyClassLoaderTest
 * Description: TODO
 *
 * @author hfl
 * @version V1.0
 * @date 2020-11-23
 */
public class MyClassLoaderTest {
    static class MyClassLoader extends ClassLoader {
        private String classPath;

        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

        private byte[] loadByte(String name) throws Exception {
            name = name.replaceAll("\\.", "/");
            FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");
            int len = fis.available();
            byte[] data = new byte[len];
            fis.read(data);
            fis.close();
            return data;
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {

            try {
                byte[] data = loadByte(name);
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        MyClassLoader classLoader = new MyClassLoader("D:/test");
        Class<?> clazz = classLoader.loadClass("com.tuling.User");
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("sout", null);
        method.invoke(obj, null);
        System.out.println(clazz.getClassLoader().getClass().getName());
    }
}      

運作結果: