首页 > 编程语言 >Java 类的加载顺序

Java 类的加载顺序

时间:2022-09-01 22:46:14浏览次数:48  
标签:顺序 Java 静态 代码 static new Message 加载

一、概述

一个 Java 类在编译器中是如何加载的,它的各个成员的加载顺序又是什么?

这些成员涉及到 静态成员变量、静态代码块、构造代码块、构造方法、成员变量、成员方法

下面我们就来探究一下这些成员之间的加载顺序

1、静态代码块:

加载时机: 静态代码块随着类的加载而加载,并且只加载一次,它的优先级与静态成员变量一致,谁先声明谁就先执行

作用: 有些业务逻辑需要在类启动的时候就加载,例如将枚举类的值放入内存中,加载配置文件等

2、静态成员变量

加载时机: 静态成员变量随着类的加载而加载,它的优先级与静态代码块一致,谁先声明谁就先执行

3、构造代码块 / 构造函数

执行时机: 构造代码块在创建对象时被调用,每次创建对象都会调用一次,但是优先于构造函数执行.需要注意的是,构造代码块不是优先于构造函数执行,而是依托于构造函数,也就是说,如果你不实例化对象,构造代码块是不会执行的

作用: 和构造函数的作用类似,都能对对象进行初始化,并且只要每创建一个对象,构造代码块都会执行一次.但是反过来,构造函数则不一定每个对象建立时都执行(多个构造函数情况下,建立对象时传入的参数不同则初始化使用对应的构造函数).
利用每次创建对象的时候都会提前调用一次构造代码块特性,我们可以做诸如统计创建对象的次数等功能

4、非静态成员变量 / 静态方法 / 非静态方法

非静态成员变量优先级和构造代码块相同,谁先声明谁就先执行

静态方法和普通方法无任何区别,谁先被调用谁就先执行

二、单个类

public class MerberSequence {
    private static Message messageA = new Message("静态成员变量 A");
    private static Integer count = 0;

    static {
        new Message("静态代码块");
    }

    private static Message messageB = new Message("静态成员变量 B");
    private Message messageC = new Message("成员变量 C");

    public MerberSequence(){
        new Message("构造方法");
    }

    {
        count++;
        new Message("构造代码块");
    }

    public static void staticMethod(){
        new Message("静态方法");
    }

    public void normalMethod(){
        new Message("普通方法");
    }

    public static void main(String[] args) {
        System.out.println("main 方法执行");
        MerberSequence merberSequence = new MerberSequence();
        merberSequence.normalMethod();
        MerberSequence.staticMethod();
        System.out.println("---------------------------");
        MerberSequence merberSequence2 = new MerberSequence();
        MerberSequence.staticMethod();
        merberSequence.normalMethod();
        System.out.println(merberSequence.count);
    }
}

优先级 1、静态成员变量 / 静态代码块: 他们的优先级相同,谁先声明谁先执行
优先级 2、普通成员变量 / 构造代码块: 他们的优先级相同,谁先声明谁先执行
优先级 3、构造代码块优先于构造方法执行,每创建一个对象就调用一次构造代码块和构造方法
优先级 4、普通方法和静态方法没有任何区别,谁先调用就谁先执行

三、具有继承关系的父子类

// 父类
class Father {
    private static Message messageA = new Message("父类的静态属性 A");

    static {
        new Message("父类的静态代码块");
    }

    private static Message messageB = new Message("父类的静态属性 B");

    {
        new Message("父类的构造代码块");
    }

    private Message messageC = new Message("父类的非静态属性 C");

    public Father() {
        new Message("父类的构造方法");
    }
}

// 子类
class Child extends Father {
    private static Message messageA = new Message("子类的静态属性 A");
    private static Message messageB = new Message("子类的静态属性 B");

    static {
        new Message("子类的静态代码块");
    }

    private Message messageC = new Message("子类的非静态属性 C");

    {
        new Message("子类的构造代码块");
    }

    public Child() {
        new Message("子类的构造方法");
    }

    // 测试方法
    public static void main(String[] args) {
        Child child = new Child();
        System.out.println(child);
    }
}

