首页 > 编程语言 >Java-Day-35( 类加载 + 细化解释各阶段 )

Java-Day-35( 类加载 + 细化解释各阶段 )

时间:2023-07-24 21:56:26浏览次数:38  
标签:初始化 Java 静态 35 public static 阶段 Day 加载

Java-Day-35

类加载

基本说明

反射机制是 java 实现动态语言的关键,也就是通过反射实现类动态加载

  • 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强

    • 在非具备 idea 辅助型的工具里编写代码时
    import java.util.Scanner;
    public class test {
        public static void main(String[] args) throws ClassNotFoundException {
            Scanner scanner = new Scanner(System.in);
            String key = scanner.next();
            switch (key) {
                case "1":
                    Dog dog = new Dog(); // 静态加载类
                    dog.hello();
                    break;
                case "2":
                    System.out.println("输入的是2");
                    break;
                default:
                    System.out.println("啥也不是");
            }
        }
    }
    
    • 上述代码中,于代码文件 ( ClassLoad_zyz.java ) 所在目录 cmd 命令行中输入 javac ClassLoad_zyz.java 进行编译的话会报错
    • 因为:虽然不输入 "1" 的话是不会需要 Dog 类的使用创建的,但是由于是静态加载类,所以不导包的话,就算不需要也会在编译时的代码检查时报错
  • 动态加载:运行时加载需要的类,如果运行时不用该类,即使该类不存在也不会报错,降低了依赖性

    • 将上述代码的 case 2 进行修改
    case "2":
    	System.out.println("输入的是2");
    	Class cls = Class.forName("Person"); // 加载Person类,
    //                 但是在编译时不会加载,只有在代码执行、运行到这里的时候才会加载
    	Object o = cls.newInstance();
        Method m = cls.getMethod("hi"); // import java.lang.reflect.*;
    	m.invoke(o);
    	break;
    
    • 只导入 Dog 的包,没导入 Person 类的包的话,javac 编译是不会报错的,会在此目录生成 .class 文件,只有在 java ClassLoad_zyz 后输入 "2" 时,动态加载 Person 类的时候才会报错
    • 原因:此处是反射的方式,反射是动态加载,不执行到 forName() 就不会报错

类加载时机

  • 当创建对象时 ( new ) —— 静态加载
  • 当子类被加载时,父类也加载 —— 静态加载
  • 调用类中的静态成员时 —— 静态加载
  • 通过反射 —— 动态加载

过程图

image-20230718113404946

类加载三大阶段

  • 加载、连接、初始化

image-20230718150800992

  • 验证 —— 文件安全进行校验

  • 准备 —— 对静态变量进行默认的初始化并分配空间

  • 解析阶段 —— 符号引用转为字节引用

    • 连接完成后 —— 合并到 JRE 运行环境中,此时就是一种可运行的状态了
  • 前两个阶段 ( 加载和连接 ) 是 JVM 来控制的,只有初始化阶段才是认为可以指定的,如静态代码块、静态变量初始化等是程序员自己可以控制的代码了

    • 注意,是加载阶段的初始化,不是 new,此处主要针对静态资源 static

细化解释各阶段

加载阶段

  • JVM 在该阶段的主要目的是将字节码从不同的数据源 ( 可能是 class 文件、也可能是 jar 包,甚至网络 ) 转化为二进制字节流加载到内存中,并生成一个代表该类的 java.lang.Class 对象
    • 就是在先前讲过的 Class 类阶段的 —— 在方法区内加载二进制数据与堆内生成 Class 类对象

连接阶段 - 验证

  • 目的是为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全

  • 包括:文件格式验证 ( 是否以魔数 oxcafebabe 开头 )、元数据验证、字节码验证和符号引用验证

    • javac 编译后的 .class 文件内容开头八位数就是 cafe babe
    • 追加载类源码:
    loadClass(String name) ——> loadClass(String var1, boolean var2) 内含SecurityManager就是验证
    
  • 可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间

连接阶段 - 准备

  • JVM 会在该阶段对静态变量分配内存并默认初始化 ( 对应数据类型的默认初始值,如:0、0L、null、false 等 )。这些变量所使用的内存都将在方法区中进行分配
//        属性 — 成员变量 - 字段
public int n1 = 10; // 实例属性,不是静态变量,因此准备阶段不会分配内存
public static int n2 = 20; // 静态变量,分配内存,默认初始化为0 (加载的初始化阶段才会真正执行此代码赋为20)
public static final int n3 = 30; // 是 static final 是常量,和静态变量不同,因为一旦赋值就不会再变了,所以此时就直接为30了

连接阶段 - 解析

  • 虚拟机将常量池内的符号引用替换为直接引用的过程
  • 到此步类都还没真正分配空间到内存中,所以类之间若有关系也只能是符号引用,记住了表面的相应的关系,只有真正用到加载完成类的时候才会由虚转实

初始化阶段

  • 到初始化阶段才真正开始执行类中定义的 Java 程序代码 —— 程序员可以控制了,此阶段是执行 < clinit >() 方法的过程
  • < clinit >() 方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并
    • 注意:还是静态部分的
  • 虚拟机会保证一个类的 < clinit >() 方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的 < clinit >() 方法,其他线程都需要阻塞等待,直到活动线程执行 < clinit >() 方法完毕
    • 类加载源码:synchronized (getClassLoadingLock(name)) { } 此机制的保证,使得某个类在内存中只有一份 Class 对象
public class test {
    public static void main(String[] args) {
//        1. 加载B类,生成B的class对象
//        2. 连接 num=0
//        3. 初始化阶段
//              自动先后顺序地收集(clinit方法)
        /*
            clinit(){
                System.out.println("静态代码块");
                // num = 300; 合并时此句就没有意义了
                num = 100;
            }
            最后合并后 num 为 100
         */
        
//        4. 如果 new 了的话,就比正常步骤多一步构造器的执行,输出时会在中间加一句:B()构造器
//        new B(); // 不加这一句的话就是只输出:静态代码块 100
        
        System.out.println(B.num); // 直接使用类的静态属性,也会导致类的加载 1.2.3.
//        静态代码块
//        100
    }
}

class B {
    static {
        System.out.println("静态代码块");
        num = 300;
    }
    static int num = 100;
    public B() {
        System.out.println("B()构造器");
    }
}

标签:初始化,Java,静态,35,public,static,阶段,Day,加载
From: https://www.cnblogs.com/zhu-ya-zhu/p/17578448.html

相关文章

  • Java-Day-36( 通过反射获取类的结构信息 + 通过反射访问类中的成员 + 章节练习 )
    Java-Day-36通过反射获取类的结构信息第一组:java.lang.Class类以下说的包含本类和父类——也包括超类等方法属性之类的若是输出时不加.getName,则都是输出:com.zyz.Zyz()publicclasstest{publicstaticvoidmain(String[]args){}@Testpubl......
  • 老杜 JavaWeb 讲解(十四) ——JSP+Servlet改造oa项目
    (十四)JSP改造oa项目相关视频:38-Servlet和JSP改造oa项目使用Servlet+JSP完成oa项目的改造使用Servlet处理业务,收集数据。使用JSP展示数据。将之前原型中的html文件,全部修改为jsp,然后在jsp文件头部添加page指令(指定contentType防止中文乱码),将所有的JSP直接拷贝到web......
  • 价值年薪70W的JAVA进阶学习路线!终于让我从阿里P8手里抠出来了
    作为一个男人我感觉必须得做点什么来证明一下自己,现在我又回来了,准备把自己的节操准备补一下。另外给各位未来的Java程序员说一句,别的我不清楚,学习编程请从一而终咱们学习编程就挺难的,有这些先驱者来带领咱们学习,咱们应该感激,而且最重要的事跟着你选定的一家一直学下去因为每家学校......
  • 算法练习-day28
    贪心算法860.柠檬水找零题意:在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单bills支付的顺序)一次购买一杯。每位顾客只买一杯柠檬水,然后向你付5美元、10美元或20美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付5美元。注意,一开......
  • 用Java集合中的Collections.sort方法对list排序的两种方法
    用Collections.sort方法对list排序有两种方法第一种是list中的对象实现Comparable接口,如下:   <strong>/**02 *根据order对User排序03 */04 publicclassUserimplementsComparable{05 privateStringname;06 privateIntegerorder;07 publicStringgetN......
  • tokyotyrant-java客户端
    目录:概述演示[一]、概述java实现了对ttserver服务端的连接和访问。相关的源代码和jar包可以到其官网下载。官网地址:http://code.google.com/p/tokyotyrant-java/如果是maven构建项目的,在pom.xml的<dependencies>节点中增加如下依赖配置即可:1 <dependency>2<groupId>......
  • [Leetcode Weekly Contest]355
    链接:LeetCode[Leetcode]6921.按分隔符拆分字符串给你一个字符串数组words和一个字符separator,请你按separator拆分words中的每个字符串。返回一个由拆分后的新字符串组成的字符串数组,不包括空字符串。注意separator用于决定拆分发生的位置,但它不包含在结果字符串......
  • Day08_for循环+print补充用法
    1.for循环和while循环取值: 2.for循环字典: 3.for循环字符串: 4.总结for循环和while循环的异同: 5.for循环控制循环次数:range() 6.for+break和for+else: 7.range(): 8.for+continue: 9.for循环嵌套: 10.print补充用法: ......
  • day12
    一、miao~1.得到的jpg,010打开在末尾发现wav文件2.foremost分离,Audacity打开查看频谱图,发现了CatCTF3.猜测是音频的解密密码,但是使用silenteye和steghide均无用,需使用deepsound进行解密,输入密码后得到flag.txt4.得到txt中的内容很像兽音,在线解密,得到flagCatCTF{d0_y0u_Ha......
  • 为什么有一些什么方法都没有的接口会存在?比如java.lang.Cloneable
    /***Aclassimplementsthe<code>Cloneable</code>interfaceto*indicatetothe{@linkjava.lang.Object#clone()}methodthatit*islegalforthatmethodtomakea*field-for-fieldcopyofinstancesofthatclass.*<p>*Invo......