ClassCastException深入分析

來源:互聯網
上載者:User

標籤:style   blog   http   color   java   使用   os   io   

ClassCastException是JVM在檢測到兩個類型間轉換不相容時引發的運行時異常。此類錯誤通常會終止使用者請求。在執行任何子系統的應用程式代碼時都有可能發生ClassCastException異常。通過轉換,可以指示Java編譯器將給定類型的變數作為另一種變數來處理。對基礎類型和使用者定義型別都可以轉換。Java語言規範定義了允許的轉換,其中大多數可在編譯時間進行驗證。不過,某些轉換還需要運行時驗證。如果在此運行時驗證過程中檢測到不相容,JVM就會引發ClassCastException異常。例如:

Fruit f;

Apple a = (Apple)f;

當出現下列情況時,就會引發ClassCastException異常:

1.        Fruit和Apple類不相容。當應用程式代碼嘗試將某一對象轉換為某一子類時,如果該對象並非該子類的執行個體,JVM就會拋出ClassCastException異常。

2.        Fruit和Apple類相容,但載入時使用了不同的ClassLoader。這是這種異常發生最常見的原因。在這裡,需要瞭解一下什麼是ClassLoader?


ClassLoader

         ClassLoader是允許JVM尋找和載入類的一種Java類。JVM有內建的ClassLoader。不過,應用程式可以定義自訂的ClassLoader。應用程式定義新的ClassLoader通常出於以下兩種原因:

1.        自訂和擴充JVM載入類的方式。例如,增加對新的類庫(網路、加密檔案等)的支援。

2.        劃分JVM名稱空間,避免名稱衝突。例如,可以利用劃分技術同時運行同一應用程式的多個版本(基於空間的劃分)。此項技術在應用伺服器(如WebLogic Server)內的另一個重要用途是啟用應用程式熱重新部署,即在不重新啟動JVM的情況下啟動應用程式的新版本(基於時間的劃分)。

ClassLoader按層級方式進行組織。除系統BootClassLoader外,其它ClassLoader都必須有父ClassLoader。

在理解類載入的時候,需要注意以下幾點:

1.        永遠無法在同一ClassLoader中重新載入類。“熱重新部署”需要使用新的ClassLoader。每個類對其ClassLoader的引用都是不可變的:this.getClass().getClassLoader()。

2.        在載入類之前,ClassLoader始終會先詢問其父ClassLoader(委託模型)。這意味著將永遠無法重寫“核心”類。

3.        同級ClassLoader間互不瞭解。

4.        由不同ClassLoader載入的同一類檔案也會被視為不同的類,即便每個位元組都完全相同。這是ClassCastException的一個典型原因。

5.        可以使用Thread.setContextClassLoader(a)將ClassLoader串連到線程的上下文。

基於以上的基本原理,可以加深大家對ClassCastException的理解,和在碰到問題時提供一種解決問題的思路。



ClassCastException and ClassLoader Puzzle 2/21/2013   PIERRE-HUGUES CHARBONNEAU   2 COMMENTS The following question and puzzle will test your knowledge on Java class loaders and more precisely on one of the Java language specifications. It will also help you better troubleshoot problems such asjava.lang.NoClassDefFoundError.
I highly suggest that you do not look at the explanation and solution until you review the code and come up with your own explanation.
You can download the Java program source code and binaries (compiled with JDK 1.7) here. In order to run the program, simply use the following command:
<JDK 1.7 HOME>\bin\java -classpath MainProgram.jar org.ph.javaee.training9.ChildFirstCLPuzzle
** Make sure that you also download the 3 JAR files below before you run the program.
  • MainProgram.jar contains the main program along with super classProgrammingLanguage.
  • ProgrammingLanguage.jar contains the super class ProgrammingLanguage.
  • JavaLanguage.jar contains the implementation class JavaLanguage, which extendsProgrammingLanguage.

Question (puzzle)
Review closely the program source and packaging along with the diagram below reflecting the class loader delegation model used for this program.


Why can’t we cast (ChildFirstCLPuzzle.java @line 53) the Object javaLanguageInstance of type JavaLanguage , into  ProgrammingLanguage ?
...............................                    // Finally, cast the object instance into ProgrammingLanguage /** Question: why is the following code failing with ClassCastException given the fact JavaLanguage is indeed a ProgrammingLanguage?? **/ ProgrammingLanguage programmingLanguage = (ProgrammingLanguage)javaLanguageInstance;
............................... 

Propose a solution to allow the above cast to succeed without changing the original source code. Hint: look again at the class loader delegation model, packaging and diagram.
Answer & solution
The Java program is attempting to demonstrate a Java language specification rule related to class loaders: two classes loaded by different class loaders are considered to be distinct and hence incompatible.
If you review closely the program source, packaging and diagram, you will realize the following facts:
  • Our main program is loaded to the parent class loader e.g. $AppClassLoader.
  • The super class ProgrammingLanguage is also loaded to the parent class loader since it is referenced by our main program at line 53.
  • The implementation class JavaLanguage is loaded to our child class loader e.g. ChildFirstClassLoader which is following a “child first” delegation model.
  • Finally, the super class ProgrammingLanguage is also loaded to our child class loader.

The key point to understand is that the super class is loaded by 2 different class loaders. As per Java language specification, two classes loaded by different class loaders are considered to bedistinct and hence incompatible. This means that ProgrammingLanguage loaded from the “child firs” class loader is different and not compatible with ProgrammingLanguage loaded from the parent classloader. This is why the cast attempted at line 53 failed with the error below:
ChildFirstCLPuzzle execution failed with ERROR: java.lang.ClassCastException: org.ph.javaee.training9.JavaLanguage cannot be cast to org.ph.javaee.training9.ProgrammingLanguage
Now how can we fix this problem without actually changing the source code? Well please keep in mind that we are using a “child first” delegation model here. This is why we end up with 2 versions of the same ProgrammingLanguage class. The solution can be visualized as per below.

In order to fix this problem, we can simply ensure that we have only one version of ProgrammingLanguage loaded. Since our main program is referencing ProgrammingLanguage directly, the solution is to remove the ProgrammingLanguage.jar file from the child class loader. This will force the child class loader to look for the class from the  parent  class loader, problem solved! In order to test the solution, simply remove the ProgrammingLanguage.jar from your testing folder and re-run the program.
I hope you appreciated this puzzle related to “child first” class loader delegation model and class loader rules. This understanding is especially important when you are dealing with complex Java EE deployments involving many class loaders, exposing you to this type of problems at runtime.
Please do not hesitate to post any comment or question on this puzzle.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.