背景

之前在集成第三方即时通信系统-融云的时候,我直接clone它的服务端源码,然后导入我的项目,我在测试它连接融云服务器案例时,发现一直不成功,始终报一个 ExceptionInInitializerError 的异常。后来通过网上查资料才发现,这个异常是静态变量初始化时出现异常时,JVM会抛出java.lang.ExceptionInInitializerError的异常。由此,我对这个异常做了进一步探究。

抛出ExceptionInInitializerError异常的原因

因为这个异常时在静态变量初始化发生异常时抛出的,所以首先我们了解一下静态变量初始化的问题

静态变量初始化

提到静态变量初始化,又不得不提JVM的类加载机制,把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

类加载的生命周期包括:加载,验证,准备,解析,初始化,使用和卸载这7个阶段。静态变量的初始化相关操作主要在准备和初始化阶段。

准备阶段

对于我们的静态变量来说,首先在准备阶段进行类变量内存的分配以及设置类变量初始值,(类变量是指被static修饰的变量),例如:

  public static int value = 123.
//这时初始值为value = 0;

初始化阶段

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

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

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

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

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

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

引起ExceptionInInitializerError异常的真凶

分析完了静态变量初始化问题,再来看具体引起ExceptionInInitializerError异常产生的原因是什么。在没碰到ExceptionInInitializerError异常的时候,我也不知道具体能引起它的原因有什么,所以我还是利用了搜索引擎Google了一下,发现任何异常都有可能引起ExceptionInInitializerError异常的发生,比如说:java.lang.ArrayIndexOutOfBound或者java.lang.NullPointerException。

再来具体看看我项目中的实际情况是什么:

我运行代码发现,控制台打印出了空指针的错误

  Exception in thread "main" java.lang.ExceptionInInitializerError
at io.rong.util.CommonUtil.getCheckInfo(CommonUtil.java:340)
at io.rong.util.CommonUtil.checkFiled(CommonUtil.java:73)
at io.rong.methods.user.User.register(User.java:59)
at io.rong.example.user.UserExample.main(UserExample.java:40)
Caused by: java.lang.NullPointerException //空指针
at io.rong.util.JsonUtil.<clinit>(JsonUtil.java:17)
... 4 more

空指针的错误具体位置是在:

  public class JsonUtil {
   private static final String JSONFILE = JsonUtil.class.getClassLoader().getResource("jsonsource").getPath()+"/";//这个地方报错
  ...
}

即也就是在静态变量初始化的时候抛出的空指针异常。那么为什么会抛出空指针呢。接下来就要说JsonUtil.class.getClassLoader().getResource("jsonsource")的问题

class.getClassLoader()解析问题

getClassLoader()获取的是这个 类对象的加载器,只有Class类才有getClassLoader()方法,当一个类被虚拟机加载完毕过后,也就是上面所说的类加载机制,然后会创建一个Class类实例,用于虚拟机对类的管理,所以JsonUtil.class就是获得它的Class类,。

