栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java中类不会被初始化的几种情况

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java中类不会被初始化的几种情况

大家都知道类初始化是在类的连接后执行的,类的生命周期如下图所示:

初始化是执行类构造器clinit()方法的过程。
clinit()方法是由编译器自动收集类中的所有类变量(被static修饰的变量)和静态代码块(static{}块)中的语句合并产生的。
所以验证类有没有被初始化就可以看它的静态块有没有执行。

下面的代码是打印已加载类的方法,示例中会用到,查看类是否已经被加载

public class PrintClassInfo {
    public static void printLoadedClass(String packageNameFilter)throws Exception{
        if(packageNameFilter==null){
            packageNameFilter="classinitdemo";
        }
        final String condition=packageNameFilter;
        ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
        Class loader=ClassLoader.class;
        Field classesFiled = loader.getDeclaredField("classes");
        classesFiled.setAccessible(true);
        Vector classVector = (Vector)classesFiled.get(classLoader);
        List classes=new ArrayList<>(classVector);
        classes = classes.stream().filter(clazz->clazz.getName().contains(condition)).collect(Collectors.toList());
        System.out.println("加载的类:");
        classes.forEach(clazz-> System.out.println(clazz.getName()));
    }
}

代码中引用类而不会初始化该类有以下几种情况

  1. 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。子类和父类都会被加载。
public class B {
    public static int b = 10;
    static {
        System.out.println("B初始化");
    }
}
public class A extends B{
    static {
        System.out.println("A初始化");
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println(A.b);
    }
}
输出:
B初始化
10
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B
me.ffulauh.javalang.jvm.classinitdemo.A

A, B都会被加载,只有B被初始化。

  1. 定义对象数组,不会触发该类的初始化。该类会加载
B[] bs=new B[10];
输出:
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B
  1. 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不
    会触发定义常量所在的类。也不会加载常量所在的类。
    运行期间确定值得常量除外
 public static final int NUM = new Random().randomInt();

调用上述常量就会触发类的初始化

public class Consts {
    public static final String HAN="CaptHua";
    static {
        System.out.println("Consts初始化");
    }
}
public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        System.out.println(Consts.HAN);
        printLoadedClass(null);
    }
}
输出:
CaptHua
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test

public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        System.out.println(Consts.NUM);
        printLoadedClass(null);
    }
}
输出:
Consts初始化
625281582
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.Consts
  1. 通过类名获取 Class 对象,不会触发类的初始化,会加载。
public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        System.out.println(B.class);
        printLoadedClass(null);
    }
}
输出:
class me.ffulauh.javalang.jvm.classinitdemo.B
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B
  1. 通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触
    发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。会加载类。
public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        Class.forName("me.ffulauh.javalang.jvm.classinitdemo.B",false,Thread.currentThread().getContextClassLoader());
        printLoadedClass(null);
    }
}
输出:
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B
  1. 通过 ClassLoader 默认的 loadClass 方法,也不会触发初始化动作(加载了,但是
    不初始化)。
public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
        classLoader.loadClass("me.ffulauh.javalang.jvm.classinitdemo.B");
        printLoadedClass(null);
    }
}
输出:
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/344757.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号