Bootstrap

Java.lang.ExceptionInInitializerError异常

在静态代码块初始化过程中发生了异常,JVM则会跑出java.lang.ExecptionInInitializerError异常。静态代码块、静态变量都是在类加载的时候进行初始化的。

类的生命周期分为了加载、连接(验证、准备、解析)、初始化、使用、卸载这5个过程,而静态代码块和静态变量的初始化相关操作主要位于连接的准备、和初始化中。

连接的准备阶段:主要做的事为static修饰的成员变量分配内存,并赋予初始值。

初始化阶段是执行类构造器clinit()方法的过程:

clinit方法是有编译器自动收集类中的所有类变量(类变量就是静态变量)的赋值动作和静态语句块(static{})块中的语句合并产生的,编译器收集顺序是 由语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量。

clinit()方法不需要显式调用父类构造器,虚拟机会保证在子类clinit()方法执行之前,父类的clinit()方法已经执行完毕。所以虚拟机第一个执行的肯定是java.lang.object.

由于父类的clinit()方法先执行,也就意味着父类中定义的静态语句块要优于子类的变量赋值操作。

如果一个类中没有静态语句块和堆变量赋值语句,编译器可以不为这个类生成clinit()方法。

所以由以上可以看出类变量的初始化顺序由它们在源文件中出现的顺序决定的,如果第一行声明了一个静态变量,它在第二行被使用,实际上它却在第三行被初始化,这样+-的情况就会出现变量初始化异常,具体异常就是NullPointerException异常。

如果在主线程中执行了这段代码,控制台或日志文件就会出现“Exception inthread "main" java.lang.ExceptionInInitializerError”。在大量的日志文件中可能被忽略,而你可能得到的是java.lang.NoClassDefFound异常。不幸的是只有在你使用到这个类时,才能出现这个错误。因为ExceptionInInitializerError导致这个类无法加载,然后由于类加载失败了JVM会抛出NoClassDefFoundError。这样就会导致你会检查路径、PATH、以及java.library.path看是不是缺少这个类。因此,如果你在分析NotClassDefFoundError的原因时,最好看下日志文件中是否有ExceptionInInitializerError,然后再检查classPath。

当知道出现ExceptionInInitializerError异常时,是应为类加载过程中静态代码块初始化过程失败所导致的。由于他出现在负责启动程序的主线程中,因此最好从主类开始分析,主类是指你在命令行参数中指定的那个,或者声明了public static void main (String args[])方法的那个类。

java中读取配置文件中路径时,若路径中部分使用“\”而不是“/”,系统默认解析为“\u”形式,因此配置文件中若有路径信息,应使用“\\”或者“/”。

使用类加载来构建资源时,注意包名中的“.”使用“/”代替。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;