Java 初始化块详解

简介: Java 初始化块详解

代码案例摘自:https://blog.csdn.net/a647777/article/details/108789049


概念摘自百度百科


初始化块概念


初始化块用于初始化类的对象。分为实例初始化块和静态初始化块。其中在一个对象编译的过程中,静态初始化块只在类加载的时候被初始化一次,并且是初始化内容存在堆的方法区(元空间)中,而实例化代码块,则是在对象被实例化的时候调用。


初始化块是类的第4种成员(成员变量、方法、构造器),与构造器作用有些类似,用于对JAVA对象进行初始化操作。


初始化块定义


实例化代码块:


{
  Java语句;
}


使用static关键字来定义“静态代码块”


static{
  Java语句;
}


初始化块举例


例如:


public class Animal {
  //定义初始化块
  {
    int a = 6;
    if(a>4) {
      System.out.println("Animal初始化块,局部变量a的值大于4");
    }
    System.out.println("Animla的初始化块");
  }
  //再定义一个初始化块
  {
    System.out.println("Animal的第二个初始化块");
  }
  //定义构造器
  public Animal() {
    System.out.println("Animal的无参构造器");
  }
}
public class Demo01 { 
  public static void main(String[] args) {
    Animal a = new Animal();
  }
}


运行结果如下:



可见,JAVA创建对象时,首先执行初始化块。


如果一个类中定义了多个初始化块,则按照顺序执行(这其实没有什么意义,因为初始化块都可以合并为一个)。并且,初始化块在构造器(构造函数)之前执行。


初始化块与构造器区别


二者的区别是:


  • 初始化块是一段固定的代码,它无法接受任何参数,对一个类的所有对象进行的初始化处理完全相同;


  • 而构造器则是可以带参数的,对不同的对象,参数不同,可以进行不同的初始化处理。


静态初始化块


与静态方法、静态成员变量类似,在初始化块之前加上static就变成了静态初始化块。


普通初始化块是对象的,负责初始化具体对象;


静态初始化块是类的,负责初始化类。


与静态方法相同,静态初始化块不能访问非静态方法,非静态成员变量(因为静态初始化块是在类加载的时候就执行了的,这个时候可能还没有类的对象,就没办法执行非静态方法、非静态成员变量)


初始化块执行顺序


JAVA中,创建一个对象时,若是第一次创建该类的对象,则会首先加载并初始化该类,因此会首先执行其所有父类的静态初始化块(按照顺序执行,首先是最顶层父类,然后是下一层,层层向下执行),最后是其本身的静态初始化块。


再依次执行所有父类的初始化块、构造器,最后是自己类的初始化块、构造器。


一旦该对象创建成功,该类在虚拟机中将一直存在,第二次创建该类的对象时,就无需加载与初始化类。


其中,类的静态初始化块、静态成员变量的声明都可以看作是类的初始化代码,执行顺序依代码顺序而定。


代码举例如下:


class Person {
  static {
    System.out.println("我是Person类的静态初始化块");
  }
   {
    System.out.println("我是Person类的普通初始化块");
  }
   public Person() {
     System.out.println("我是Person类的无参构造器");
   }
}
class Police extends Person{
  static {
    System.out.println("我是Police类的静态初始化块");
  }
  {
    System.out.println("我是Police类的普通初始化块");
  }
   public Police() {
     System.out.println("我是Police类的无参构造器");
   }
   public Police(int a) {
     //调用自己的无参构造器
     this();
     System.out.println("我是Police类的有参构造器,参数为:"+a);
   }
}
class SWAT extends Police{
  static {
    System.out.println("我是SWAT的静态初始化块");
  }
  {
    System.out.println("我是SWAT的普通初始化块");
  }
  public SWAT() {
    //调用直接父类的有参构造器
    super(10);
    System.out.println("我是SWAT的无参构造器");
  }
}
public class Demo01 { 
  public static void main(String[] args) {
    new SWAT();
  }
}


上述代码创建了三个类,Person,Police,SWAT。其中,Person是Police的直接父类,Police是SWAT的直接父类。


输出结果为:


