IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java中类不会被初始化的几种情况 -> 正文阅读

[Java知识库]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<Class> classVector = (Vector<Class>)classesFiled.get(classLoader);
        List<Class> 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
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 14:48:21  更:2021-10-24 14:50:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:23:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码