ClassLoader类加载器

ClassLoader

  在Java语言中提供了一个系统的环境变量:CLASSPATH,这个环境属性的作用主要是在JVM进程启动时进行类加载路径的定义,在JVM中可以根据类加载器而后进行指定路径中类的加载,也就是说找到了类的加载器就意味着找到了类的来源。

ClassLoader

系统类加载器

  如果现在要想获得类的加载器,那么一定要通过ClassLoader来获取,而要想获取ClassLoader类的对象,则必须利用Class类(反射的根源)实现,方法:
    public ClassLoader getClassLoader()
  当获取了ClassLoader后还可以获取其父类的ClassLoader类对象:
    public final ClassLoader getParent​()
范例:观察类加载器

class Message{}
public class JavaAPIDemo {
    public static void main(String[] args)throws Exception{
        Class<?> clazz=Message.class;
        ClassLoader loader=clazz.getClassLoader();//获取当前类的加载器
        System.out.println(loader);
        //1.8:sun.misc.Launcher$AppClassLoader@18b4aac2
        //1.9+:jdk.internal.loader.ClassLoaders$AppClassLoader@4f8e5cde
        loader=loader.getParent();//获取父类加载器
        System.out.println(loader);
        //1.8:sun.misc.Launcher$ExtClassLoader@60e53b93
        //1.9+:jdk.internal.loader.ClassLoaders$PlatformClassLoader@16f65612
        loader=loader.getParent();//获取祖父类加载器
        System.out.println(loader);//null
    }
}

从JDK1.9+版本提供有一个“PlatformClassLoader”类加载器,而在JDK1.8及以前的版本中提供的加载器为“ ExtClassLoader”,因为在JDK的安装目录中提供了一个ext的目录,开发者可以将*.jar文件拷贝到此目录中,这样就可以直接执行了,但是这样的处理开发并不安全,最初时也是不提倡使用的,所以从JDK1.9开始将其彻底废除,同时为了与系统类加载器和应用类加载器之间保持设计的平衡,提供有平台类加载器。

当你获得了类加载器后就可以利用类加载器来实现类的反射加载处理:
  protected Class<?> findClass​(String name) throws ClassNotFoundException

自定义类加载器

  清楚了类加载器的功能后就可以根据自身的需求来实现自定义的类加载器,但是千万要记住一点:自定义的类加载器其加载的顺序是在所有系统类加载器的最后。系统类中的类加载器都是根据CLASSPATH路径进行加载的,而如果有了自定义的类加载器,就可以由开发者任意指定类的加载位置。

自定义类加载器

1、随意编写一个程序类,并且将这个类保存在磁盘上。

public class Message {
    public void send(){
        System.out.println("www.baidu.com");
    }
}

2、将此类直接拷贝到系统磁盘上(非项目路径)进行编译处理,并且不打包,所以这个类无法通过CLASSPATH正常加载。
  javac /Users/david/Documents/mydir/Message.java
3、自定义一个类加载器,并且继承自ClassLoader类。在ClassLoader类中提供有一个字节转换为类结构的方法:

  • 定义类:
      protected final Class<?> defineClass​(String name, byte[] b, int off, int len) throws ClassFormatError
import java.io.*;
public class MLDNClassLoader extends ClassLoader {
    private static final String MESSAGE_CLASS_PATH = "/Users/david/Documents/mydir/Message.class";
    /**
     * 进行指定类的加载
     *
     * @param className 类的完整名称“包.类”
     * @return 返回一个指定类的Class对象
     * @throws Exception 如果类文件不存在,则无法加载
     */
    public Class<?> loadData(String className) throws Exception {
        byte[] data = loadClassData();//读取二进制数据文件
        if (data == null) {
            return null;
        }
       return defineClass(className,data,0,data.length);
    }
    private byte[] loadClassData() throws Exception {//通过文件进行类的加载
        InputStream input = null;
        ByteArrayOutputStream bos = null;//将数据加载到内存之中
        try {
            bos=new ByteArrayOutputStream();   
            input = new FileInputStream(new File(MESSAGE_CLASS_PATH));//文件加载流
            input.transferTo(bos);//读取数据
            return bos.toByteArray();//将所有读取到的字节数取出
        } catch (Exception e) {

        } finally {
            if (input != null) {
                input.close();
            }
            if (bos != null) {
                bos.close();
            }
        }
        return null;
    }
}

4、编写测试类实现类加载控制。

import  java.lang.reflect.Method;
public class JavaAPIDemo {
    public static void main(String[] args)throws Exception{
        MLDNClassLoader classLoader = new MLDNClassLoader();//实例化自定义类加载器
        Class<?> clazz=classLoader.loadData("com.mldn.demo.Message");
        Object obj = clazz.getDeclaredConstructor().newInstance();
        Method method = clazz.getDeclaredMethod("send");
        method.invoke(obj);
    }
}

如果在以后结合网络程序开发的话,就可以通过一个远程的服务器来确定一个类的功能。

5、观察当前的Message类的加载器的情况

public class JavaAPIDemo {
    public static void main(String[] args)throws Exception{
        MLDNClassLoader classLoader = new MLDNClassLoader();//实例化自定义类加载器
        Class<?> clazz=classLoader.loadData("com.mldn.demo.Message");
        System.out.println(clazz.getClassLoader());//com.mldn.demo.MLDNClassLoader@3f0ee7cb
        System.out.println(clazz.getClassLoader().getParent());//jdk.internal.loader.ClassLoaders$AppClassLoader@4f8e5cde
        System.out.println(clazz.getClassLoader().getParent().getParent());//jdk.internal.loader.ClassLoaders$PlatformClassLoader@3c679bde
    }
}

如果现在定义了一个类:java.lang.String,并且利用了自定义的类加载器进行加载处理,这个类将不会被加载,Java中针对于类加载器有双亲加载机制,如果现在要加载的程序类是由系统提供的类则会由系统类加载器进行加载,在开发者定义的类与系统类名称相同,那么为了保证系统的安全性绝对不会加载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容

  • 作者:成 富, 软件工程师, IBM 中国软件开发中心 类加载器(class loader)是 Java™中的一个...
    Android技术研究阅读 3,878评论 0 74
  • 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个...
    dinel阅读 412评论 0 0
  • JAVA类装载方式,有两种: 1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器...
    代码之尖阅读 642评论 0 49
  • JVM类加载机制 概述 类加载过程 加载 通过类的全限定名获取类的二进制流 将静态存储结构转化为方法区的运行时数据...
    东溪95阅读 2,961评论 0 15
  • 画了不少画,吃了不少肉,喝了不少酒
    陈围阅读 164评论 0 0