我是Person类的静态初始化块
我是Police类的静态初始化块
我是SWAT的静态初始化块
我是Person类的普通初始化块
我是Person类的无参构造器
我是Police类的普通初始化块
我是Police类的无参构造器
我是Police类的有参构造器,参数为:10
我是SWAT的普通初始化块
我是SWAT的无参构造器


因为这是第一次使用SWAT这个类,因此需要初始化类,因此会首先依次执行Person类的静态初始化块、Police类的静态初始化块和SWAT类的静态初始化块。


随后,创建对象时,则会依次执行各个父类的初始化块,构造器。首先是Person类的普通初始化块、无参构造器,然后是Police类的普通初始化块、无参构造器、有参构造器(因为SWAT的无参构造器中调用了Police的有参构造器(super(10)),而Police的有参构造器中调用了Police的无参构造器(this())),最后是SWAT自己的普通初始化块、无参构造器。


修改一下代码


public class Demo01 { 
  public static void main(String[] args) {
    new SWAT();
    new SWAT();
  }
}


输出将增加:


我是Person类的普通初始化块
我是Person类的无参构造器
我是Police类的普通初始化块
我是Police类的无参构造器
我是Police类的有参构造器,参数为:10
我是SWAT的普通初始化块
我是SWAT的无参构造器


因为该类已经被加载过了,因此,各个类的静态初始化块均不会被重新运行。

相关文章
|
5月前
|
Java 编译器 Go
25、Java 初始化块和静态初始化块详解,超详细(案例多、官方教程)
25、Java 初始化块和静态初始化块详解,超详细(案例多、官方教程)
211 1
Java的初始化块
初始化块是一种初始化数据域的方法。
|
Java 编译器 Go
第25篇:Java 初始化块和静态初始化块详解,超详细(案例多、官方教程)
📜 私有静态方法初始化类变量的好处是:如果你需要重新为类变量进行初始化的时候,私有静态方法可以被重复使用
173 0
第25篇:Java 初始化块和静态初始化块详解,超详细(案例多、官方教程)
|
存储 设计模式 Java
第18篇:Java的类变量、类方法;static 关键字;静态导入;初始化块;静态初始化块;单例模式
☘️ 被static修饰的成员变量可叫做:类变量、静态变量、静态字段 ☘️ 类变量在程序运行过程中只占用一份固定的内存(存储在方法区) ☘️ 可通过类名访问 ☘️ 可通过引用变量名访问(不推荐)
103 0
第18篇:Java的类变量、类方法;static 关键字;静态导入;初始化块;静态初始化块;单例模式
|
Java 程序员
教妹学Java(三十四):代码初始化块
教妹学Java(三十四):代码初始化块
117 0
Java 中的 static 使用之静态变量·静态方法·静态初始化块
Java 中的 static 使用之静态变量 大家都知道,我们可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立。然而在某些时候,我们更希望该类所有的对象共享同一个成员。
|
Java
java中的初始化块
public class Person {   int a=6;//声明实例变量制定默认值,也可以认为是对象的初始化代码,执行顺序与源代码中的排列顺序相同 {   System.
671 0
|
4天前
|
安全 Java UED
Java中的多线程编程:从基础到实践
本文深入探讨了Java中的多线程编程,包括线程的创建、生命周期管理以及同步机制。通过实例展示了如何使用Thread类和Runnable接口来创建线程,讨论了线程安全问题及解决策略,如使用synchronized关键字和ReentrantLock类。文章还涵盖了线程间通信的方式,包括wait()、notify()和notifyAll()方法,以及如何避免死锁。此外,还介绍了高级并发工具如CountDownLatch和CyclicBarrier的使用方法。通过综合运用这些技术,可以有效提高多线程程序的性能和可靠性。
|
4天前
|
缓存 Java UED
Java中的多线程编程:从基础到实践
【10月更文挑战第13天】 Java作为一门跨平台的编程语言,其强大的多线程能力一直是其核心优势之一。本文将从最基础的概念讲起,逐步深入探讨Java多线程的实现方式及其应用场景,通过实例讲解帮助读者更好地理解和应用这一技术。
19 3