




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第十四章 類型信息 RTTI 反射與代理第1頁,共103頁。一、為什么需要RTTI1、 RTTI的概念 RTTI(Run-Time Type Identification) 運行時類型識別第2頁,共103頁。一、為什么需要RTTI2、 多態的復習 從我們熟悉的一個例子開始:第3頁,共103頁。 這是一個典型的類層次結構圖:基類位于頂部, 派生類向下發展 面向對象的基本的目:讓代碼只操縱對基類的 引用,這樣,如果要添加一個新類來擴展程序, 就不會影響到原來的代碼第4頁,共103頁。 abstract class Shape void draw() System.out.println(this
2、+ “.draw()”); / 注意:這里需要的是字符串,但是提供的是 對象,所以需要toString方法轉換 abstract public String toString(); / 定義為抽象,以強制繼承者覆蓋該方法,并 可以防止對Shape的實例化 第5頁,共103頁。 class Circle extends Shape public String toString() return “Circle”; / 派生類僅僅覆蓋了toString方法,下同 class Square extends Shape . class Triangle extends Shape . 第6頁,共103
3、頁。 public class Shapes / 測試程序 public static void main(String args) List shapeList = Arrays.asList (new Circle(),new Square(), new Triangle(); for(Shape shape:shapeList) / 類型轉換 shape.draw(); 第7頁,共103頁。 當把Shape對象放入List數組時向上轉型 但是在向上轉型為Shape的時候,也丟失了Shape 對象的具體類型 對數組而言,它們只是Shape類的對象第8頁,共103頁。 當從數組中取出元素時,
4、這種容器(實際上它將 所有事物都當成Object引用)會自動將結果轉型 回Shape 這是RTTI最基本的使用形式:在運行時, 識別 一個對象的類型 但是RTTI類型轉換卻不徹底: Object被轉型為 Shape,而不是轉型為Circle、Square或Triangle第9頁,共103頁。 接下來就是多態機制的事情了: 多態機制保證:Shape對象實際執行什么樣代碼, 是由引用所指向的具體對象Circle、 Square或者 Triangle決定的,即動態綁定 這正是面向對象編程的基本目標:你希望大部分 的代碼能盡可能少地了解對象的具體類型,而是 只是與對象家族中的一個通用表示打交道第10頁
5、,共103頁。一、為什么需要RTTI3、 問題的提出 值得注意的是:動態綁定是在運行時, 由系統自動完成的第11頁,共103頁。 假如我們的要求比這個還高: 我們不想在運行時,由系統自動進行動態綁定 而是希望在運行的過程中,能夠根據某個引用的 確切類型,使用某種特別的方式來處理它,此時 該怎么辦?第12頁,共103頁。 例如:假設我們允許用戶將某一具體類型的幾何 形狀全部變成某種特殊的顏色,以突出顯示它們 或者,可能要用某個方法來旋轉列出的所有圖形 但想跳過圓形,因為對圓形旋轉沒有意義 充分使用RTTI,可以查詢某個Shape引用所指向 對象的確切類型,然后選擇或者剔除特例第13頁,共103頁
6、。二、Class對象1、 Class對象的概念和作用 要理解RTTI的工作原理,首先必須知道 類型信息在運行時是如何表示的? 利用Class對象來描述和表示第14頁,共103頁。 每個類都有一個Class對象,它描述了與類相關的 信息 利用圖形分析清楚:類和類的Class對象的關系 因為后面還會有新的概念加進來第15頁,共103頁。 每當我們編寫并且編譯了一個新的類, 就會生成 一個與此類相關的Class對象 該Class對象是如何生成的? Java虛擬機利用類加載器生成 該Class對象保存在哪里? 保存在一個同名的.class文件中第16頁,共103頁。二、Class對象2、 類加載器 類
7、加載器的組成 實際上可以包含一條類加載器鏈,但是 只有一個原生類加載器第17頁,共103頁。 原生類加載器加載的是所謂的可信類,包括Java API類,它們通常是從本地盤加載的 通常不需要添加額外的類加載器,但是如果你有 特殊的需求(例如以某種特殊的方法加載類,以 支持Web服務器應用,或者在網絡中下載類), 那么你有一種方式可以掛接額外的類加載器第18頁,共103頁。二、Class對象 類加載器的作用 保證Java是一種動態加載語言 Java程序在它開始運行之前并非被完全 加載,其各個部分是在必需時才加載的第19頁,共103頁。 深入分析: 所有的類都是在對其第一次使用時,動態加載到 Jav
8、a虛擬機中的 例如:當程序創建第一個對類的靜態成員的引用 時,就會加載這個類第20頁,共103頁。 構造器也是類的靜態方法 即使構造器之前并沒有使用static關鍵字 所以,使用new操作符創建類的新對象, 也會被 當作對類的靜態成員的引用,從而導致類的加載第21頁,共103頁。二、Class對象 類加載器的執行過程 詳見P315分析:第22頁,共103頁。1、首先,檢查這個類的Class對象是否已經加載 如果還沒有加載, 那么默認的類加載器,就會 根據類名查找.class文件2、一旦某個類的Class對象被載入內存,它就會被 用來創建這個類的所有對象第23頁,共103頁。3、值得思考的問題:
9、 當一個Class對象被載入內存以后,它所描述的類 是否也立即會被載入內存? 答案:不會,而是盡可能被推遲第24頁,共103頁。二、Class對象 典例分析: P315316 forName ()的調用將會導致:如果所 描述的類沒有加載就加載它第25頁,共103頁。 class Candy / 糖果 static print(“Loading Candy”); class Gum / 口香糖 static print(“Loading Gum”); class Cookie / 餅干 static print(“Loading Cookie”); 第26頁,共103頁。 class publi
10、c class SweetShop / 甜品店 public static void main(String args) print(“inside main”); new Candy(); print(“After creating Candy”); 第27頁,共103頁。 try Class.forName(“Gum”); / 返回一個Class對象的引用 catch(ClassNotFoundException e) print(“Couldnt find Gum”); print(“After Class.forName(“Gum”)”); new Cookie(); print(“A
11、fter creating Cookie”); 第28頁,共103頁。二、Class對象3、 Class類的聲明(Java.lang.Class ) public final class Class extends Object implements Serializable, GenericDeclaration, Type,AnnotatedElement第29頁,共103頁。二、Class對象4、 Class類的構造器 Class類沒有公共構造器 Class對象是在加載類時,由Java虛擬機 通過調用類加載器的defineClass() 方法自動構造的 第30頁,共103頁。二、Clas
12、s對象5、 Class類的方法 Class類共有57個方法 詳細資料請參閱官方文檔第31頁,共103頁。1、public static Class forName(String className) throws ClassNotFoundException 功能:返回描述指定類的Class對象 調用forName(“X”) 將導致名為X的類被初始化 參數className:需要類的完全限定名第32頁,共103頁。2、public String getName() 以String形式返回此Class對象所描述的實體名稱 即:返回此Class對象所描述的實體(類、接口、 數組類、基本類型或者vo
13、id)的完全限定名第33頁,共103頁。3、public String getCanonicalName() 返回規范化名稱(標準名稱/完全限定名)4、public String getSimpleName() 返回簡稱第34頁,共103頁。5、public Class getSuperclass() 返回表示此Class對象所描述的實體(類、接口、 基本類型或void)的超類的Class對象6、public Class getInterfaces() 此Class對象描述的類所包含的接口第35頁,共103頁。7、public T newInstance() throws Instantiat
14、ionException, IllegalAccessException 創建此Class對象所描述類的一個新實例 該方法的作用:如同用一個帶有空參數列表的 new表達式實例化該類第36頁,共103頁。 典例:利用上述解釋分析課本P316317代碼 解釋: Class c=null; / Class對象就和其它對象一樣, 你可以獲取并操作它的引用 obj.getClass() / 來源于Object的方法第37頁,共103頁。第38頁,共103頁。第39頁,共103頁。二、Class對象6、 類字面常量 類字面常量的作用 作用:利用它生成對Class對象的引用 格式:類名.class 優點:比
15、Class.forName更簡單和安全第40頁,共103頁。二、Class對象 類字面常量的本質 類名.class僅僅只創建了對Class對象的 引用, 但并沒有初始化該Class對象 利用圖形分析這個復雜的概念第41頁,共103頁。二、Class對象 類字面常量的重要性質 我們首先分析: 為了使用一個類,需要做的準備工作 實際包含三個步驟:第42頁,共103頁。1、加載 這是由類加載器執行的 該步驟將查找字節碼文件,并且根據這個字節碼 文件創建一個Class對象 如何查找:通過Classpath類路徑第43頁,共103頁。2、鏈接 在鏈接階段將驗證類中的字節碼(安全) 為類的靜態域分配存儲空
16、間(但并未初始化) 如果有必要的話,將解析這個類創建的對其它類 的引用(類的組合)第44頁,共103頁。3、初始化 首先:按照先基類,后子類的原則 然后:按照初始化的第一基本原則和初始化的 第二基本原則進行初始化第45頁,共103頁。 重要性質:使用Class對象的三個階段 創建對Class對象的引用 初始化該Class對象 初始化該Class對象所描述的類 第46頁,共103頁。 重要推論:類的初始化被推遲到: 對靜態方法或者非常數靜態域進行首次引用時才 進行 非常數靜態域是指:static但非final的域第47頁,共103頁。第48頁,共103頁。第49頁,共103頁。 解釋: stat
17、ic final可以分為編譯期常量和非編譯器常量 對編譯期常量(如Initable.StaticFinal)的訪問不 需要先對Initable類進行初始化 而對非編譯期常量(如Initable.StaticFinal2 )的 訪問將導致:強制Initable類進行初始化第50頁,共103頁。 解釋: 如果一個域是static而非final的: 從前面的分析可知:訪問非參數靜態域將導致類 的初始化 例如:對Initable2.StaticNotFinal的訪問第51頁,共103頁。二、Class對象7、 泛化的Class引用 普通的Class引用(復習) 總是用來指向某個Class對象第52頁,
18、共103頁。 Class對象可以用來創建類的實例 Class對象包含了: 可作用于這些實例的所有方法代碼 該類的靜態成員第53頁,共103頁。二、Class對象 限定的Class引用 通過泛型語法來實現第54頁,共103頁。 Java允許你,對Class引用所指向的Class對象的 類型進行限定 也就是對它指向的Class對象所描述的類的類型 進行限定 典例分析:第55頁,共103頁。 public class GenericClassReferences public static void main(String args) Class intClass = int.class; Clas
19、s genericIntClass = int.class; / 聲明一個Class引用:genericIntClass / 并且限定它所指向Class對象是用來描述 Integer類的信息第56頁,共103頁。 genericIntClass = Integer.class; / Integer.class與int.class等價 intClass = double.class; / 普通的類引用可以被重修賦值為指向其它的 class對象 / genericIntClass = double.class; / 泛型類引用只能賦值為指向其聲明的類型 第57頁,共103頁。二、Class對象 帶
20、通配符?的Class引用 Java泛型可以使用通配符?,用來表示 任何事物第58頁,共103頁。 典例: Class intclass = int.class; intclass引用指向這樣的一個Class對象, 它所描述的類暫時不能確定第59頁,共103頁。二、Class對象 帶extends關鍵字的Class引用 詳見P321分析:第60頁,共103頁。 為了創建這樣的一個Class引用,它被限定為某種 類型,或者該類型的任何子類型 需要將通配符與extends關鍵字相結合,創建一個 范圍 典例分析:第61頁,共103頁。 歸納: 向Class引用添加泛型語法的原因僅僅是為了提供 編譯期類
21、型檢查 而使用普通的Class引用,直到運行時你才會發現 它的錯誤,顯得很不方便第62頁,共103頁。三、類型轉換前先做檢查1、 復習與歸納 迄今為止,我們已知的RTTI形式包括 以下兩種:第63頁,共103頁。三、類型轉換前先做檢查 傳統的類型轉換 例如:本章開始范例中的(shape) 由RTTI確保類型轉換的正確性, 如果 執行了一個錯誤的類型轉換,就會拋出 一個ClassCastException異常第64頁,共103頁。 解釋:1、在C+中,經典的類型轉換(Shape)并不使用 RTTI 它只是簡單的告訴編譯器:將這個對象作為新的 類型看待第65頁,共103頁。2、Java要執行類型檢
22、查,保證類型安全的向下轉型 向上轉型肯定是安全的,所以編譯器允許自由地 做向上轉型的賦值操作,而并不需要任何顯式的 轉型操作 向下轉型不安全,除非你擁有額外的信息,這些 信息使你知道該類型是某種特定類型第66頁,共103頁。三、類型轉換前先做檢查 代表對象類型的Class對象 通過查詢Class對象可以獲取運行時所需 的信息第67頁,共103頁。三、類型轉換前先做檢查2、 RTTI在Java中還有第三種形式,就是 關鍵字instanceof 它返回一個布爾值, 告訴我們:對象 是不是某個特定類型的實例第68頁,共103頁。 instanceof的典型使用方式: if(x instanceof
23、Dog) (Dog)x.bark(); 典例分析:P323327第69頁,共103頁。 程序的第一部分:P323325 通過一個類的繼承體系,描述了各種各樣的Pet 以及它們的主人(通過類的層次結構圖分析) 部分代碼如下:第70頁,共103頁。 package typeinfo.pets; public class Person extends Individual public Person(String name) super(name); public class Pet extends Individual public Pet(String name) super(name); pu
24、blic Pet() super(); 第71頁,共103頁。 程序的第二部分:P325 該部分代碼的功能是:定義出一種方法,通過它 可以隨機地創建不同類型的寵物,并且為了方便 起見,還可以創建寵物數組和寵物List 為了使該工具能夠適應多種不同的實現,我們將 其定義為抽象類第72頁,共103頁。 public abstract class PetCreator / 寵物生成器 private Random rand = new Random(47); 創建一個隨機數的種子第73頁,共103頁。 public abstract ListClass types(); types是一個抽象方法,它
25、的返回值為List 而List是由這樣的Class對象所構成的列表,這些 Class對象所描述的類都是Pet的子類第74頁,共103頁。 該方法的主要功能是:利用前面已定義好的List (由描述各個Pet子類的Class對象組成) ,隨機的 創建一個Pet子類的實例public Pet randomPet() / 隨機產生List中的索引 int n = rand.nextInt(types().size(); 第75頁,共103頁。try / 通過Class.newInstance來創建該類的新實例 return types().get(n).newInstance(); catch(Ins
26、tantiationException e) throw new RuntimeException(e); catch(IllegalAccessException e) throw new RuntimeException(e); 第76頁,共103頁。public Pet createArray(int size) / 寵物數組 / 聲明并創建數組result,該數組元素類型為Pet Pet result = new Petsize; for(int i = 0; i size; i+) resulti = randomPet(); / 使用randomPet隨機的創建一個Pet并放入數組
27、 return result;第77頁,共103頁。public ArrayList arrayList(int size)/ 寵物List/ 利用寵物數組求得寵物List ArrayList result = new ArrayList(); 聲明一個指向ArrayList類型的引用result,而該 ArrayList存放的數據元素為Pet第78頁,共103頁。 將普通數組轉換為ArrayList類型的典型方法/ 將createArray返回的數組全部添加到result集合Collections.addAll(result,createArray(size);return result;
28、第79頁,共103頁。 程序的第三部分:P325326 在PetCreator中所聲明的抽象方法types,在其 子類中必須要提供實現 types方法返回類型的限定:使用randomPet() 和其它方法來創建的寵物類型的List第80頁,共103頁。 public class ForNameCreator extends PetCreator / 使用完全限定名的生成器 private static ListClass types = new ArrayListClass(); 聲明指向List類型的一個引用types 該List是由這樣的Class對象構成的列表,這些 Class對象所描述
29、的類都是Pet的子類第81頁,共103頁。private static String typeNames = / 聲明數組typeNames并立即初始化 / 使用包名來引用這些類(參見程序的第一部分) typeinfo.pets.Mutt, typeinfo.pets.Pug, typeinfo.pets.EgyptianMau, typeinfo.pets.Manx, “typeinfo.pets.Cymric”, . ; 第82頁,共103頁。SuppressWarnings(“unchecked”) 為了產生具有實際類型的Class對象的List,必須 使用轉型,而這將會產生編譯器警告
30、SuppressWarnings注釋作用:抑制未檢查異常 該注釋不能直接置于靜態初始化語句之上,所以 此程序采用一個變通的辦法:將loader ()方法 單獨定義,然后再置于一個靜態初始化語句中第83頁,共103頁。private static void loader() try for(String name : typeNames) / 強制轉換并添加到types所指向的List types.add( (Class) Class.forName(name); catch(ClassNotFoundException e) throw new RuntimeException(e); 第84
31、頁,共103頁。 / 靜態初始化語句 static loader(); / 在程序的最后,提供types方法的具體實現 public ListClass types() return types; 第85頁,共103頁。 程序的第四部分:P326327 為了對Pet進行計數,我們需要一個能夠跟蹤各種 不同類型的Pet的數量的工具 Map是此需求的首選,其中鍵是Pet類型名,而值 是保存Pet數量的Integer第86頁,共103頁。 public class PetCount / 測試程序,對寵物進行計數 static class PetCounter extends HashMap 嵌套類(
32、靜態內部類) PetCounter:寵物計數器第87頁,共103頁。 public void count(String type) / 調用Map接口的get方法,返回鍵對應的值 Integer quantity = get(type); if(quantity = null) put(type,1); else put(type,quantity + 1); / 內部類定義結束第88頁,共103頁。public static void countPets(PetCreator creator) PetCounter counter= new PetCounter(); for(Pet pet
33、 : creator.createArray(20) 取出容器中的每一個Pet并作進一步處理 print(pet.getClass().getSimpleName() + ); / 輸出Pet的名字第89頁,共103頁。 / 使用一串繁瑣的instanceof對該數組中的每個Pet 進行測試和計數 / 注意:pet是動態的,即運行時才能決定 if(pet instanceof Pet) counter.count(“Pet”); if(pet instanceof Dog) counter.count(“Dog”); / 輸出統計結果 print(counter); 第90頁,共103頁。 歸
34、納:RTTI的三種使用形式 傳統的類型轉換(發生在編譯時) Class對象(通過查詢Class對象可以獲取運行時 所需的信息) 關鍵字instanceof(發生在運行時)第91頁,共103頁。 public static void main(String args) countPets(new ForNameCreator(); / 使用PetCreator來隨機地向數組中填充Pet / 這是一個比較龐大而復雜的程序,而如果想要理解 該程序,就需要深入分析它的各個組成部分第92頁,共103頁。三、類型轉換前先做檢查3、 使用類字面常量 如果我們采用類字面常量來重新實現 PetCreator,那么,改寫后的結果在 許多方面都會顯得更加清晰 對程序的第三部分進行優化第93頁,共103頁。 package typeinfo.pets;import java.util.*;public class LiteralPetCreator extends PetCreator/ 使用類字面常量的生成器 / Literal就是字面上的意思 /
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年瑜伽教練資格證考試題庫:初級理論模擬試題
- 2025年初中地理模擬考試卷地理國情認知地理信息工程案例分析試題
- 2025年小學語文畢業升學考試全真模擬卷(語文綜合素養測評)-閱讀理解能力提升策略篇
- 2025年機電工程管理與實務一建考試法規題庫詳解與實戰題卷
- 2025年專升本藝術概論考試模擬試題(藝術鑒賞提升與藝術素養)
- 2025農產品運輸合同
- 2025年小學語文畢業升學模擬試卷(口語表達與溝通技巧專項試題)
- 2025年江蘇省南京市秦淮區重點中學三模生物試題試卷含解析
- 遼寧生態工程職業學院《國際貿易與實務》2023-2024學年第二學期期末試卷
- 武漢交通職業學院《局部解剖學》2023-2024學年第二學期期末試卷
- 汞中毒學習課件
- 國際商事調解的流程和程序
- 工廠領手套管理制度
- JGJT220-2010 抹灰砂漿技術規程
- 【基于PLC的搬運機器人系統設計4700字(論文)】
- 園林綠化公司管理規章制度
- 2023年云南省昆明市官渡區小升初數學試卷
- 山東船廠船臺碼頭施工組織設計
- 2022年廣州白云廣附實驗學校入學數學真卷(三)
- XX家具商場顧客接待流程制度
- 猜謎語(小學低年級)
評論
0/150
提交評論