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