而JsonUtil.class.getClassLoader().getResource("jsonsource")就是在JsonUtil当前位置查找“jsonsource"这个资源文件。这是一个相对路径,实际上它返回的是一个URL.

   public URL getResource(String name) {
      URL url;
      ...

然后getPath(),就是获取这个URL的路径地址。但是却报出 java.lang.NullPointerException空指针异常。说明资源没找到。想想第三方平台肯定提供的资源的,结果仔细一看,是我没有把它SDK中的resources资源文件导入,所以找不到“jsonsource"资源,所以才报出空指针错误,从而报出ExceptionInInitializerError异常。这才找到了最终的真凶。

参考资料

项目中碰到的ExceptionInInitializerError异常的更多相关文章

  1. text-align:justify在项目中碰到的问题

    最近在项目中,使用了一个新的样式属性:text-align:justigy,这个属性在使用过程中遇到了一些小异常,现在总结下.  text-align有一个属性值为justify,为对齐之意.其实现的 ...

  2. Vue项目三、项目中碰到的问题详解

    一.组件的划分创建 方法一: 把页面上需要复用的模块,拆分成组件.比如,页面的header.footer.面包屑.弹出框等拆分成组件.所以在src中应该有一个文件夹(components)专门放这些会 ...

  3. 解决tomcat部署项目中碰到的几个问题

    在tomcat上部署项目并进行测试,经常会碰到各种问题.在不同的操作系统上部署,对问题的解决也会有一些差异. 1 发现问题 1.1 项目部署 先将项目达成war包,放到tomcat的webapps目录 ...

  4. 关于项目中遇到的NullPointerException异常时处理手段

    在项目开发中,经常会遇到NullPointerException异常,特别是一些新手,非常的郁闷,有时候会很隐蔽,特别是不同的人书写的代码进行调用时. 以下是我所遇到的NullPointerExcep ...

  5. Extjs 在项目中碰到问题

    1.切换tabpanel,新建tab关闭后再新建报错,在火狐下报错 TypeError: el is null   el.addCls.apply(el, arguments); 这个我在下一篇文章中 ...

  6. JavaWeb项目中获取对Oracle操作时抛出的异常错误码

    最近在项目中碰到了这么一个需求,一个JavaWeb项目,数据库用的是Oracle.业务上有一个对一张表的操作功能,当时设置了两个字段联合的唯一约束.由于前断没有对重复字段的校验,需要在插入时如果碰到唯 ...

  7. J2EE项目中异常处理

     为什么要在J2EE项目中谈异常处理呢?可能许多java初学者都想说:“异常处理不就是try….catch…finally吗?这谁都会啊!”.笔者在初学java时也是这样认为的.如何在一个多层的j2e ...

  8. 【C++模版之旅】项目中一次活用C++模板(traits)的经历

    曾经曾在一个项目中碰到过一个挺简单的问题,但一时又不能用普通常规的方法去非常好的解决,最后通过C++模板的活用,通过traits相对照较巧妙的攻克了这个问题.本文主要想重现问题发生,若干解决方式的比較 ...

  9. 我是如何在公司项目中使用ESLint来提升代码质量的

    ESLint:你认识我吗 ESLint是一个语法规则和代码风格的检查工具. 和学习所有编程语言一样,想要入门ESLint,首先要去它的官网看看:https://eslint.org/. ESLint的 ...

随机推荐

  1. 好记性不如烂笔头——double

    两个数据转换成double型做差,会出现误差,转换成Decimal就OK了.

  2. Spring Boot中的缓存支持(一)注解配置与EhCache使用

    Spring Boot中的缓存支持(一)注解配置与EhCache使用 随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决 ...

  3. Android 中AIDL的使用与理解

    AIDL的使用: 最常见的aidl的使用就是Service的跨进程通信了,那么我们就写一个Activity和Service的跨进程通信吧. 首先,我们就在AS里面新建一个aidl文件(ps:现在AS建 ...

  4. FZU 2020 组合

    组合数求模要用逆元,用到了扩展的欧几里得算法. #include<cstdio> int mod; typedef long long LL; void gcd(LL a,LL b,LL ...

  5. 使用doxygen为C/C++程序生成中文文档

    文章来自:http://www.fmddlmyy.cn/text21.html 依照约定的格式凝视源码,用工具处理凝视过的源码产生文档.通过这样的方式产生文档至少有下面优点: 便于代码和文档保持同步. ...

  6. 使用boost::property_tree生成带attribute的xml

    曾经写过一篇"使用Boost property tree来解析带attribute的xml", 但是还有姐妹篇一直没贴.看看前一篇贴了都快都快3年了,时间过的真快. 这一小篇就算是 ...

  7. tensorflow 下的滑动平均模型 —— tf.train.ExponentialMovingAverage

    在采用随机梯度下降算法训练神经网络时,使用 tf.train.ExponentialMovingAverage 滑动平均操作的意义在于提高模型在测试数据上的健壮性(robustness). tenso ...

  8. [AngularJS Ng-redux] Integrate ngRedux

    Up to this point, we have created an effective, yet rudimentary, implementation of Redux by manually ...

  9. 洛谷 P3112 后卫马克Guard Mark

    ->题目链接 题解: 贪心+模拟 #include<algorithm> #include<iostream> #include<cstring> #incl ...

  10. JS实现页面table鼠标移动改变tr行颜色,单击tr选中复选框功能

    JS源代码: //需要设置tr背景颜色 var highlightcolor='#bfecfc'; //设置背景颜色 function changeto(index){ var tr1 = docum ...