类的初始化过程是这样的:按照顺序自上而下运行类中的变量赋值语句和静态语句,如果有父类,则首先按照顺序运行父类中的变量赋值语句和静态语句。先看一个例子,首先建两个类用来显示赋值操作:`u/GVG7_0
.C
s4d$AIn4n0- public class Field1{
- public Field1(){
- System.out.println("Field1构造方法");
- }
- }
- public class Field2{
- public Field2(){
- System.out.println("Field2构造方法");
- }
- }
|
{(?br+o"Ff1c1`0 下面是演示初始化顺序的代码:
bB
l+|'As6]%BGb051Testing软件测试网Y1ajV;DY@0F51Testing软件测试网2JM*d1T&NuE
- class InitClass2{
- static{
- System.out.println("运行父类静态代码");
- }
- public static Field1 f1 = new Field1();
- public static Field1 f2;
- }
-
- class SubInitClass2 extends InitClass2{
- static{
- System.out.println("运行子类静态代码");
- }
- public static Field2 f2 = new Field2();
- }
-
- public class Test2 {
- public static void main(String[] args) throws ClassNotFoundException{
- new SubInitClass2();
- }
- }
|
v3jgCHD0 上面的代码中,初始化的顺序是:第03行,第05行,第11行,第13行。第04行是声明操作,没有赋值,所以不会被运行。而下面的代码:
h,}R1c;g.H$c051Testing软件测试网9V7M O`,F1c*@mYw {&M}0d0- class InitClass2{
- public static Field1 f1 = new Field1();
- public static Field1 f2;
- static{
- System.out.println("运行父类静态代码");
- }
- }
-
- class SubInitClass2 extends InitClass2{
- public static Field2 f2 = new Field2();
- static{
- System.out.println("运行子类静态代码");
- }
- }
-
- public class Test2 {
- public static void main(String[] args) throws ClassNotFoundException{
- new SubInitClass2();
- }
- }
|
k7Eq-lo+e(P1H1W{q0 初始化顺序为:第02行、第05行、第10行、第12行,各位可以运行程序查看结果。51Testing软件测试网c]:POL3B
EN}
51Testing软件测试网 ?lUYdm 在类的初始化阶段,只会初始化与类相关的赋值语句和静态语句,也就是有static关键字修饰的信息,没有static修饰的赋值语句和静态语句在实例化对象的时候才会运行。51Testing软件测试网
]k`H'F
51Testing软件测试网hX5{T:m-|,e 使用51Testing软件测试网"~%U`
_%]3gq)be
51Testing软件测试网Hnd*k8G Ka
t:f~ 类的使用包括主动引用和被动引用,主动引用在初始化的章节中已经说过了,下面我们主要来说一下被动引用:51Testing软件测试网"F$U3Zk
RCB E
51Testing软件测试网%M"T1v!N,a$^&k5? ● 引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化。51Testing软件测试网_TO-a5q1c
+q d*m:Y0i#v"N0 ● 定义类数组,不会引起类的初始化。51Testing软件测试网SEk#vyEp-]R
Qe0S
Fp"D$i$@P8I0 ● 引用类的常量,不会引起类的初始化。
5_Q:tb?8B.o0 E l4t(}L0被动引用的示例代码:
L.R6_v0|+F051Testing软件测试网
E8BudA
x51Testing软件测试网b~]B*k!Es@^J;E \
- class InitClass{
- static {
- System.out.println("初始化InitClass");
- }
- public static String a = null;
- public final static String b = "b";
- public static void method(){}
- }
-
- class SubInitClass extends InitClass{
- static {
- System.out.println("初始化SubInitClass");
- }
- }
-
- public class Test4 {
-
- public static void main(String[] args) throws Exception{
-
-
- SubInitClass[] sc = new SubInitClass[10];
- }
- }
|
51Testing软件测试网n`:I{8i-oL
J(q)t 最后总结一下使用阶段:使用阶段包括主动引用和被动引用,主动饮用会引起类的初始化,而被动引用不会引起类的初始化。51Testing软件测试网:j|"{4s
C
5z-La
{"gB0 当使用阶段完成之后,java类就进入了卸载阶段。
i~V*d4rXH051Testing软件测试网4\
Mf(q!^6x,s 卸载51Testing软件测试网+J6k2X9~6E-c\x
`V
51Testing软件测试网F3M
MZ#wp 关于类的卸载,笔者在单例模式讨论篇:单例模式与垃圾回收一文中有过描述,在类使用完之后,如果满足下面的情况,类就会被卸载:
.Qpk/qUk\R051Testing软件测试网 h w)N%|Ctq
{v 该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
1ZXj2YN@Xqb6G'V+d0'bl^/yQ0 加载该类的ClassLoader已经被回收。
KD1j ya f051Testing软件测试网cSj
B6pjm 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
~Y#_hw+EzU)b051Testing软件测试网)BF+o:WFRV-f Qt/J 如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就是在方法区中清空类信息,java类的整个生命周期就结束了。51Testing软件测试网/r
S/c)p {y%x
!zx d~N
~0 总结
)r,s$G3nFS0C!|4E \dn"v P%U.y0 做java的朋友对于对象的生命周期可能都比较熟悉,对象基本上都是在jvm的堆区中创建,在创建对象之前,会触发类加载(加载、连接、初始
化),当类初始化完成后,根据类信息在堆区中实例化类对象,初始化非静态变量、非静态代码以及默认构造方法,当对象使用完之后会在合适的时候被jvm垃圾
收集器回收。读完本文后我们知道,对象的生命周期只是类的生命周期中使用阶段的主动引用的一种情况(即实例化类对象)。而类的整个生命周期则要比对象的生
命周期长的多。51Testing软件测试网H)]:c&W
^nNzE