作者:Flyingis
ClassCastException是JVM在檢測到兩個(gè)類型間轉(zhuǎn)換不兼容時(shí)引發(fā)的運(yùn)行時(shí)異常。此類錯(cuò)誤通常會(huì)終止用戶請求。在執(zhí)行任何子系統(tǒng)的應(yīng)用程序代碼時(shí)都有可能發(fā)生ClassCastException異常。通過轉(zhuǎn)換,可以指示Java編譯器將給定類型的變量作為另一種變量來處理。對基礎(chǔ)類型和用戶定義類型都可以轉(zhuǎn)換。Java語言規(guī)范定義了允許的轉(zhuǎn)換,其中大多數(shù)可在編譯時(shí)進(jìn)行驗(yàn)證。不過,某些轉(zhuǎn)換還需要運(yùn)行時(shí)驗(yàn)證。如果在此運(yùn)行時(shí)驗(yàn)證過程中檢測到不兼容,JVM就會(huì)引發(fā)ClassCastException異常。例如:
Fruit f;
Apple a = (Apple)f;
當(dāng)出現(xiàn)下列情況時(shí),就會(huì)引發(fā)ClassCastException異常:
1. Fruit和Apple類不兼容。當(dāng)應(yīng)用程序代碼嘗試將某一對象轉(zhuǎn)換為某一子類時(shí),如果該對象并非該子類的實(shí)例,JVM就會(huì)拋出ClassCastException異常。
2. Fruit和Apple類兼容,但加載時(shí)使用了不同的ClassLoader。這是這種異常發(fā)生最常見的原因。在這里,需要了解一下什么是ClassLoader?
ClassLoader
ClassLoader是允許JVM查找和加載類的一種Java類。JVM有內(nèi)置的ClassLoader。不過,應(yīng)用程序可以定義自定義的ClassLoader。應(yīng)用程序定義新的ClassLoader通常出于以下兩種原因:
1. 自定義和擴(kuò)展JVM加載類的方式。例如,增加對新的類庫(網(wǎng)絡(luò)、加密文件等)的支持。
2. 劃分JVM名稱空間,避免名稱沖突。例如,可以利用劃分技術(shù)同時(shí)運(yùn)行同一應(yīng)用程序的多個(gè)版本(基于空間的劃分)。此項(xiàng)技術(shù)在應(yīng)用服務(wù)器(如WebLogic Server)內(nèi)的另一個(gè)重要用途是啟用應(yīng)用程序熱重新部署,即在不重新啟動(dòng)JVM的情況下啟動(dòng)應(yīng)用程序的新版本(基于時(shí)間的劃分)。
ClassLoader按層級(jí)方式進(jìn)行組織。除系統(tǒng)BootClassLoader外,其它ClassLoader都必須有父ClassLoader。
在理解類加載的時(shí)候,需要注意以下幾點(diǎn):
1. 永遠(yuǎn)無法在同一ClassLoader中重新加載類。“熱重新部署”需要使用新的ClassLoader。每個(gè)類對其ClassLoader的引用都是不可變的:this.getClass().getClassLoader()。
2. 在加載類之前,ClassLoader始終會(huì)先詢問其父ClassLoader(委托模型)。這意味著將永遠(yuǎn)無法重寫“核心”類。
3. 同級(jí)ClassLoader間互不了解。
4. 由不同ClassLoader加載的同一類文件也會(huì)被視為不同的類,即便每個(gè)字節(jié)都完全相同。這是ClassCastException的一個(gè)典型原因。
5. 可以使用Thread.setContextClassLoader(a)將ClassLoader連接到線程的上下文。
基于以上的基本原理,可以加深大家對ClassCastException的理解,和在碰到問題時(shí)提供一種解決問題的思路。
參考文獻(xiàn):
dev2dev專刊 2005年 第二期
j2sdk-1_5_0-doc