java踩坑記-static final 順序


這個坑是關於單例模式 getInstance時候的static final順序,而且問提十分隱蔽。在實際的項目,在QA環境下由於判斷條件為false,無法發現此問題;而到生產上之后,判斷條件為true,拋了空指針異常。

情況1:判斷條件為false
 1 package com.paypal.dinyu;
 2 
 3 /**
 4  * Created by dinyu on 26/07/2017.
 5  */
 6 public class Bpp {
 7     private static final Bpp INSTANCE = new Bpp();
 8     private static final Cpp CPP = Cpp.getInstance();
 9 
10     private Bpp() {
11         init();
12     }
13 
14     public static Bpp getInstance() {
15         return INSTANCE;
16     }
17 
18     private void init() {
19         if (false) {
20             System.out.println("CPP.toString: " + CPP.toString());
21         }
22     }
23 
24     public static void main(String[] args) {
25         Bpp.getInstance();
26     }
27 }
28 
29 class Cpp {
30     private static final Cpp INSTANCE = new Cpp();
31 
32     private Cpp() {
33 
34     }
35 
36     public static Cpp getInstance() {
37         return INSTANCE;
38     }
39 }

Output:

Process finished with exit code 0

情況2:判斷條件為true
 1 package com.paypal.dinyu;
 2 
 3 /**
 4  * Created by dinyu on 26/07/2017.
 5  */
 6 public class Bpp {
 7     private static final Bpp INSTANCE = new Bpp();
 8     private static final Cpp CPP = Cpp.getInstance();
 9 
10     private Bpp() {
11         init();
12     }
13 
14     public static Bpp getInstance() {
15         return INSTANCE;
16     }
17 
18     private void init() {
19         if (true) {
20             System.out.println("CPP.toString: " + CPP.toString());
21         }
22     }
23 
24     public static void main(String[] args) {
25         Bpp.getInstance();
26     }
27 }
28 
29 class Cpp {
30     private static final Cpp INSTANCE = new Cpp();
31 
32     private Cpp() {
33 
34     }
35 
36     public static Cpp getInstance() {
37         return INSTANCE;
38     }
39 }

Output:

Exception in thread "main" java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:123)
Caused by: java.lang.NullPointerException
at com.paypal.dinyu.Bpp.init(Bpp.java:20)
at com.paypal.dinyu.Bpp.<init>(Bpp.java:11)
at com.paypal.dinyu.Bpp.<clinit>(Bpp.java:7)
... 3 more

Process finished with exit code 1

出現以上情況的原因,是因為在Bpp.getInstace()時,在Bpp中new了自己,而在new的過程中又需要用到Cpp的Instance,但是Cpp的static塊在Bpp的new之后,也就是在Bpp new自己的時候,Cpp還是null,所以會拋出NPE;但是在情況1中,由於判斷條件為false,並沒有跑到使用CPP的地方,所以不會拋出NPE。

正確做法:把new Bpp放到所有static塊的最后

 1 package com.paypal.dinyu;
 2 
 3 /**
 4  * Created by dinyu on 26/07/2017.
 5  */
 6 public class Bpp {
 7     private static final Cpp CPP = Cpp.getInstance();
 8     private static final Bpp INSTANCE = new Bpp();
 9 
10     private Bpp() {
11         init();
12     }
13 
14     public static Bpp getInstance() {
15         return INSTANCE;
16     }
17 
18     private void init() {
19         if (true) {
20             System.out.println("CPP.toString: " + CPP.toString());
21         }
22     }
23 
24     public static void main(String[] args) {
25         Bpp.getInstance();
26     }
27 }
28 
29 class Cpp {
30     private static final Cpp INSTANCE = new Cpp();
31 
32     private Cpp() {
33 
34     }
35 
36     public static Cpp getInstance() {
37         return INSTANCE;
38     }
39 }

輸出結果:

CPP.toString: com.paypal.dinyu.Cpp@63947c6b

Process finished with exit code 0

 


免責聲明!

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



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