Class进入到内存有三大步,分别是loading,linking,initlalizing.
上一次说到为什么要搞双亲委派模式,主要是为了安全,如果任何一个class都可以把它load到内存中,打包给客户,然后把密码存储成String对象,我可以把密码发给自己,那就不安全了,双亲委派就不会出现这样,自定义ClassLoader加载一个java.lang.String他就产生了警惕,他先去上面查有没有加载过,上面有加载过直接返回给你,不给你重新加载。
接下来继续讲加载器
加载器父加载器不是“类加载器的加载器”,也不是“类加载器的父类加载器”。
可以看看累加载器的范围,它是来自于Launcher的源码。打印一个Class文件的toString的方法他默认显示是类的名字加上后面一个哈希code码。这个类的名字是什么意思呢?是sun->misc包下面的Launcher类,这个类下面有一个内部类叫ExeClassLoader,Launcher就是ClassLoader一个包装类启动类,在这个类里面可以看出,Bootstrap它加载的路径是我们核心路径而ext.dirs这个属性指定的哪些路径呢,为什么我们的AppClassCloader指定的是java.class.path这个路径呢?其实所有的代码都来自与Launcher的源码。
自定义类加载器
自定义类加载器有几个步骤:
1.继承Classloader
2.重写模板方法findClass
-调用defineClass
3.自定义类加载器加载自加密的class
-防止反编译
-防止篡改
简单的说就是从classloader继承,继承完了之后重写它的findClass方法,在finanClass方法中,找到load进来的那个二进制的内容,load完了之后再把这部分的内容转换成class类对象,用defindclass。自己编译好了,手动加密。
lazylaoding
jvm虚拟机的实现都是用的懒加载就是什么时候需要这个类的时候我才去加载
严格的讲应该叫lazyInitializing,jvm规范并没有规定何时加载,但是严格规定了什么时候必须初始化
-new getstatic putstatic invokestatic指令,访问final变量除外
-java.lang.reflect对类进行反射调用时
-初始化子类的时候,父类首先初始化
-虚拟机启动时,被执行的主类必须初始化
-动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstatic REF_getstatic REF_invokestatic的方法句柄时,该类必须初始化。