背景

之前在集成第三方即时通信系统-融云的时候,我直接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. JDBC高级特性(二)事务、并发控制和行集

    一.事务 事务是指一个工作单元,它包括了一组加入,删除,改动等数据操作命令,这组命令作为一个总体向系统提交运行,要么都运行成功,要么所有恢复 在JDBC中使用事务 1)con.setAutoCommi ...

  2. Cscope how to support java and c++

    Cscope 首先在文件夹下建立cscope索引文件 find -name '*.c' > cscope.file cscope -Rbkq 这个命令会生成三个文件:cscope.out, cs ...

  3. JS学习笔记 - 普通选项卡(面向过程)

    疑问: 1. getElementsByTagName 和 getElementsByClassName  的区别? 分别在什么应用场景?    <!DOCTYPE html> <h ...

  4. 【Codeforces Round #301 (Div. 2) B】 School Marks

    [链接] 我是链接,点我呀:) [题意] 已知k门成绩. 总共有n门成绩. 让你构造剩下的n-k门成绩,使得这n门成绩的中位数>=y,并且这n门成绩的和要小于等于x. n为奇数 [题解] 首先判 ...

  5. OAuth2 社区通用组件

    转载:http://www.cyqdata.com/download/article-detail-54302   使用本组件,只需要几行代码,就可以在网站上集成以下效果:     相关文章及使用说明 ...

  6. 10.9 android输入系统_APP跟输入系统建立联系和Dispatcher线程_分发dispatch

    12. 输入系统_APP跟输入系统建立联系_InputChannel和Connection核心: socketpair // 第9课第3节_输入系统_必备Linux编程知识_任意进程双向通信(scok ...

  7. 【rlz02】二进制转十进制

    Time Limit: 3 second Memory Limit: 2 MB 问题描述 输入一个二进制数,编程转换为十进制数. 整数部分不会超过65535,二进制的小数部分不会超过4位. Sampl ...

  8. MySQL误删数据救命指南

    预防误操作导致文件/数据丢失的建议: 1.欲删除文件时,将rm命令改成mv,可在系统层面将rm命令做个alias(或参考Windows / Mac OSX做法,删除文件时先进回收站).2.删除数据库. ...

  9. thinkphp 获取url参数,汉字获取不到

    //这样获取不到 dump($_GET['car_code']); //这样就可以获取了 dump(iconv("gb2312","utf-8",$_GET[' ...

  10. 《JavaScript &amp; jQuery交互式Web前端开发》之JavaScript基础指令

           在本节中.你将開始学习阅读和编写JavaScript代码,还将学习怎样编写Web浏览器可以遵照运行的指令.在開始学习后面章节中的更复杂的概念之前.我们先学习语言的一些核心部分,然后看看怎 ...