java.lang.ExceptionInInitializerError


一.錯誤,原因


java.lang.ExceptionInInitializerError


二.原因

引起java.lang.ExceptionInInitializerError 錯誤的原因是:在類的初始化時,出錯。也就是說,在加載類時,執行static的屬性、方法塊時,出錯了。

比如

 


   
   
  
  
          
  1. <span style= "font-family:Times New Roman;"> public class AA{
  2. private static AA aa = new AA();
  3. private AA(){ //構造方法
  4. init();
  5. }
  6. public void init(){
  7. .... }
  8. }</span>

初始化類時,會調用init方法,如果init方法出錯,這類初始化失敗,就會報java.lang.ExceptionInInitializerError錯誤。

同理,在執行


   
   
  
  
          
  1. static{
  2.   ...
  3. }


方法塊時,也可能報這個錯。


三.原因分析


      當在靜態初始化塊中出現了異常的時候,JVM會拋出 java.lang.ExceptionInInitializerError異常。

java中的靜態變量,是在類加載的時候進行初始化的。如果在這個靜態變量初始化的過程中出現了異常,就會拋出 java.lang.ExceptionInInitializerError異常。


      任何異常都可能會引發這種情況,比如說,java.lang.ArrayIndexOutOfBound或者java.lang.NullPointerException。我們通常會被這個錯誤弄暈,覺得自己並沒有定義任何的靜態初始化塊,為什么還會拋出ExceptionInInitializerError異常;事實上,Java默認會將靜態變量的初始化放在一個默認的靜態初始化塊中,然后按它們在源文件中聲明的順序來進行初始化。比如說變量ABC聲明在第一行,在第二行中使用到了,而在第三行的時候才初始化,那么第二行的代碼會拋出一個NullPointerException異常,這個異常會被封裝到一個ExceptionInInitializerError異常中,如果這段代碼在主線程中執行了,你會看到控制台或者日志文件中出現這樣的錯誤信息: "Exception in thread "main"java.lang.ExceptionInInitializerError"。


       在一個擁有大量日志文件的大型系統中,這樣的錯誤很容易被忽略,而程序員會得到一個java.lang.NoClassDefFoundError異常。不幸的是只有其他代碼使用到了這個類的時候才會出現這個錯誤,因為ExceptionInInitializerError導致了這個類無法加載。由於類加載失敗了,因此JVM會拋出NoClassDefFoundError。我們會去檢查類路徑,PATH,以及java.library.path看是不是缺少了這個類,卻又發現不了任何問題。如果在分析NoClassDefFoundError的原因,最好看下你的日志文件中有沒有ExceptionInInitializerError,然后再考慮要不要檢查classpath。


Exception in thread"main" java.lang.ExceptionInInitializerError的原因 :


       正如別的錯誤或者異常一樣,當看見這行信息,你知道這是出現ExceptionInInitializerError異常了,這個異常是由於類加載過程中靜態塊初始化過程失敗所導致的。由於它出現在負責啟動程序的主線程中,因此你最好從主類中開始分析,這里說的主類是指你在命令行參數中指定的那個,或者說是你聲明了public static void main(String args[])方法的那個類。如果你仔細地看一下完整的堆棧跟蹤信息,會發現引發ExceptionInInitializerError的類。ExceptionInInitializerError是LinkageError的子類,這意味着這個異常會導致你的類無法加載到JVM的內存中。現在我們來看一下這個示例程序。

 


   
   
  
  
          
  1. <span style= "font-family:Times New Roman;">importjava.util.ArrayList;
  2. importjava.util.List;
  3. /**
  4. * Java Program to understand and solveExceptionInitializerError, which comes
  5. * When static initializer blocks throwsunchecked exception during class loading
  6. * and initialization.
  7. *
  8. * @author Javin Paul
  9. */
  10. public classStaticInitializerDemo{
  11. private static final List<CreditCard>cards = new ArrayList<CreditCard>();
  12. private static CreditCard prefferdCard =cards.get( 0); // 1st card is default
  13. public static boolean isVisa = "VISA".equalsIgnoreCase(prefferdCard.getNetwork());
  14. public static void main(String args[]) {
  15. makePayment(prefferdCard);
  16. }
  17. public static void makePayment(CreditCard cc){
  18. if (isVisa) {
  19. //offer 5% discount
  20. }
  21. // deduct payment
  22. }
  23. }
  24. class CreditCard{
  25. private long card_number; //16 digit cardnumber
  26. private int cvv; // 3 digit cvv number
  27. private int expiryMonth;
  28. private int expiryYear;
  29. private String bank;
  30. private String network;
  31. public CreditCard(long card_number, int cvv,int expiryMonth, int expiryYear, String bank, String network) {
  32. super();
  33. this.card_number = card_number;
  34. this.cvv = cvv;
  35. this.expiryMonth = expiryMonth;
  36. this.expiryYear = expiryYear;
  37. this.bank = bank;
  38. this.network = network;
  39. }
  40. /**
  41. * @return the card_number
  42. */
  43. public final long getCard_number() {
  44. return card_number;
  45. }
  46. /**
  47. * @return the cvv
  48. */
  49. public final int getCvv() {
  50. return cvv;
  51. }
  52. /**
  53. * @return the expiryMonth
  54. */
  55. public final int getExpiryMonth() {
  56. return expiryMonth;
  57. }
  58. /**
  59. * @return the expiryYear
  60. */
  61. public final int getExpiryYear() {
  62. return expiryYear;
  63. }
  64. /**
  65. * @return the bank
  66. */
  67. public final String getBank() {
  68. return bank;
  69. }
  70. /**
  71. * @return the network
  72. */
  73. public final String getNetwork() {
  74. return network;
  75. }
  76. }
  77. </span>


