一、概述
一个 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