JAVA类加载小记

在java 编译完成之后,就是java对象的加载了。实际上是对class文件的查找,将字节码文件放入内存当中。

在这前先了解下双亲委派模式:一个类在被加载时,首先该类会委派到APPClassLoader去加载,然后AppClassLoader再委派给EXTClassLoader去加载,ExtClassLoader又会委派给BootStrapClassLoader去加载,BootstrapClassLoader做为最顶层的一环,也是作为java native的方法(即C++代码实现的),主要加载java环境配置变量里面,JAVA_HOME 下面的lib文件夹下面的直属jar包,根据路劲去这些jar包中去加载ExtClassLoader委托给它的类,如果没找到,就由ExtClassLoader去加载该类,而ExtClassLoader主要加载JAVA_HOME下面的lib文件夹下面的EXT文件夹下面的jar包,如果ExtClassLoader也找不到该类,就由APPClassLoader去加载该类,APPClassLoader主要加载classpath下面的jar包,如果AppClassLoader没加载到该类,就交由自定义的ClassLoader去加载,下面代码示例有自定义ClassLoader的加载,如果自定义的ClassLoader仍未加载到该类,就会抛出无法加载该类的异常信息。

上面描述了双亲委派的加载模式,为什么要用该模式呢?直接找不是很方便吗?又耗性能,又费时间的。。。

其实,主要是出于java安全方面考虑;假如说自定义了一个类名叫:java.lang.String,我们都知道java类库里面就有该类,那么虚拟机究竟要用哪个类?答案是会用类库里面的这个类,自定义的这个类,始终是不会被用到的,不妨可以去试试,正所谓,天大地大,java类库的优先级最大。但用到该模式或许还有其他目的,可以评论指点。好了,直接代码;

一般分两种情况

1.在项目target/classes的目录下直接利用Class.forName(""),或

ClassLoader.getSystemClassLoader().loadClass(""),即可。

2.外部class文件(不在target/classes目录下),加载java类,即自定义ClassLoader,

需要新建类并继承ClassLoader,重写findClass方法具体代码如下:

public class MyClassLoad extends ClassLoader {

    private String classPath;

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        MyClassLoad myClassLoad = new MyClassLoad();
        myClassLoad.setClassPath("src/main/resources/templates/com/microcore/rpc/modul/");
        Class<?> aClass = myClassLoad.loadClass("com.microcore.rpc.modul.User");
        Object o = aClass.newInstance();
        System.out.println(o);
    }


    @Override
    public Class<?> findClass(String s) throws ClassNotFoundException {
        byte[] bytes = null;
        try {
            bytes = loadClassData(s);
            return defineClass(s, bytes, 0, bytes.length);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  super.findLoadedClass(s);
    }

    private byte[] loadClassData(String name) throws IOException {
        File file = getFile(name);
        FileInputStream inputStream = new FileInputStream(file);
        byte[] arrData = new byte[(int) file.length()];
        inputStream.read(arrData);
        return arrData;
    }

    private File getFile(String name){
        File dir  = new File(name);
        if(!dir.exists()){
            System.out.println("不存在");
        }
        String _classPath = classPath.replaceAll("[\\\\]","/");
        int offset = _classPath.lastIndexOf("/");
        if(offset!=-1&&offset<_classPath.length()-1){
            _classPath+="/";
        }
        _classPath+=name+".class";
        dir = new File(_classPath);
        if(!dir.exists()){
            System.out.println("不存在");
        }
        return dir;
    }

    public String getClassPath() {
        return classPath;
    }

    public void setClassPath(String classPath) {
        this.classPath = classPath;
    }
}

代码中:

myClassLoad.setClassPath("src/main/resources/templates/com/microcore/rpc/modul/");

classpath为,class文件在项目中的相对路劲,也可写带盘符的,

myClassLoad.loadClass("com.microcore.rpc.modul.User");

loadclass参数为需要加载class文件的全限定名,及类的包路径。面对加载也存在两个类之间的引用问题(一个类里面有另外一个类的引用包路径),如果是在同一个指定的文件夹下,这里只需要解决defineClass方法入参,即路劲问题就可以。如果是第三方jar包里面,那么要解压jar包,将解压后的class文件和该引用的class文件放在同一文件夹下,然后才能引入。

里面最核心的一段代码:

defineClass(s, bytes, 0, bytes.length);

传入class文件路劲,class的字节流,以及字节流的长度。目的时找到该字节码文件,并加载到内存当中;

上述为两种加载class文件到内存的方法。多提建议,谢谢!

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焱墩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值