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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM