• java类的初始化


    java类的加载过程主要分为三个阶段:加载-链接(验证、准备、解析)-初始化,本文重点研究初始化阶段干了什么

    1、初始化阶段干了什么
    简单说,类的初始化就是执行静态域代码,包括静态代码块、静态变量初始化、静态常量(非String、基本类型)初始化,说白了就是()V 方法,有如下代码:

    public class ClassInit {
        final static Integer a = 1;
        static {
            System.out.println("init");
        }
        public static void main(String[] args) {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    javap -v 查看字节码,字节码会存在如下方法:

      static {};
        descriptor: ()V
        flags: ACC_STATIC
        Code:
          stack=2, locals=0, args_size=0
             0: iconst_1
             1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
             4: putstatic     #3                  // Field a:Ljava/lang/Integer;
             7: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
            10: ldc           #5                  // String init
            12: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            15: return
          LineNumberTable:
            line 10: 0
            line 12: 7
            line 13: 15
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    0、1、4三行字节码对应final static Integer a = 1;,也就是说,静态代码块、静态变量初始化、静态常量(非String、基本类型)在编译时会根据顺序,从上到下放到一个方法中,而这个方法就是初始化阶段要执行的操纵。

    2、什么时候初始化
    问题的关键就在与什么时候会触发初始化操作:
    (1)首先当创建类的对象的时候肯定会会初始化,
    (2)此外就是访问某个类或者其子类的类变量、类常量(非String、基本类型)、类方法的时候,
    (3)调用Class.forName方法,参数2位true或者默认(默认就是true)
    注意:创建一个类的数组、调用A.calss()方法都不会初始化
    实例代码:

    public class ClassInit {
        final static Integer a = 1;
        static {
            System.out.println("init");
        }
        public static void main(String[] args) {
            B.f();
        }
    }
    class A{
        static {
            System.out.println("static A");
        }
        public A() {
        }
    }
    class B extends A {
        static {
            System.out.println("static B");
        }
        public B() {
            System.out.println("public B");
        }
        public static void f(){
        }
    }
    //输出:
    init				执行main方法肯定得先有对象,创建对象之前肯定会初始化,所以先打印
    static A			子类调用类方法,如果父类没有初始化,则先初始化父类
    static B			父类初始化完了,初始化自己
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3、初始化和new的关系
    如下代码:

    public class ClassInit {
        final static Integer a = 1;
        static {
            System.out.println("init");
        }
        public static void main(String[] args) {
            new B();
        }
    }
    class A{
        static {
            System.out.println("static A");
        }
        public A() {
            System.out.println("public A");
        }
    }
    class B extends A {
        static {
            System.out.println("static B");
        }
        public B() {
            System.out.println("public B");
        }
        public static void f(){
        }
    }
    //打印
    init					执行main方法肯定得先有对象,创建对象之前肯定会初始化,所以先打印
    static A				调用子类B的构造方法之前,会先调用父类的构造方法,此时如果父类没有初始化,则先初始化
    static B				父类初始化完成,在初始化自己
    public A				先初始化,后续采取执行构造方法,先执行父类构造方法
    public B				在执行子类构造方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    4、父类和子类的构造方法
    最后补充一点关于父类构造方法的调用:
    (1)调用子类的有参或者无参构造方法,如果没有显示的调用父类的某一个构造方法,都会默认先调用父类的空参构造,如果没有会报错。
    (2)父类没有空参构造,子类在调用构造方法时,必须在第一行显示的调用父类的有参构造方法。
    (3)执行顺序是先执行父类构造方法,在执行子类构造方法。

  • 相关阅读:
    【关于检查请求参数的基本有效性】
    惠普发布最新财报,对AIPC寄予厚望
    业务数据分析-Excel必须掌握的7个操作技巧(二)
    【学习笔记十九】EWM Yard Management概述及后台配置
    redo log 和 binlog 的一些总结
    三年半经验,成功拿下字节阿里网易offer
    服务器前端部署总结
    MySQL安装配置与使用教程(2023.11.13 MySQL8.0.35)
    Java 并发编程基础 --Synchronized
    以用地业务链串接为核心的自然资源业务数据治理与重构路径
  • 原文地址:https://blog.csdn.net/baidu_40120883/article/details/126563772