欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java中static静态变量的初始化完全解析

程序员文章站 2024-03-12 19:32:26
静态变量初始化顺序 1.简单规则 首先先看一段最普遍的java代码: public class test { public static test1 t...

静态变量初始化顺序
1.简单规则

首先先看一段最普遍的java代码:

public class test
{
 public static test1 t = new test1();
 public static int a = 0;
 public static int b;

 public static void main(string[] arg)
 {
  system.out.println(test.a);
  system.out.println(test.b);
 }
}

class test1
{
 public test1()
 {
  test.a++;
  test.b++;
 }
}

这里先猜下控制台输出结果是什么?

ok, 或许你已经猜到下面了结果了,那么你还是熟悉java的。

复制代码 代码如下:
0 1

如果你不明白是为什么会输出上面的结果,那么我来告诉你。

java静态变量初始化遵循以下规则:

  • 静态变量会按照声明的顺序先依次声明并设置为该类型的默认值,但不赋值为初始化的值。
  • 声明完毕后,再按声明的顺序依次设置为初始化的值,如果没有初始化的值就跳过。

看了这个就会明白,原来test.a的值变化了三次。

声明时设置为0>>test1::test1里设置为1>>test.a初始化为0

2.复杂规则

明白了这个,请再看下面的代码。

public class a
{
 public static int b = b.a;
 public static a plus =new a("a");
 public static final int finalint = (int)(math.random()*100);
 public static b p = new b("a");

 public static final string finalstr = "finalstr";
 public static final integer finalinteger = new integer(10);
 public static int a = 1;
 public static b c = null;

 public a(string from)
 {
  system.out.println("----------- begin a::a ----------------");
  system.out.println("a::a, from="+from);
  system.out.println("a::a, a.b="+a.b);
  system.out.println("a::a, a.finalint="+a.finalint);
  system.out.println("a::a, b.a="+b.a);
  system.out.println("a::a, b.plus="+b.plus);
  system.out.println("----------- end a::a ----------------");
 }

 public static void main(string[] arg)
 {
  system.out.println("main, a.b="+a.b);
  system.out.println("main, b.t="+b.t);
  system.out.println("main, c.a="+c.a);
 }
}

class b
{
 public static int t = a.a;
 public static a plus = new a("b");
 public static int a = 1;

 public b(string from)
 {
  system.out.println("----------- begin b::b ----------------");
  system.out.println("b::b, from="+from);
  system.out.println("b::b, b.a="+b.a);
  system.out.println("b::b, a.a="+a.a);
  system.out.println("b::b, a.p="+a.p);
  system.out.println("b::b, a.plus="+a.plus);
  system.out.println("b::b, a.finalint="+a.finalint);
  system.out.println("b::b, a.finalinteger="+a.finalinteger);
  system.out.println("b::b, a.finalstr="+a.finalstr);
  system.out.println("----------- end b::b ----------------");
 }
}

class c
{
 public static final a a = new a("c");
}

这个你还能猜到输出结果吗? 我是在一边测试一边写的,所以我没猜出来.哈哈

控制台输出结果为:

----------- begin a::a ----------------
a::a, from=b
a::a, a.b=0
a::a, a.finalint=0
a::a, b.a=0
a::a, b.plus=null
----------- end a::a ----------------
----------- begin a::a ----------------
a::a, from=a
a::a, a.b=1
a::a, a.finalint=0
a::a, b.a=1
a::a, b.plus=a@a90653
----------- end a::a ----------------
----------- begin b::b ----------------
b::b, from=a
b::b, b.a=1
b::b, a.a=0
b::b, a.p=null
b::b, a.plus=a@1fb8ee3
b::b, a.finalint=61
b::b, a.finalinteger=null
b::b, a.finalstr=finalstr
----------- end b::b ----------------
main, a.b=1
main, b.t=0
----------- begin a::a ----------------
a::a, from=c
a::a, a.b=1
a::a, a.finalint=61
a::a, b.a=1
a::a, b.plus=a@a90653
----------- end a::a ----------------
main, c.a=a@61de33

这个结果你没猜到吧,哈哈.

要一句一句的讲解程序执行结果,还是要很到的篇幅的.这里就直接写出java静态变量初始化遵循的规则了。

第一段的规则依然有效,只是不健全。

  • 只有主动请求一个类,这个类才会初始化,仅包含静态变量,函数,等静态的东西.
  • 继承关系时,先初始化父类,后初始化子类.
  • 静态变量会按照声明的顺序先依次声明并设置为该类型的默认值,但不赋值为初始化的值.
  • 声明完毕后,再按声明的顺序依次设置为初始化的值,如果没有初始化的值就跳过.
  • 当初始化a.b=b.a时,暂停初始化a.b,设置当前类为b,跳到步骤3,并执行.
  • 当初始化b.plus = new a时,暂停初始化b.plus,实例化a并赋值给b.plus.
  • 当a的构造函数里需要获得b.a的值时,b.a还初始化并处于暂停初始化状态,直接取b.a的当前值,不再等待b.a初始化.
  • final,静态常量其实是遵循普通静态变量的初始化的,但是在编译时,编译器会将不可变的常量值在使用的地方替换掉.可以用java反编译工具查看.

static数据的初始化
加上static限定的字段,是所谓的类字段,也就是说这个字段的拥有者不是对象而是类。无论创建多少对象,static数据都只有一份。

类内总是先初始化static字段,再初始化一般字段。接着初始化构造器。但是如果不创建这个类的对象,那这个对象是不会进行初始化的,并且只执行一次。

如下面的代码,在staticinitialization类中,先初始化static table table = new table();,然后才去初始化table对象,不然是不会被初始化的。

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();
}

输出:

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)

显示的静态初始化(也就是静态块)
把多个初始化语句包在一个static花括号里,叫做静态块,其实就是把多个static合在一起写了,本质是一样的。只有首次创建对象或者首次访问类的字段时才会执行,而且仅仅一次。

class cup {
 cup(int marker) {
 print("cup(" + marker + ")");
 }
 void f(int marker) {
 print("f(" + marker + ")");
 }
}

class cups {
 static cup cup1;
 static cup cup2;
 static {
 cup1 = new cup(1);
 cup2 = new cup(2);
 }
 cups() {
 print("cups()");
 }
}

public class explicitstatic {
 public static void main(string[] args) {
 print("inside main()");
 cups.cup1.f(99); // (1)
 }
 // static cups cups1 = new cups(); // (2)
 // static cups cups2 = new cups(); // (2)
} 

输出:

inside main()
cup(1)
cup(2)
f(99)

非静态实例初始化
这个没什么好讲的,就是普通初始化,按顺序执行,可以多次执行。

class mug {
 mug(int marker) {
 print("mug(" + marker + ")");
 }
 void f(int marker) {
 print("f(" + marker + ")");
 }
}

public class mugs {
 mug mug1;
 mug mug2;
 {
 mug1 = new mug(1);
 mug2 = new mug(2);
 print("mug1 & mug2 initialized");
 }
 mugs() {
 print("mugs()");
 }
 mugs(int i) {
 print("mugs(int)");
 }
 public static void main(string[] args) {
 print("inside main()");
 new mugs();
 print("new mugs() completed");
 new mugs(1);
 print("new mugs(1) completed");
 }
}

inside main()
mug(1)
mug(2)
mug1 & mug2 initialized
mugs()
new mugs() completed
mug(1)
mug(2)
mug1 & mug2 initialized
mugs(int)
new mugs(1) completed