尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java 代码块及其执行顺序

Java 代码块及其执行顺序 代码块在 Java 中代码块是理解对象初始化过程的关键。其主要分为四类1. 静态代码块静态代码块使用static关键字定义在类加载时执行一次。public class Example { static { System.out.println(静态代码块执行); } }通常用于初始化静态变量或执行静态资源的加载。public class StaticInitialization { public static final double PI; public static String names; // 静态代码块初始化 static { PI 3.1415926; names null; } }2.实例代码块非静态代码块无static的花括号。实例代码块在每次创建对象时执行用于初始化实例变量或执行对象共有的初始化逻辑。public class Example { { System.out.println(实例代码块执行); } }3.局部代码块局部代码块定义在方法或语句中用于限制变量的作用域优化内存使用。public void method() { int x 10; { int y 20; // y 的作用域仅限于此代码块 System.out.println(x y); } // System.out.println(y); // 编译错误y 不可见 }4.同步代码块使用synchronized关键字实现线程同步确保多线程环境下代码块的原子性。public void synchronizedMethod() { synchronized(this) { System.out.println(同步代码块执行); } }本文主要探究类的成员变量初始化故只讨论静态代码块与实例代码块非静态代码块以及构造方法之间的执行顺序。代码块和构造方法的执行顺序代码块是依照什么顺序被执行的呢在程序运行时遵循这样的顺序1.类加载阶段程序运行时首次使用类时触发1.类会被判断是否被加载过。被加载过的类不会二次加载。2.加载类的字节码到内存验证、准备为静态变量分配内存并设默认值、解析。3.执行静态代码块按定义顺序执行初始化静态变量。类加载的触发条件通常包括创建类的实例如new InitializationOrderDemo()。访问类的静态成员如InitializationOrderDemo.staticVar。调用类的静态方法。通过Class.forName()反射加载类。2.对象实例化阶段当使用 new 关键字创建对象时1.为对象分配内存空间初始化实例变量为默认值。2.执行实例代码块和实例成员按定义顺序执行进一步初始化实例变量。3.调用构造方法完成对象的最终初始化。总结一下类加载 → 静态代码块 → 实例代码块/实例成员变量 → 构造方法接下来通过几个代码示例方便大家理解。code1:class InitializationOrderDemo { // 静态成员变量 public static int staticVar; // 实例成员变量 public int instanceVar; // 静态代码块 static { staticVar 100; System.out.println(1. 静态代码块执行初始化静态变量 staticVar staticVar); } // 实例代码块 { instanceVar 200; System.out.println(2. 实例代码块执行初始化实例变量 instanceVar instanceVar); } // 无参构造函数 public InitializationOrderDemo() { System.out.println(3. 无参构造函数执行); } // 有参构造函数 public InitializationOrderDemo(String msg) { System.out.println(3. 有参构造函数执行); } } public class ClassObject { public static void main(String[] args) { System.out.println( InitializationOrderDemo.staticVar); } }执行结果1. 静态代码块执行初始化静态变量 staticVar 100100通过访问类的静态成员触发类加载执行静态代码块。由于没有对象实例化故不会执行代码实例块和构造函数。注意类加载并非就是编译。类的加载的触发需要创建类的实例如new InitializationOrderDemo()。访问类的静态成员如InitializationOrderDemo.staticVar。调用类的静态方法。通过Class.forName()反射加载类。如果此main方法中什么也不写那么也不会执行静态代码块。code2class InitializationOrderDemo { // 静态成员变量 public static int staticVar; // 实例成员变量 public int instanceVar; // 静态代码块 static { staticVar 100; System.out.println(1. 静态代码块执行初始化静态变量 staticVar staticVar); } // 实例代码块 { instanceVar 200; System.out.println(2. 实例代码块执行初始化实例变量 instanceVar instanceVar); } // 无参构造函数 public InitializationOrderDemo() { System.out.println(3. 无参构造函数执行); } // 有参构造函数 public InitializationOrderDemo(String msg) { System.out.println(3. 有参构造函数执行); } } public class ClassObject { public static void main(String[] args) { InitializationOrderDemo example new InitializationOrderDemo(); } }执行结果1. 静态代码块执行初始化静态变量 staticVar 1002. 实例代码块执行初始化实例变量 instanceVar 2003. 无参构造函数执行创建类的实例触发类的加载阶段然后对象实例化阶段。类加载 → 静态代码块 → 实例代码块/实例成员变量 → 构造方法code3:class InitializationOrderDemo { // 静态成员变量 public static int staticVar; // 实例成员变量 public int instanceVar; // 静态代码块 static { staticVar 100; System.out.println(1. 静态代码块执行初始化静态变量 staticVar staticVar); } // 实例代码块 { instanceVar 200; System.out.println(2. 实例代码块执行初始化实例变量 instanceVar instanceVar); } // 无参构造函数 public InitializationOrderDemo() { System.out.println(3. 无参构造函数执行); } // 有参构造函数 public InitializationOrderDemo(String msg) { System.out.println(3. 有参构造函数执行); } } public class ClassObject { public static void main(String[] args) { System.out.println( 第一次创建对象 ); InitializationOrderDemo example1 new InitializationOrderDemo(); System.out.println(\n 第二次创建对象 ); InitializationOrderDemo example2 new InitializationOrderDemo(带参数的构造函数); } }执行结果 第一次创建对象 1. 静态代码块执行初始化静态变量 staticVar 1002. 实例代码块执行初始化实例变量 instanceVar 2003. 无参构造函数执行 第二次创建对象 2. 实例代码块执行初始化实例变量 instanceVar 2003. 有参构造函数执行由此可见类的加载只会被执行一次。以上我们可以得到优先级为静态代码块实例代码块 构造方法。这是不同级的顺序那么如果同为静态代码块或实例代码块其执行顺序是怎样的对于构造方法取决于调用了谁。对于静态代码块、实例代码块取决于其定义顺序。例如class Example { static { staticVar 10; System.out.println(静态代码块1); } static { staticVar 11; System.out.println(静态代码块2); } public static int staticVar 21; } public class ClassObject { public static void main(String[] args) { System.out.println(Example.staticVar); } }执行结果静态代码块1静态代码块221按照定义顺序先执行前面的static再执行后面的static最后执行public static int staticVar 21;注static { staticVar 10; System.out.println(静态代码块1); } static { staticVar 11; System.out.println(静态代码块2); } public static int staticVar 21;等价于public static int staticVar; static { staticVar 10; System.out.println(静态代码块1); } static { staticVar 11; System.out.println(静态代码块2); } static { staticVar 21; }最终值为 21因为静态变量赋值staticVar 21按定义顺序在最后执行。在类的继承中执行顺序class Animal { static { System.out.println(static :: Animal{ }); } { System.out.println(实例代码块 Animal{ }); } public Animal() { System.out.println(Animal(.....)); } } class Cat extends Animal { static { System.out.println(static :: Cat{ }); } { System.out.println(实例代码块 Cat{ }); } public Cat() { System.out.println(Cat(...)); } } public class Test2 { public static void main(String[] args) { Cat cat1 new Cat(); System.out.println(); Cat cat2 new Cat(); } }执行结果static :: Animal{ }static :: Cat{ }实例代码块 Animal{ }Animal(.....)实例代码块 Cat{ }Cat(...)实例代码块 Animal{ }Animal(.....)实例代码块 Cat{ }Cat(...)总结1.类加载阶段先父类再子类。并且只加载一次。2.对象实例化阶段先父类再子类。对象初始化阶段包括实例代码块和构造函数的执行。所以顺序是父类静态代码块 → 子类静态代码块 → 父类实例代码块 → 父类构造方法 → 子类实例代码块 → 子类构造方法
返回列表