Java中的ClassLoader详细解释

java中的.java文件经过编译以后,就会生成类文件.class文件。class文件是以二进制字节码存放在硬盘中的。当我们需要使用或加载Java文件到JVM中的时候,会从硬盘中读取字节码的class文件,然后通过类加载器将class文件加载到JVM中。也就是说,所有的Java文件都是通过类加载器加载到JVM中的。当然类加载器也是一个Java文件。那么第一个类加载器又是如何加载到JVM中的呢?在启动JVM的时候,会调运一个本地方法findBootStrapClass方法加载最初始的那个ClassLoader,private
native Class findBootstrapClass(String name),这个本地方法使用C++编写的。

1.系统已有3种类加载器

1.1 BooststrapClassLoader(boot) 加载rt.jar下面的类(此加载器采用C++编写,一般开发中是看不到的)

1.2 ExtClassLoader  加载ExtClassLoader下面的类(ext文件夹下面的jar)

1.3 AppClassLoader  加载classpaht下面的类

我们写的类几乎都是通过AppClassLoader这个加载器加载到JVM中的。

2.类加载器的加载机制(双亲委托机制)

每一个类加载器都有一个对应的parentClassLoader。

2.1    系统类加载器的父子关系

自定义类加载器的父亲是AppClassLoader

AppClassLoader的父亲是ExtClassLoader

ExtClassLoader的父亲是BooststrapClassLoader

public class TestClassLoader {
    public static void main(String[] args) {
        // 当前对象的类加载器
        ClassLoader loader = new TestClassLoader().getClass().getClassLoader();
        // 从当前对象的类加载器想上找他的各个祖先
        while (loader != null) {
            System.out.println(loader.getClass().getName());
            loader = loader.getParent();
        }
        // 知道找到最后的祖先是null
        System.out.println(loader);
    }
}
输出:
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null

2.2    类加载器加载的顺序

类加载器是从根向下加载的

也就是boot-》ExiClassLoader -》AppClassLoader

当一个类需要被加载的时候,首先是由AppClassLoader加载器将其传递给其父亲ExtClassLoader,然后ExtClassLoader再将其传递给他的父亲boot。

当boot发现他的加载范围内有对应的class,就加载到JVM中,否则交给儿子ExtClassLoader处理。

ExtClassLoader再在他的加载范围类找有没有对应的class,有就加载到JVM中,没有就交给AppClassLoader处理。

AppClassLoader再在classpath路径下找对应的class,找到就加载,没有就报异常。

原因:这样可以保证JVM中某一个className对应的是同一个class,因为都是从根向下加载的。

避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。

要是从下向上加载,可能导致某一个className在JVM中对应好几个class。可能我们会定义自己的类加载器和自己的加载范围。

当自己定义的类加载在他们各自的范围都发现需要加载的类,那么他们可能都会加载,导致JVM中一个className对应好几个不同的class

2.3    比如我们自己定义一个类加载器去加载java.lang.String这个类,那么我们是不能达到我们目的的。

因为加载机制是从上到下加载,当传递到上面的boot的时候,已经被加载到JVM中,轮不到我们自定义的类加载器去加载它。

但是,我们肯定是可以自己定义一个类加载器去加载我们指定的类的。

3.如何自定义一个类加载

首先,我们需要继承ClassLoadar

然后,我们不能破坏原来的类加载机制(双亲委托机制),所以我们不能覆盖loadClass方法,我们需要覆盖findclass方法。

最后,在findClass方法中写入我们的类加载器的代码。

