ClassCastException深入分析
作者:Flyingis
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的理解,和在碰到問題時提供一種解決問題的思路。
參考文獻:
dev2dev專刊 2005年 第二期
posted on 2005-12-18 18:57 Flyingis 閱讀(28702) 評論(4) 編輯 收藏 所屬分類: JavaSE