加载
一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以去完成还可以自定义类加载器去控制字节流的获取方式(重写一个类加载器的 loadClass() 方法)。数组类型不通过类加载器创建,它由 Java 虚拟机直接创建。<br><br><br><br>
初始化
于初始化阶段,虚拟机严格规范了有且只有5种情况下,必须对类进行初始化(只有主动去使用类才会初始化类):<br><br><br><br>当遇到 new 、 getstatic、putstatic或invokestatic 这4条直接码指令时,比如 new 一个类,读取一个静态字段(未被 final 修饰)、或调用一个类的静态方法时。<br><br>当jvm执行new指令时会初始化类。即当程序创建一个类的实例对象。<br><br>当jvm执行getstatic指令时会初始化类。即程序访问类的静态变量(不是静态常量,常量会被加载到运行时常量池)。<br><br>当jvm执行putstatic指令时会初始化类。即程序给类的静态变量赋值。<br><br>当jvm执行invokestatic指令时会初始化类。即程序调用类的静态方法。<br><br>使用 java.lang.reflect 包的方法对类进行反射调用时如Class.forname("..."),newInstance()等等。 ,如果类没初始化,需要触发其初始化。<br><br>初始化一个类,如果其父类还未初始化,则先触发该父类的初始化。<br><br>当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main 方法的那个类),虚拟机会先初始化这个类。<br><br>MethodHandle和VarHandle可以看作是轻量级的反射调用机制,而要想使用这2个调用, 就必须先使用findStaticVarHandle来初始化要调用的类。
卸载
卸载类需要满足3个要求:<br><br><br><br>该类的所有的实例对象都已被GC,也就是说堆不存在该类的实例对象。<br><br>该类没有在其他任何地方被引用<br><br>该类的类加载器的实例已被GC<br><br>所以,在JVM生命周期类,由jvm自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。<br><br><br><br>只要想通一点就好了,jdk自带的BootstrapClassLoader,PlatformClassLoader,AppClassLoader负责加载jdk提供的类,所以它们(类加载器的实例)肯定不会被回收。而我们自定义的类加载器的实例是可以被回收的,所以使用我们自定义加载器加载的类是可以被卸载掉的。