JVM类的加载机制

1.类的初始化过程

2.触发类的初始化情况

3.双亲委派机制

    Java向上委派加载,只有当上层找不到对应的class文件时,才会交给下一级类加载器加载

4.类加载的时序图

 5.自定义类加载器

         1.验证类加载顺序

package com.roger.classloader;

import com.sun.java.accessibility.util.EventID;

public class ClassLoaderMain {

    public static void main(String[] args) {
        System.out.println("java.lang.String-在%JAVA_HOME%\\lib\\目录下的jar包中");
        System.out.print("使用的类加载器为-");
        System.out.println(String.class.getClassLoader());
        System.out.println("com.sun.java.accessibility.util.EventID-在%JAVA_HOME%\\lib\\ext\\目录下的jar包中");
        System.out.print("使用的类加载器为-");
        System.out.println(EventID.class.getClassLoader());
        System.out.println("com.roger.classloader.ClassLoaderMain-在%CLASSPATH%目录下");
        System.out.print("使用的类加载器为-");
        System.out.println(ClassLoaderMain.class.getClassLoader());
    }
}

    运行结果:

java.lang.String-在%JAVA_HOME%\lib\目录下的jar包中
使用的类加载器为-null
com.sun.java.accessibility.util.EventID-在%JAVA_HOME%\lib\ext\目录下的jar包中
使用的类加载器为-sun.misc.Launcher$ExtClassLoader@45ee12a7
com.roger.classloader.ClassLoaderMain-在%CLASSPATH%目录下
使用的类加载器为-sun.misc.Launcher$AppClassLoader@18b4aac2

     2.自定义类加载器

package com.roger.classloader;

import java.io.*;

/**
 * 自定义类加载器的步骤
 * 1.继承java.lang.ClassLoader类
 * 2.重写findClass()方法 --- 找到要加载的class文件,并转换成字节流
 * 3.调用defineClass方法 --- 把findClass()方法找到的字节流转换成jvm认识的Class类型
 * 4.使用自定义的类加载器的方法是:
 *      调用其父类的loadClass(String name)方法
 *
 *  如果想破换双亲委派机制
 *     只需要重写 ClassLoader的loadClass(String name) 方法
 */
public class CustomClassLoader extends ClassLoader {

    private static final String EXT = ".class";

    //自定义类加载器的加载路径
    private String classPath;

    public CustomClassLoader(String classPath, ClassLoader parent) {
        super(parent);
        this.classPath = classPath;
    }

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

    @Override
    protected Class<?> findClass(String className) throws ClassNotFoundException {
        byte[] clazzBytes = loadClassBytes(className);
        if (clazzBytes == null) {
            throw new ClassNotFoundException("该类不存在,类名为" + className);
        }
        return super.defineClass(className, clazzBytes, 0, clazzBytes.length);
    }

    private byte[] loadClassBytes(String className) {
        String classFilePath = getClassFileAllPath(className);
        ByteArrayOutputStream bout = null;
        InputStream fin = null;
        try {
            fin = new FileInputStream(classFilePath);
            bout = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = fin.read(bytes)) != -1) {
                bout.write(bytes, 0, len);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException("该类文件不存在,文件路径为:" + classPath);
        } catch (IOException e) {
            throw new RuntimeException("该类文件内容损坏,无法读取,文件路径为:" + classPath);
        } finally {
            try {
                if (fin != null) {
                    fin.close();
                }
                if (bout != null) {
                    bout.close();
                }
            } catch (IOException e) {

            }
        }
        return bout.toByteArray();
    }


    private String getClassFileAllPath(String className) {
        String filePathName = className.replace(".", File.separator);
        if (classPath.endsWith("/") || classPath.endsWith("\\")) {
            return classPath + filePathName + EXT;
        }
        return classPath + File.separator + filePathName + EXT;
    }

    public static void main(String[] args) {
        String classPath = "F:\\test";
        CustomClassLoader customClassLoader = new CustomClassLoader(classPath);
        try {
            Class<?> StringClass = customClassLoader.loadClass("java.lang.String");
            System.out.println("调用Java核心包的类-类加载器为:" + StringClass.getClassLoader());

            Class<?> eventIdClass = customClassLoader.loadClass("com.sun.java.accessibility.util.EventID");
            System.out.println("调用Java扩展包的类-类加载器为:" + eventIdClass.getClassLoader());

            Class<?> classLoaderMainClass = customClassLoader.loadClass("com.roger.classloader.ClassLoaderMain");
            System.out.println("调用Classpath路径下的类-类加载器为:" + classLoaderMainClass.getClassLoader());

            Class<?> customArithClass = customClassLoader.loadClass("com.roger.classloader.Arith");
            System.out.println("调用自定义的类加载路径-类加载器为:" + customArithClass.getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

     运行路劲:

调用Java核心包的类-类加载器为:null
调用Java扩展包的类-类加载器为:sun.misc.Launcher$ExtClassLoader@45ee12a7
调用Classpath路径下的类-类加载器为:sun.misc.Launcher$AppClassLoader@18b4aac2
调用自定义的类加载路径-类加载器为:com.roger.classloader.CustomClassLoader@2503dbd3

在准备class文件的时候,遇到编码GBK不可映射字符:

         

  通过下面命令解决:

 javac -encoding utf-8 CountDownLatchMain.java

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值