查看源码解释:

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // 首先检查name对应的Class是否已经被加载
        Class c = findLoadedClass(name);
        //如果没有被加载
        if (c == null) {
            long t0 = System.nanoTime();
            //尝试让parentClassLoader去加载
            try {
                if (parent != null) {
                    //当parent不为null的时候,让parent去loadClass
                    c = parent.loadClass(name, false);
                } else {
                    //当parent为null的时候,就调运本地方法
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {

            }
            //当parentClassLoader没有加载的时候
            if (c == null) {
                long t1 = System.nanoTime();
                //调运findClass方法去加载
                c = findClass(name);
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

4.举例

目标:自定义一个类加载器加我们指定路径下,经过我么加密的class。

过程:找到指定路径下的class文件,解密,加载到JVM中。

4.1先定义一个需要被加密编译的类,同时使用它进行测试

public class MyClass extends Date {
    @Override
    public String toString() {
        return "hello world";
    }
}

4.2加密原来的class文件

public static void main(String[] args) throws Exception {
    String inputSrc = args[0];//原来的class文件的路径和文件名
    String outputSrc = args[1];//加密以后存放的文件路径和文件名
    FileInputStream fis = new FileInputStream(inputSrc);
    FileOutputStream fos = new FileOutputStream(outputSrc);
    //调用加密算法
    cypher(fis, fos);
    fis.close();
    fos.close();
}

/**
 * 加密解密函数方法
 *
 * @param is
 * @param os
 * @throws IOException
 */
private static void cypher(InputStream is, OutputStream os) throws IOException {
    int b = -1;
    while ((b = is.read()) != -1) {
        // 将0变成1,将1变成0
        os.write(b ^ 0xff);
    }
}

4.3编写我们自己的类加载器

public class MyClassLoader extends ClassLoader {
    //要加载的类的路径
    private String classSrc;

    public MyClassLoader() {

    }

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

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //先找到自己的加密的class文件的位置
        String classFielName = classSrc + "\\" + name + ".class";
        try {
            FileInputStream fis = new FileInputStream(classFielName);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            //调运解密算法
            cypher(fis, baos);
            fis.close();
            byte[] bytes = baos.toByteArray();
            //将读出来的二进制转换为Class字节码
            return defineClass(null, bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return super.findClass(name);
    }
}

4.4使用我们自己的类加载加载我们加密的类到JVM中

//首先使用自己的类加载器去加载我们加密的class文件
//注意,这个地方的加载类的路径下的class应该是我们加密以后文件的位置
Class clazz = new MyClassLoader("E:/AllWorkspace/workspace1/classLoaderTest/bin/com/gusi/test").loadClass("MyClass");
//通过反射,测试我们的classLoader
Date date = (Date) clazz.newInstance();
System.out.println(date.toString());
时间: 2024-12-29 10:05:50

Java中的ClassLoader详细解释的相关文章

Android中Service的详细解释与使用

Android中Service的详细解释与使用: 概念: (1).Service可以说是一个在后台运行的Activity.它不是一个单独的进程,它只需要应用告诉它要在后台做什么就可以了. (2).它要是实现和用户的交互的话需要通过通知栏或者是通过发送广播,UI去接收显示. (3).它的应用十分广泛,尤其是在框架层,应用更多的是对系统服务的调用. 作用: (1).它用于处理一些不干扰用户使用的后台操作.如下载,网络获取.播放音乐,他可以通过INTENT来开启,同时也可以绑定到宿主对象(调用者例如A

Android中WebView的详细解释

Android中WebView的详细解释: 1. 概念: WebView(网络视图)能加载显示网页,可以将其视为一个浏览器.它使用了WebKit渲染引擎加载显示网页. 2. 使用方法: (1).实例化WebView组件: A.在Activity中实例化WebView组件.eg: WebView webView = new WebView(this); B.调用WebView的loadUrl()方法,设置WevView要显示的网页.eg: 互联网用:webView.loadUrl("http://

Java中的ClassLoader具体解说

java中的.java文件经过编译今后,号码大全就会生成类文件.class文件关键词挖掘工具.class文件是以二进制字节码寄存在硬盘中的.当咱们需求运用或加载Java文件到JVM中的时分,会从硬盘中读取字节码的class文件,然后经过类加载器将class文件加载到JVM中.也即是说,一切的Java文件都是经过类加载器加载到JVM中的.当然类加载器也是一个Java文件.那么第一个类加载器又是怎么加载到JVM中的呢?在发动JVM的时分,会调运一个本地办法findBootStrapClass办法加载

Android中时间戳的详细解释

Android中时间戳的详细解释: (1).定义: 时间戳就是根据当前系统时间生成的一组随机数字. (2).作用: 作为对数据唯一性的一种判断依据.避免了重复修改数据所带来的错误! (3).应用: (1).在银行account表中建立时间戳字段timestamp,设定为文本类型varchar. (2).当银行A读取account表中的存款字段时,同时也读取时间戳字段,比如123456. (3).当银行A修改完存款数值后,进行存盘操作时,将先前读取的时间戳123456与当时表中的时间戳进行一次对比

一看你就懂,超详细 java 中的 ClassLoader 详解

ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见.理解ClassLoader的加载机制,也有利于我们编写出更高效的代码.ClassLoader的具体作用就是将class文件加载到jvm虚拟机中去,程序就可以正确运行了.但是,jvm启动的时候,并不会一次性加载所有的class文件,而是根据需要去动态加载.想想也是的,一次性加载那么多jar包那么多class,那内存不崩溃.本文的目的也是学习ClassLoader这种加载机制. 备注:

一看你就懂,超详细java中的ClassLoader详解

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见.理解ClassLoader的加载机制,也有利于我们编写出更高效的代码.ClassLoader的具体作用就是将class文件加载到jvm虚拟机中去,程序就可以正确运行了.但是,jvm启动的时候,并不会一次性加载所有的class文件,而是根据需要去动态加载.想想也是的,一次性加载那么多jar包那么多class,那内存不

Java中的statickeyword具体解释

1.statickeyword主要有2个作用: ①为某特定的数据类型或者对象分配单一的存储空间.而与创建对象的个数无关. ②在不创建对象的情况下能够直接通过类名来直接调用方法或者使用类的属性. 2.static主要有4种使用情况:成员变量(属性),成员方法.代码块,和内部类 3.Java中没有全局变量的概念.可是能够通过static来实现全局变量的效果. Java中提供了2种类型的变量:①用static修饰的静态变量②实例变量 他们的差别是静态变量时属于类的,仅仅要静态变量所在的类被载入.就会被

java中的subString具体解释及应用

substring(參数)是java中截取字符串的一个方法 有两种传參方式 一种是public String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串. 该子字符串从指定索引处的字符開始,直到此字符串末尾. 还有一种是public String substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串.该子字符串从指定的 beginIndex 处開始,直到索引 endIn

Java中对于ClassLoader类加载器 嵌套了深度技术的价值

关于Java技术是一种不断兴起的编程语言,对于ClassLoader 是 Java 届最为神秘的技术之一,无数人被它伤透了脑筋,摸不清门道究竟在哪里.本文我带你彻底吃透 ClassLoader,让你甚至Java类加载器的神奇之处  1.ClassLoader 做什么的? 顾名思义,它是用来加载 Class 的.它负责将 Class 的字节码形式转换成内存形式的 Class 对象.字节码可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流,