学习类的主动加载和被动加载,类的主动加载和被动加载的区别就是是否激活了Clinit()函数。
Clinit()函数的作用是对类的静态变量赋值,所以类是否激活Clinii()函数的外在表现就是是否触发了stattic代码块的内容。
类的主动加载和被动加载是互斥的,因此学习一个就会知道另一个,所以先看情况比较好记的被动加载。
类被动加载情况总结
class Parent{
static{
System.out.println("Parent的初始化过程");
}
public static int num = 1;
}
class Child extends Parent{
static{
System.out.println("Child的初始化过程");
}
}
public class PassiveUse1 {
@Test
public void test1(){
System.out.println(Child.num);
}
}
执行结果只会输出Parent的初始化过程
,而Child作为子类并没有被初始化
class Parent{
static{
System.out.println("Parent的初始化过程");
}
public static int num = 1;
}
class Child extends Parent{
static{
System.out.println("Child的初始化过程");
}
}
public class PassiveUse1 {
@Test
public void test2(){
Parent[] parents = new Parent[10];
}
}
执行后不会输出任何结果
class Person{
static{
System.out.println("Person类的初始化");
}
public static final int NUM = 1;//在链接过程的准备环节就被赋值为1了。
public static final String string = "qbc";//在链接过程的准备环节就被赋值为qbc了。
public static final int NUM1 = new Random().nextInt(10);//此时的赋值操作需要在()中执行
}
public class PassiveUse2 {
@Test
public void test1(){
System.out.println(Person.NUM);
}
}
执行后不会输出Person类的初始化
如果这个常量是一个对象,那就会触发初始化方法,因为在链接阶段不会进行赋值操作,除非常量是一个固定的数字在编译阶段已经赋值.静态变量和常量对象赋值操作都需要初始化操作(初始化阶段会真正执行代码)
class Person{
static{
System.out.println("Person类的初始化");
}
public static final int NUM = 1;//在链接过程的准备环节就被赋值为1了。
public static final int NUM1 = new Random().nextInt(10);//此时的赋值操作需要在()中执行
public static final String string = "qbc";
}
public class PassiveUse2 {
@Test
public void test1(){
System.out.println(Person.NUM1);
}
}
执行结果会输出Person类的初始化
class Person{
static{
System.out.println("Person类的初始化");
}
public static final int NUM = 1;//在链接过程的准备环节就被赋值为1了。
public static final int NUM1 = new Random().nextInt(10);//此时的赋值操作需要在()中执行
public static final String string = "qbc";
}
public class PassiveUse2 {
@Test
public void test3(){
try {
Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.hhh.java1.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
执行结果不会输出Person类的初始化
class Father {
static {
System.out.println("Father类的初始化过程");
}
}
class Son extends Father implements CompareB{
static {
System.out.println("Son类的初始化过程");
}
public static int num = 1;
}
interface CompareB {
public static final Thread t = new Thread() {
{
System.out.println("CompareB的初始化");
}
};
public static int NUM1 = new Random().nextInt();
}
测试用例1
public class ActiveUse3 {
@Test
public void test2() {
System.out.println(Son.num);
}
}
执行结果Father类的初始化过程 Son类的初始化过程
,可以发现接口没执行clinit()
测试用例2
public class ActiveUse3 {
@Test
public void te(){
System.out.println(Son.NUM1 );
}
}
执行结果CompareB的初始化
,发现调用接口的静态方法会触发接口的Clinit()
测试用例3
// 修改CompareB接口,加入default方法
interface CompareB {
public static final Thread t = new Thread() {
{
System.out.println("CompareB的初始化");
}
};
public static int NUM1 = new Random().nextInt();
public default void method1(){
System.out.println("你好!");
}
}
public class ActiveUse3 {
@Test
public void test2() {
System.out.println(Son.num);
}
}
执行结果CompareB的初始化
发现接口也初始化了,这说明了接口定义defaut方法,子类初始化,接口也会一起被初始化。