Java——静态字段和实例字段的初始化说明(概念理解+应用举例)

简介: Java——静态字段和实例字段的初始化说明(概念理解+应用举例)

我们都知道,在Java语言中,有静态字段和实例字段,但是,它们两者之间的初始化是有区别的。


其中,需要说明的一点就是:静态字段由类调用,实例字段由对象调用!!!


1. 静态字段


static 静态字段 / 静态变量 的初始化过程,由Java虚拟机JVM加载类后,自动进行静态字段初始化。


①静态字段的默认初始化:静态字段设置为其类型的默认值。


②静态字段的声明初始化:静态字段设置为声明时的初始化值。


③静态字段的静态块初始化:依次调用静态块进行初始化。


从源程序的角度看,静态字段以上三种初始化的顺序:


①首先进行默认初始化。


②然后根据声明初始化、静态块初始化这两者在程序中的顺序来依次进行!!!(两者谁先谁后是不一定的)


2. 实例字段


实例字段 / 实例变量 的初始化过程,由new进行实例初始化。


①实例字段的默认初始化:实例字段设置为其类型的默认值。


②实例字段的声明初始化:实例字段设置为声明时的初始化值。


③实例字段的实例构造方法初始化:根据实例构造方法签名,调用实例构造方法进行初始化。


从源程序的角度看,实例字段以上三种初始化的顺序:


①首先必须进行默认初始化。


②然后进行声明初始化。


③最后进行实例构造方法的初始化。


因为实例字段相对来说,比较好理解,所以我们在这里重点对静态字段的初始化进行讲解!!!


我们依次来看下面的五个程序!!!👇👇👇


Program Ⅰ: (没有静态块,静态变量的声明初始化的顺序不同)


class Test1 {
  public Test1() {
    System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b);
    Test.a++;
    Test.b++;
    System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b);
  }
}
public class Test {
  public static Test1 t=new Test1();
  public static int a;
  public static int b=10;
  public static void main(String[] args) {
    System.out.println("最后的结果:a="+Test.a+",b="+Test.b);
  }
}


Program Output Ⅰ:

Program Analysis Ⅰ:


按此顺序初始化静态变量:默认初始化→声明初始化


默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。


声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。


静态字段初始化流程如下:


1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。结果:t=null,a=0,b=0


2. 声明初始化:①首先进行静态字段t的声明初始化,创建Test1的实例,调用实例构造方法,执行之后的结果:a=1,b=1


                         ②然后进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,并执行Test.a++,                     此时a=1;但是静态字段b由声明初始化,结果b=10。(大家对照这个流程,看一下上面的代码和运行结果)



Program Ⅱ:(没有静态块,静态变量的声明初始化的顺序不同)


class Test1 {
  public Test1() {
    System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b);
    Test.a++;
    Test.b++;
    System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b);
  }
}
public class Test {
  public static int a;
  public static int b=10;
        public static Test1 t=new Test1();
  public static void main(String[] args) {
    System.out.println("最后的结果:a="+Test.a+",b="+Test.b);
  }
}


Program Output Ⅱ:


Program Analysis Ⅱ:


按此顺序初始化静态变量:默认初始化→声明初始化


默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。


声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。


静态字段初始化流程如下:


1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。结果:t=null,a=0,b=0。


2. 声明初始化:①首先进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,结果还是a=0;但                     静态字段b有声明初始化,所以结果是b=10。


                        ②然后再进行静态字段t的声明初始化,创建Test1的实例,调用实例构造方法,Test.a++,Test.b++,执行                     之后的结果是a=1,b=11。(大家对照这个流程,看一下上面的代码和运行结果)


Program Ⅲ:(有静态块,静态块定义在声明初始化语句之后)

