详解java类的生命周期(三)

2014-11-24 07:51:07 · 作者: · 浏览: 3
赋值,所以不会被运行。而下面的代码:

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

初始化顺序为:第02行、第05行、第10行、第12行,各位可以运行程序查看结果。

在类的初始化阶段,只会初始化与类相关的赋值语句和静态语句,也就是有static关键字修饰的信息,没有static修饰的赋值语句和静态语句在实例化对象的时候才会运行。

使用
类的使用包括主动引用和被动引用,主动引用在初始化的章节中已经说过了,下面我们主要来说一下被动引用:

引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化。
定义类数组,不会引起类的初始化。
引用类的常量,不会引起类的初始化。
请看一下被动引用的示例代码:

[java] 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{
// String a = SubInitClass.a;// 引用父类的静态字段,只会引起父类初始化,而不会引起子类的初始化
// String b = InitClass.b;// 使用类的常量不会引起类的初始化
SubInitClass[] sc = new SubInitClass[10];// 定义类数组不会引起类的初始化
}
}
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{
// String a = SubInitClass.a;// 引用父类的静态字段,只会引起父类初始化,而不会引起子类的初始化
// String b = InitClass.b;// 使用类的常量不会引起类的初始化
SubInitClass[] sc = new SubInitClass[10];// 定义类数组不会引起类的初始化
}
}

最后总结一下使用阶段:使用阶段包括主动引用和被动引用,主动饮用会引起类的初始化,而被动引用不会引起类的初始化。

当使用阶段完成之后,java类就进入了卸载阶段。

卸载
关于类的卸载,笔者在单例模式讨论篇:单例模式与垃圾回收一文中有过描述,在类使用完之后,如果有下面的情况,类就会被卸载:

该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
加载该类的ClassLoader已经被回收。
该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就是在方法区中清空类信息,java类的整个生命周期就结束了。

总结
做java的朋友对于对象的生命周期可能都比较熟悉,对象基本上都是在jvm的堆区中创建,在创建对象之前,会触发类加载(加载、连接、初始化),当类初始化完成后,根据类信息在堆区中实例化类对象,初始化非静态变量、非静态代码以及默认构造方法,当对象使用完之后会在合适的时候被jvm垃圾收集器回收。读完本文后我们知道,对象的生命周期只是类的生命周期中使用阶段的主动引用的一种情况(即实例化类对象)。而类的整个生命周期则要比对象的生命周期长的多。


摘自 卡奴达摩的专栏