背景

之前在集成第三方即时通信系统-融云的时候,我直接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. Iceberg使用

    Iceberg是Mac下比較好用的pkg生成工具. 在files中选择你想要存放(自己文件的目录),生成pkg后目录就会存储在设置的那个目录下. 点击scripts选择pkg安装各个阶段所要运行脚本路 ...

  2. v-if和updated钩子结合使用 渲染echart图表

    项目需求是这样的,用户可以自定选择echart 曲线图 是横向还是竖向显示.我的做法是 写了一个横向的echart图表,也写了一个竖向的echart图表,然后两者共用存在store里的图表数据,就能实 ...

  3. OC学习篇之—写类别(类的扩展)

    首先我们来看一下场景,如果我们现在想对一个类进行功能的扩充,我们该怎么做? 对于面向对象编程的话,首先会想到继承,但是继承有两个问题: 第一个问题:继承的前提是这个类可以被继承,因为在Java中有些类 ...

  4. Shiro的Filter机制详解---源码分析(转)

    Shiro的Filter机制详解 首先从spring-shiro.xml的filter配置说起,先回答两个问题: 1, 为什么相同url规则,后面定义的会覆盖前面定义的(执行的时候只执行最后一个). ...

  5. 【转载】C# winform操作excel(打开、内嵌)

    本文转载自静待"花落<C# winform操作excel(打开.内嵌)>   说明:显示的excel是利用模板创建的 using System;using System.Coll ...

  6. C#无符号右移

    /// <summary>         /// 无符号右移,与JS中的>>>等价         /// </summary>         /// & ...

  7. 26、从零写UVC驱动之分析描述符

    指令:lsusb 可以查看usb设备的描述符信息,当然lsusb指令要带一些参数 一个usb设备有多个config配置+设备描述符,一个config有多个接口和association.config描述 ...

  8. 17、网卡驱动程序-DM9000举例

    (参考:cs89x0.c可以参考) DM9000 芯片实现网络功能的基础,在接收数据时采用中断方式,即当有数据到来并在 DM9000 内部 CRC 校验通过后会产生一个接收中断: 网卡驱动程序框架: ...

  9. Win或Linux中编译安装软件的命令解析: configure; make; make install

    原文地址:http://www.cnblogs.com/Jerry-Chou/archive/2010/12/18/1909843.html 翻译一篇文章,我最早从这篇文章中了解到为什么Linux平台 ...

  10. linux下如何获取某一进程占用的物理内存和虚拟内存

    首先,ps -A查看你所查看进程的进程号 ps -A 加入进程号为pid 那么使用如下脚本,可以打印该进程使用的虚拟内存和物理内存: root@Storage:/mnt/mtd# cat rss.sh ...