java static数据的初始化

本文深入探讨了Java中静态成员的初始化过程,包括静态成员何时及如何被初始化,以及静态成员与非静态成员初始化顺序的区别。并通过具体代码示例展示了静态成员在类加载时的初始化行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     无论创建多少对象,static数据都只只用一份存储区域。static关键字不能应用于局部变量,因此他只能这用于域。如果一个域是基本类型,并且没有给它初始化,那么他会默认为基本类型的标准初始值;如果是一个引用,那么他会默认为初始值null。

     想要了解静态域是如何初始化的,请看下面的例子。

 

    package initialization;

//: initialization/StaticInitialization.java
// Specifying initial values in a class definition.
import static net.mindview.util.Print.*;

 

class Bowl {
  Bowl(int marker) {
    print("Bowl(" + marker + ")");
  }
  void f1(int marker) {
    print("f1(" + marker + ")");
  }
}

 

class Table {
  static Bowl bowl1 = new Bowl(1);
  Table() {
    print("Table()");
    bowl2.f1(1);
  }
  void f2(int marker) {
    print("f2(" + marker + ")");
  }
  static Bowl bowl2 = new Bowl(2);
}

 

class Cupboard {
  Bowl bowl3 = new Bowl(3);
  static Bowl bowl4 = new Bowl(4);
  Cupboard() {
    print("Cupboard()");
    bowl4.f1(2);
  }
  void f3(int marker) {
    print("f3(" + marker + ")");
  }
  static Bowl bowl5 = new Bowl(5);
}

 

public class StaticInitialization {
  public static void main(String[] args) {
    print("Creating new Cupboard() in main");
    new Cupboard();
    print("Creating new Cupboard() in main");
    new Cupboard();
    table.f2(1);
    cupboard.f3(1);
  }
  static Table table = new Table();
  static Cupboard cupboard = new Cupboard();
}

 /* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*/
    Bowl类使得看到类的创建,而Table类和Cupboard类在他们的类中分别定义了Bowl类的static成员对象。注意在定义静态数据成员之前,Cupboard类先定义了一个Bowl类型的非静态成员bowl3。

   由此可见静态数据只有在必要时才进行初始化。如果不创建Table对象,也不引用Talbe的bowl1和bowl2,那么Talbe的bowl1和bowl2永远都不会被创建。只有在第一个Talbe被创建时或第一次访问其中的Bowl类型的静态成员时,他们才会被初始化。此后静态数据不会在被初始化。

   通过上面的事例可以总结:在创建一个类时,初始化的顺序是先是静态数据,并且仅初始化一次(如果它们尚未因前面对象的创建或某些动作的执行未被初始化),而后是非静态数据(每次在创建时都会初始化),然后是构造函数。

     另外直接用类名调用静态数据和静态方法时,这个类中的所以静态成员都会被初始化(非static成员不会被初始化),前提是他们从未被初始化过。

  从结果中可以观察到这一点。要执行main()(stati方法),必须加载StaticInitialization类,然后是StaticInitialization 类中的sataic成员table 和cupboard 的初始化,这将导致Tabel和Cupboard 类中的静态数据也会被初始化。这样在main()未开始之前,所有对象已经被初始化。然而在main()方法在执行创建Cupboard 类对象时,Cupboard 中的static数据不会再被初始化,因为static数据已经在main()之前已经被第一次初始化。

 

### Java 中 `static` 关键字的初始化过程 在 Java 中,`static` 是用于声明属于类而非特定对象的字段、方法或代码块的关键字。以下是关于 `static` 的初始化过程及其使用的详细介绍: #### 静态变量和静态代码块的加载顺序 当 JVM 加载一个类时,会按照以下顺序处理该类中的静态部分: 1. **静态变量的初始化** 静态变量会在类被加载时按其在源码中出现的顺序依次初始化[^1]。 2. **静态代码块的执行** 执行所有的静态代码块,同样遵循它们在源码中定义的顺序[^2]。 这些操作只发生一次,即第一次使用该类时触发(例如通过创建实例或者访问静态成员)。一旦类被加载并完成了静态初始化,后续对该类的操作不会再次触发这一过程。 #### 示例分析 考虑下面的例子来理解具体的流程: ```java public class StaticInitExample { static int x = getValue(); static { System.out.println("Static block executed"); } public static int getValue() { System.out.println("getValue method called"); return 42; } } ``` 运行此程序的结果将是先输出 `"getValue method called"` ,接着才是 `"Static block executed"` 。这表明即使存在显式的赋值逻辑,JVM也会优先依据书写次序完成所有必要的准备工作后再进入下一个阶段[^3]。 #### 解决可能遇到的问题——重复初始化情况下的应对策略 有时开发者可能会面临某些特殊场景下需要重新设置某个已经存在的静态属性的情况。虽然理论上讲,除非卸载再重载整个 ClassLoader 否则无法做到真正的“重新”初始化;不过可以通过设计模式规避此类需求,比如采用单例模式控制资源获取时机等手段间接达成目的[^3]。 另外值得注意的是,在涉及继承关系的情况下,父类的所有静态组件都会早于任何子类相关内容得到处置[^5]。这意味着如果尝试从派生类别处引用超类型里的东西,则需确保前者已被适当安排好才能正常运作。 ### 使用建议 为了使应用程序更加健壮可靠,在运用 `static` 进行开发期间应当注意几点事项: - 尽量减少对外暴露可变状态的机会; - 对共享数据结构采取同步措施防止并发冲突; - 明确区分哪些行为应该关联至具体实体之上而不是全局范围内适用的功能模块里去实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值