JVM中的类加载过程分析——2.初识类加载方式

目录

1.先给大家提3个问题:

        1)通过类型定义变量,类会被加载吗?        2)类加载时一定会执行静态代码块吗?        3)类加载时什么时候会执行静态代码块呢?

第一题的答案是定义变量的形式是不会加载ClassA的。

第二题的答案也显而易见:不是所有的类加载时都会执行静态代码块, 要分情况而论。

第三题的答案就是:当类采用隐式加载 时会执行静态代码块,当类调用Class.forName方法执行时,默认会执行静态代码块,注意是默认,一旦修改了其中的initialize参数,也不会执行静态代码块。


1.先给大家提3个问题:

        1)通过类型定义变量,类会被加载吗?
        2)类加载时一定会执行静态代码块吗?
        3)类加载时什么时候会执行静态代码块呢?
 

        我们带着这3个问题去认识我们Java中的类加载器,平时你是感觉不到它的存在的,但是它又确实是存在而且不可或缺的。如果没有它,我们的类就无法正常运行加载。我们观察以下代码:
 

class ClassA{
    public static int a=10;
    static{
        System.out.println("ClassA.static{}");
    }
}
public class ClassLoaderTraceTests {
    public static void main(String[] args) throws ClassNotFoundException {
        ClassA clsA=null;//通过类型定义变量clsA 观察是否加载ClassA
    }
}

我们可以看到没有任何控制台输出,也就证明是没有加载ClassA这个类的。

第一题的答案是定义变量的形式是不会加载ClassA的。

接着看下面的代码:

class ClassA{
    public static int a=10;
    static{
        System.out.println("ClassA.static{}");
    }
}
public class ClassLoaderTraceTests {
    public static void main(String[] args) throws ClassNotFoundException {
        //ClassA clsA=null;//定义变量的形式是不会加载ClassA的
        int a=ClassA.a;
        System.out.println(a);
       
    }
}

 我们定义一个变量a 并把ClassA中的静态成员变量a赋值给它,我们看下控制台输出的结果:

 可以看到在我们做赋值时,隐式的加载了ClassA这个类,并且执行了静态代码块,也就是说隐式加载时,这个类会被读到内存中,并同时执行静态代码块,接着看下面的代码:
 

class ClassA{
    public static int a=10;
    static{
        System.out.println("ClassA.static{}");
    }
}
public class ClassLoaderTraceTests {
    public static void main(String[] args) throws ClassNotFoundException {
        //ClassA clsA=null;//定义变量的形式是不会加载ClassA的
//        int a=ClassA.a;//隐式加载(ClassA这个类会被读到内存,并且执行静态代码块)
//        System.out.println(a);
        ClassLoader.getSystemClassLoader()
              .loadClass("com.java.jvm.loader.ClassA") ;//显式加载,此时静态代码块不会执行
              
    }
}

用ClassLoader类中的loadClass加指定类的全限定名的方式去 加载一个类,就是显示加载,我们来看下结果:

显示加载的方式,静态代码块不会执行。


第二题的答案也显而易见:不是所有的类加载时都会执行静态代码块, 要分情况而论。

我们继续看以Class.forName形式加载类时的情况:
 

class ClassA{
    public static int a=10;
    static{
        System.out.println("ClassA.static{}");
    }
}
public class ClassLoaderTraceTests {
    public static void main(String[] args) throws ClassNotFoundException {
        //ClassA clsA=null;//定义变量的形式是不会加载ClassA的
//        int a=ClassA.a;//隐式加载(ClassA这个类会被读到内存,并且执行静态代码块)
//        System.out.println(a);
//        ClassLoader.getSystemClassLoader()
//               //显式加载,此时静态代码块不会执行
//              .loadClass("com.java.jvm.loader.ClassA") ;
          Class.forName("com.java.jvm.loader.ClassA");
    }
}

运行结果如下:

可以看到这种加载的形式,类会加载,同时静态代码块也执行了。同时还可以在forName这个方法中增加参数以控制类加载时是否 执行初始化操作,也就是静态代码块是否被执行。如下图代码:
 

class ClassA{
    public static int a=10;
    static{
        System.out.println("ClassA.static{}");
    }
}
public class ClassLoaderTraceTests {
    public static void main(String[] args) throws ClassNotFoundException {
        //ClassA clsA=null;//定义变量的形式是不会加载ClassA的
//        int a=ClassA.a;//隐式加载(ClassA这个类会被读到内存,并且执行静态代码块)
//        System.out.println(a);
//        ClassLoader.getSystemClassLoader()
//               //显式加载,此时静态代码块不会执行
//              .loadClass("com.java.jvm.loader.ClassA") ;
//          Class.forName("com.java.jvm.loader.ClassA");//类会加载,静态代码块也执行
        Class.forName("com.java.jvm.loader.ClassA",
                false,//false不执行初始化动作,静态代码块不执行
                ClassLoader.getSystemClassLoader());
    }
}

运行结果如下:

也就是forName这个方法initialize这个参数默认是true的,所以默认执行静态代码块初始化。 

第三题的答案就是:当类采用隐式加载 时会执行静态代码块,当类调用Class.forName方法执行时,默认会执行静态代码块,注意是默认,一旦修改了其中的initialize参数,也不会执行静态代码块。

所以说我们在分析问题时,要考虑到是在什么条件下,有什么样的结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leon_coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值