目录
1)通过类型定义变量,类会被加载吗? 2)类加载时一定会执行静态代码块吗? 3)类加载时什么时候会执行静态代码块呢?
第二题的答案也显而易见:不是所有的类加载时都会执行静态代码块, 要分情况而论。
第三题的答案就是:当类采用隐式加载 时会执行静态代码块,当类调用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参数,也不会执行静态代码块。
所以说我们在分析问题时,要考虑到是在什么条件下,有什么样的结果