輸出:


   
   
  
  
          
  1. <span style= "font-family:Times New Roman;">Exception inthread "main" java.lang.ExceptionInInitializerError
  2. Caused by:java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
  3. at java.util.ArrayList.rangeCheck(UnknownSource)
  4. at java.util.ArrayList.get(Unknown Source)
  5. atStaticInitializerDemo.<clinit>(StaticInitializerDemo.java: 15)</span>


看一下棧跟蹤信息,知道真正的異常是java.lang.IndexOutOfBoundsException,它在StaticInitiazerDemo的第二行被拋出來了。這是由於調用了ArrayList的get()方法並傳入了位置0,而這個ArrayList的大小也是0(Index: 0, Size: 0)。看到這條信息后你知道當我們想從列表中取出第一張CreditCard時,這個列表是空的。


四.解決辦法


解決注意事項:

如何解決Exception inthread "main" java.lang.ExceptionInInitializerError

需要記住以下幾點:

1. "Exception in thread"main" java.lang.ExceptionInInitializerError"意味着異常出現在主線程,並且是LinkageError的一個子類java.lang.ExceptionInInitializerError,這是JVM類加載失敗時才拋出的,原因是靜態初始化代碼中出現了諸如IndexOutOfBoundsException或者NullPointerException這樣的RuntimeException。


2. 記住JVM會將所有的靜態變量的初始化按它們在源文件中的出現順序放到一個靜態初始化塊中。因此,不要覺得沒有看到靜態初始塊就認為不會出現這個異常。事實上,需要確保靜態變量的正確順序,比如說,如果一個變量初始化的時候用到了另一個變量,你得確保這個變量在前面已經初始化過了。


3. 如果別的代碼想要使用這個類,則會拋出ExceptionInInitializerError異常,而它又會導致ClassNotFoundException或者NoClassDefFoundError。為什么?因為這個類加載失敗了,並沒有加載到JVM的內存中。因此如果你在解決類不存在之類的異常時,先看看日志文件中有沒有這個異常。


4. 記住靜態初始化代碼塊會拋出RuntimeException而不是已檢查異常,而后者需要有對應的catch塊來進行處理。


需要謹記的是這個異常的一個副作用是NoClassDefFoundError,而Java程序拋出這個異常的位置可能會離java.lang.ExceptionInInitializerError很遠,這取決於客戶端代碼何時引用到這個類。因此,在查看類路徑解決NoClassDefFoundError異常之前,最好先看看日志有沒有出現ExceptionInInitializerError。


五.參考網址


1.   http://www.2cto.com/kf/201309/241190.html

2.   http://www.tuicool.com/articles/IVBVn2

原文地址:https://blog.csdn.net/li1500742101/article/details/46049973


免責聲明!

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



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