// 打印信息的类
class Message {
    public Message(String message) {
        System.out.println(message);
    }
}

优先级 1、父类静态成员变量 / 静态代码块

优先级 2、子类静态成员变量 / 静态代码块

优先级 3、父类非静态成员变量 / 父类构造代码块 (创建子类对象必须先调用父类的构造方法,完成父类属性的初始化)

优先级 4、父类构造方法

优先级 5、子类非静态成员变量 / 父类构造代码块

优先级 6、子类构造方法

四、内部类

内部类:内部类是延时加载的,也就是说只会在第一次使用时加载.不使用就不加载.由此,可以很好的用于单例模式(不使用不加载:避免了饿汉式的内存浪费;可巧妙避免线程安全问题)

public class Singleton {
    // 加载顺序 静态成员变量 = 静态代码块 > 静态方法 > 构造方法
    private static Singleton instance = null;

    // 构造方法私有化,防止外界创建对象
    private Singleton() {
        // 如果是单例,那么构造方法只会被创建一次,否则就会调用超过一次
        System.out.println("调用了构造方法创建对象");
    }

    public static Singleton getInstance() {
        // 内部类是延时加载的,也就是说只有在使用的时候才会去加载内部类,避免了内存的浪费、线程安全等问题
        Singleton instance = InnerClass.instance;
        return instance;
    }

    static class InnerClass{
        private static Singleton instance = new Singleton();
    }
}

  

 

标签:顺序,Java,静态,代码,static,new,Message,加载
From: https://www.cnblogs.com/xiaomaomao/p/16648099.html

相关文章

  • Jenkins使用Maven构建Java项目
    Jenkins使用Maven构建Java项目什么是MavenMaven是一个项目管理和综合工具。Maven提供给开发人员构建一个完整的生命周期框架。开发团队可以自动完成该项目的基础设施建......
  • # JavaScript 函数
    目录JavaScript函数函数概念函数的使用函数的使用函数的封装函数的参数形参和实参形参和实参个数不匹配问题return终止函数return只能返回一个值JavaScript函数函数概......
  • 【Java基础】方法的重载、可变形参
    1.方法重载同一个类中,方法名相同,参数个数或参数类型不同。根据方法的参数列表的不同来区分。publicintadd(intx,inty){returnx+y;}pu......
  • Java常用类之日期操作类
    日期操作类在Java中对日期的操作类常用的有以下4种:Date类Calendar类DateFormat类SimpleDateFormat类一起来了解一下各个类如何使用的吧!!! 一、Date类1、......
  • 异常java.sql.SQLException: Before start of result set
    使用rs.getString();前一定要加上rs.next();原因:ResultSet对象代表SQL语句执行的结果集,维护指向其当前数据行的光标。每调用一次next()方法,光标向下移动一行。最初它位于......
  • 【Java基础】类的成员之二:方法(函数)
    1.方法表示类或对象具有的功能,也称为函数,定义在类中2.方法的执行过程方法被调用一次就会执行一次,方法中只能调用方法或属性,不能在方法内部定义方法。3.return关键字......
  • java中的语法糖
    Java语法糖语法糖(SyntacticSugar),也称糖衣语法,是由英国计算机学家Peter.J.Landin(彼得·兰丁)发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有......
  • 正则表达式在Java中的使用
    正则表达式在Java中的使用不仅限于String类中的match()方法!!!正则中的^与$首先我们来了解这两个符号在正则表达式中的作用:^符号放在表达式头部表示开始匹配$符号放......
  • 【学习底层原理系列】Java底层-synchronized锁-3轻量级锁篇
     一.上一篇回顾1.偏向锁中的批量撤销和批量重偏向2.偏向锁发生了竞争,锁就要升级二.轻量级锁拆解1.加锁流程构建LockRecord,将LockRecord的obj指向当前锁对象,然后将无......
  • 【Java基础】类的结构之一:属性(变量)
    1.成员变量与局部变量二者的区别成员变量局部变量声明的位置直接声明在类中方法形参或内部、代码块内、构造器内等修饰符private、public、static、fin......