java含有静态代码块新建的时候报错java.lang.ExceptionInInitializerError

问题描述

最近在写一些单元测试用例,为了避免连接外界服务,所有选择mock了数据库Dao层,计划将数据库所需要的数据存在List中,在类加载的时候初始化List并且填充数据。代码如下:

 1 public class UserDaoMock extends UserDao {
 2     @Override
 3     public List<UserInfo> selectUserInfo() {
 4         return getUserInfo();
 5     }
 6 
 7     static {
 8         initUserInfo();
 9     }
10 
11     public static UserInfo getUserInfo() {
12         return userInfos;
13     }
14 
15     
16     private static List<UserInfo> userInfos = new ArrayList<UserInfo>();
17     private static void initUserInfo() {
18         UserInfo userInfo1 = new UserInfo();
19         userInfo1.setId(1L);
20         userInfo1.setPin("user1");
21         userInfo1.setUserId(1L);
22         userInfo1.setDataBillingType(1);
23         userInfo1.setErp("operator1");
24         userInfo1.setCreatedTime("2019-01-01");
25         userInfo1.setModifiedTime("2019-05-01");
26         userInfo1.setYn(1);
27         userInfos.add(userInfo1);
28 
29         UserInfo userInfo2 = new UserInfo();
30         userInfo2.setId(2L);
31         userInfo2.setPin("user2");
32         userInfo2.setUserId(2L);
33         userInfo2.setDataBillingType(1);
34         userInfo2.setErp("operator2");
35         userInfo2.setCreatedTime("2019-01-01");
36         userInfo2.setModifiedTime("2019-05-01");
37         userInfo2.setYn(1);
38         userInfos.add(userInfo2);
39 
40         UserInfo userInfo3 = new UserInfo();
41         userInfo3.setId(3L);
42         userInfo3.setPin("user3");
43         userInfo3.setUserId(3L);
44         userInfo3.setDataBillingType(1);
45         userInfo3.setErp("operator1");
46         userInfo3.setCreatedTime("2019-01-01");
47         userInfo3.setModifiedTime("2019-05-01");
48         userInfo3.setYn(1);
49         userInfos.add(userInfo3);
50     }
51 }

结果在new对象的时候:

1 UserDao userDao = new UserDaoMock();

一直报错:

java.lang.ExceptionInInitializerError
        at com.jd.ads.afa_index.indexes.task.TestUserServiceTask.setUp(TestUserServiceTask.java:37)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
        at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
        at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
        at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:119)

起初以为是init方法出错了,尝试了多种方式,才发下原来是类加载时,当执行到static{}语句块时开始调用userInfos,但userInfos这个list由于是在后面而还未定义和初始化,所以导致了错误。还是因为基础知识不扎实啊!!!

问题解决

将static对象提到最前面,即解决了此问题,简直愚昧的我啊:

 1 public class UserDaoMock extends UserDao {
 2     private static List<UserInfo> userInfos = new ArrayList<UserInfo>();
 3 
 4     @Override
 5     public List<UserInfo> selectUserInfo() {
 6         return getUserInfo();
 7     }
 8 
 9     static {
10         initUserInfo();
11     }
12 
13     public static UserInfo getUserInfo() {
14         return userInfos;
15     }
16 
17     private static void initUserInfo() {
18         UserInfo userInfo1 = new UserInfo();
19         userInfo1.setId(1L);
20         userInfo1.setPin("user1");
21         userInfo1.setUserId(1L);
22         userInfo1.setDataBillingType(1);
23         userInfo1.setErp("operator1");
24         userInfo1.setCreatedTime("2019-01-01");
25         userInfo1.setModifiedTime("2019-05-01");
26         userInfo1.setYn(1);
27         userInfos.add(userInfo1);
28 
29         UserInfo userInfo2 = new UserInfo();
30         userInfo2.setId(2L);
31         userInfo2.setPin("user2");
32         userInfo2.setUserId(2L);
33         userInfo2.setDataBillingType(1);
34         userInfo2.setErp("operator2");
35         userInfo2.setCreatedTime("2019-01-01");
36         userInfo2.setModifiedTime("2019-05-01");
37         userInfo2.setYn(1);
38         userInfos.add(userInfo2);
39 
40         UserInfo userInfo3 = new UserInfo();
41         userInfo3.setId(3L);
42         userInfo3.setPin("user3");
43         userInfo3.setUserId(3L);
44         userInfo3.setDataBillingType(1);
45         userInfo3.setErp("operator1");
46         userInfo3.setCreatedTime("2019-01-01");
47         userInfo3.setModifiedTime("2019-05-01");
48         userInfo3.setYn(1);
49         userInfos.add(userInfo3);
50     }
51 }

注:

类加载时不会为实例变量赋值,对象创建时不会为静态变量赋值。我们调用静态方法时,此类就开始加载,加载的时候不会为实例变量赋值,但是会按顺序给静态变量赋值。

类加载特性 :
      *在虚拟机的生命周期中一个类只被加载一次。
      *类加载的原则:延迟加载,能少加载就少加载,因为虚拟机的空间是有限的。
      *类加载的时机:
      1)第一次创建对象要加载类.
      2)调用静态方法时要加载类,访问静态属性时会加载类。
      3)加载子类时必定会先加载父类。
      4)创建对象引用不加载类.
      5) 子类调用父类的静态方法时
          (1)当子类没有覆盖父类的静态方法时,只加载父类,不加载子类
          (2)当子类有覆盖父类的静态方法时,既加载父类,又加载子类
      6)访问静态常量,如果编译器可以计算出常量的值,则不会加载类,例如:public static final int a =123;否则会加载类,例如:public static final int a = math.PI。

转载请注明:https://www.cnblogs.com/fnlingnzb-learner/p/10615516.html

猜你喜欢

转载自www.cnblogs.com/fnlingnzb-learner/p/10615516.html
今日推荐