001--java类的热替换

所谓类的热替换,是指程序在运行的时候,对方法区的类定义进行替换,因为堆中的Class对象是对方法区对象的封装,所以也可以理解为对Class对象的替换。

java热替换的前提是要替换的类必须是自定义类加载器加载的,否则替换不了。至于原因,跟java类加载器的父委托机制有关系。

java的类加载采取的是父委托机制,使用这种机制的好处是:为了安全,在这种机制下,用户自定义的类加载器不可能加载应该由父类加载器加载的可靠类。从而防止由父类加载的可靠代码被恶意修改。举个栗子,java.lang.String类只能由bootstrap加载,而不能由我们自定义的加载器加载(如果不是父委托机制,我们完全可以自己写一个java.lang.String类,然后通过自定义的加载器加载到程序中)。

我们知道,不同的类加载器可以重复加载已经加载过的类(前提是这个类必须是由自定义加载器加载,而没有用到java自带的加载器),加载后这些类处于不同的命名空间,是相互不可见的。

自定义类加载器需要继承ClassLoader类,调用loadClass(String className)方法来加载类。此时需要重写findClass(String className)方法。关于这个的详细写法,可以自行google。

这里介绍用URLClassLoader来加载类。我们自己的类一般是打成jar包,放在一个目录下,然后用加载器来加载。

        //file是协议名称,后面是1个斜杠,2个斜杠会出错
        path = "file:/e:/github/classloader/teacher_b.jar";
        url = new URL(path);
        classLoader = new URLClassLoader(new URL[]{url});
        clazz = classLoader.loadClass("com.classloader.interfaces.imp.Teacher");
执行loadClass方法,就是单纯的把类加载到内存,并不是对类的主动使用(主动使用分6种情况),不会引起类的初始化。

此时获得了Class对象,目标其实已经达成。后面只需要用反射生产类的对象,然后把这个对象替换以前的对象就可以了。

如果程序写的再完美一点,可以把老的Class给卸载掉,注意,只有自定义类加载器加载的类才可以卸载。
卸载的办法很简单,保持类对象,Class对象,classloader对象的引用是null,jvm就会把他们当作是垃圾,会在适当的时候,卸载掉方法区中的二进制数据。   

多写一点额外的内容,类加载器的命名空间
命名空间由加载器和所有的父加载器所加载的类构成。在同一个命名空间中,不可能出现类名相同的两个类。在不同的命名空间中,可能出现类名相同的两个类(类名指类全称)。由子加载器加载的类能看见父加载器加载的类,反之不可以,比如java.lang.String类,我们自己写的类肯定能看见,但是它肯定看不见我们自己定义的类。如果两个加载器之间没有直接或者间接的父子关系,那么两个加载器加载的类是相互不可见的。
有一种访问控制级别叫做包可见,只有是同一个类加载器加载的同一个包下的类才能包可见(例如自己定义的java.lang.SS类是不能访问java.lang包里包可见的方法的)。以上是大白话,有个专有词汇叫做运行时包。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值