class Test1 {
  public Test1() {
    System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b);
    Test.a++;
    Test.b++;
    System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b);
  }
}
public class Test {
  public static Test1 t=new Test1();
  public static int a;
  public static int b=10;
  static {
    a=20;
    System.out.println("static静态代码块1之后 a="+Test.a+",b="+Test.b);
  }
  static {
    b=30;
    System.out.println("static静态代码块2之后 a="+Test.a+",b="+Test.b);
  }
  public static void main(String[] args) {
    System.out.println("最后的结果:a="+Test.a+",b="+Test.b);
  }
}


Program Output Ⅲ:



Program Analysis Ⅲ:

按此顺序初始化静态变量:默认初始化→声明初始化→静态代码块初始化


默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。


声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。


静态代码块初始化:按照静态代码块的顺序依次设置静态字段的值。


静态字段初始化流程如下:


1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。 结果:t=null,a=0,b=0。


2. 声明初始化:①首先进行静态字段t的声明初始化,创建Test1的实例,调用实力构造方法,执行之后的结果是a=1,b=1


                         ②进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,结果还是a=1;但是静                    态字段b有声明初始化,所以结果是b=10。


3. 静态代码块初始化:①首先执行静态代码块1,对静态字段a进行静态块初始化,结果是a=20,b=10。


                                    ②然后执行静态代码块2,对静态字段b进行静态块初始化,结果是a=20,b=30。(大家对照这个流程,看一下上面的代码和运行结果)



Program Ⅳ:(有静态块,静态块定义在声明初始化语句之前)


class Test1 {
  public Test1() {
    System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b);
    Test.a++;
    Test.b++;
    System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b);
  }
}
public class Test {
  static {
    a=20;
    System.out.println("static静态代码块1之后 a="+Test.a+",b="+Test.b);
  }
  static {
    b=30;
    System.out.println("static静态代码块2之后 a="+Test.a+",b="+Test.b);
  }
  public static Test1 t=new Test1();
  public static int a;
  public static int b=10;
  public static void main(String[] args) {
    System.out.println("最后的结果:a="+Test.a+",b="+Test.b);
  }
}


Program Output Ⅳ:



Program Analysis Ⅳ:


按此顺序初始化静态变量:默认初始化→静态代码块初始化→声明初始化


默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。


静态代码块初始化:按静态块的顺序依次设置静态字段的值。


声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。


静态字段初始化流程如下:


1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。 结果:t=null,a=0,b=0。


2. 静态代码块初始化:①首先执行静态代码块1,对静态字段a进行静态块初始化,结果是a=20,b=0。


                                    ②然后执行静态代码块2,对静态字段b进行静态块初始化,结果是a=20,b=30。


3. 声明初始化:①首先进行静态字段t的声明初始化,创建Test1的实例,调用实例构造方法,执行后的结果是a=21,b=31


                         ②然后进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,结果还是a=21;                      但是静态字段b有声明初始化,所以结果是b=10。(大家对照这个流程,看一下上面的代码和运行结果)



Program Ⅴ:(有静态块,声明初始化语句在两个静态块定义之间)

class Test1 {
  public Test1() {
    System.out.println("Test1实例构造函数之前 a="+Test.a+",b="+Test.b);
    Test.a++;
    Test.b++;
    System.out.println("Test1实例构造函数之后 a="+Test.a+",b="+Test.b);
  }
}
public class Test {
  static {
    a=20;
    System.out.println("static静态代码块1之后 a="+Test.a+",b="+Test.b);
  }
  public static Test1 t=new Test1();
  public static int a;
  public static int b=10;
  static {
    b=30;
    System.out.println("static静态代码块2之后 a="+Test.a+",b="+Test.b);
  }
  public static void main(String[] args) {
    System.out.println("最后的结果:a="+Test.a+",b="+Test.b);
  }
}


Program Output Ⅴ:



Program Analysis Ⅴ:


按此顺序初始化静态变量:默认初始化→静态代码块1初始化→声明初始化→静态代码块2初始化


默认初始化:静态变量按照声明的顺序依次设置为该类型的默认值。


静态代码块初始化:按静态块的顺序依次设置静态字段的值。


声明初始化:静态变量按声明的顺序依次设置为声明初始化的值,如果没有声明初始化就跳过。


静态字段初始化流程如下:


1. 默认初始化:类被加载后,首先静态字段会进行默认初始化。 结果:t=null,a=0,b=0。


2. 静态代码块1初始化:对静态字段a进行静态块初始化,结果a=20,b=0。


3. 声明初始化:①首先进行静态字段t的声明初始化,创建Test1的实例,调用实例构造方法,执行之后结果是a=21,b=1。


                         ②然后进行静态字段a和b的声明初始化,因为静态字段a没有声明初始化,所以就跳过,结果还是a=21;                      但是静态字段b有声明初始化,所以结果是b=10。


4. 静态代码块2初始化:对静态字段b进行静态块初始化,结果a=21,b=30。(大家对照这个流程,看一下上面的代码和运行结果)


根据上面这五个Java小程序,大家可能觉得比较多,看起来不舒服,但是静态字段这部分内容还是很重要的!!!


所以希望大家可以耐心的去理解每一个程序代码,对我们后面的Java知识的学习还是有很大帮助的!!!😊😊😊


相关文章
|
2月前
|
人工智能 安全 Java
Java和Python在企业中的应用情况
Java和Python在企业中的应用情况
62 7
|
12天前
|
存储 Java 程序员
Java的基础概念一
### Java编程基础简介 #### 一、注释 注释用于解释代码,不会参与编译和运行。Java支持三种注释: - **单行注释**:以 `//` 开头。 - **多行注释**:以 `/* ... */` 包围。 - **文档注释**:通常用于生成开发文档。 #### 二、关键字 关键字是被Java赋予特定含义的英文单词,全部小写,且在代码编辑器中有特殊颜色标记。常用的如 `class` 表示定义一个类。
Java的基础概念一
|
2天前
|
Java 数据安全/隐私保护
Java的基础概念(二)
本文介绍了Java编程语言中的运算符和表达式,涵盖算术运算符、赋值运算符、关系运算符、逻辑运算符、三元运算符等。重点讲解了算术运算符的使用,如加减乘除取余,并强调了整数除法和取余的特殊性。同时,详细说明了隐式转换与强制转换的概念及应用场景,以及字符串和字符的拼接规则。通过多个案例演示了不同运算符的实际应用,包括数值拆分、自增自减、三元表达式的使用等。最后简要提及了运算符的优先级,指出小括号具有最高优先级。
|
13天前
|
安全 算法 Java
Java CAS原理和应用场景大揭秘:你掌握了吗?
CAS(Compare and Swap)是一种乐观锁机制,通过硬件指令实现原子操作,确保多线程环境下对共享变量的安全访问。它避免了传统互斥锁的性能开销和线程阻塞问题。CAS操作包含三个步骤:获取期望值、比较当前值与期望值是否相等、若相等则更新为新值。CAS广泛应用于高并发场景,如数据库事务、分布式锁、无锁数据结构等,但需注意ABA问题。Java中常用`java.util.concurrent.atomic`包下的类支持CAS操作。
44 2
|
2月前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
163 6
|
1月前
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
37 2
|
2月前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
69 6
|
2月前
|
关系型数据库 MySQL Java
MySQL索引优化与Java应用实践
【11月更文挑战第25天】在大数据量和高并发的业务场景下,MySQL数据库的索引优化是提升查询性能的关键。本文将深入探讨MySQL索引的多种类型、优化策略及其在Java应用中的实践,通过历史背景、业务场景、底层原理的介绍,并结合Java示例代码,帮助Java架构师更好地理解并应用这些技术。
57 2
|
2月前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
2月前
|
Java 测试技术 API
Java 反射机制:深入解析与应用实践
《Java反射机制:深入解析与应用实践》全面解析Java反射API,探讨其内部运作原理、应用场景及最佳实践,帮助开发者掌握利用反射增强程序灵活性与可扩展性的技巧。
124 4