有時(shí)候我們說某個(gè)語言具有很強(qiáng)的動(dòng)態(tài)性,有時(shí)候我們會(huì)區(qū)分動(dòng)態(tài)和靜態(tài)的不同技術(shù)與作法。我們朗朗上口動(dòng)態(tài)綁定( dynamic binding )、動(dòng)態(tài)鏈接( dynamic linking )、動(dòng)態(tài)加載( dynamic loading )等。然而 “ 動(dòng)態(tài) ” 一詞其實(shí)沒有絕對而普遍適用的嚴(yán)格定義,有時(shí)候甚至像對象導(dǎo)向當(dāng)初被導(dǎo)入編程領(lǐng)域一樣,一人一把號(hào),各吹各的調(diào)。
?
一般而言,開發(fā)者社群說到動(dòng)態(tài)語言,大致認(rèn)同的一個(gè)定義是: “ 程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動(dòng)態(tài)語言 ” 。從這個(gè)觀點(diǎn)看, Perl , Python , Ruby 是動(dòng)態(tài)語言, C++ , Java , C# 不是動(dòng)態(tài)語言。
?
盡管在這樣的定義與分類下 Java 不是動(dòng)態(tài)語言,它卻有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制: Reflection 。這個(gè)字的意思是 “ 反射、映象、倒影 ” ,用在 Java 身上指的是我們可以于運(yùn)行時(shí)加載、探知、使用編譯期間完全未知的 classes 。換句話說, Java 程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱的 class ,獲悉其完整構(gòu)造(但不包括 methods 定義),并生成其對象實(shí)體、或?qū)ζ? fields 設(shè)值、或喚起其 methods 1 。這種 “ 看透 class ” 的能力( the ability of the program to examine itself )被稱為 introspection ( 內(nèi)省、內(nèi)觀、反省 )。 Reflection 和 introspection 是常被并提的兩個(gè)術(shù)語。
?
Java 如何能夠做出上述的動(dòng)態(tài)特性呢?這是一個(gè)深遠(yuǎn)話題,本文對此只簡單介紹一些概念。整個(gè)篇幅最主要還是介紹 Reflection APIs ,也就是讓讀者知道如何探索 class 的結(jié)構(gòu)、如何對某個(gè) “ 運(yùn)行時(shí)才獲知名稱的 class ” 生成一份實(shí)體、為其 fields 設(shè)值、調(diào)用其 methods 。本文將談到 java.lang.Class ,以及 java.lang.reflect 中的 Method 、 Field 、 Constructor 等等 classes 。
?
“ Class ” class
眾所周知 Java 有個(gè) Object class ,是所有 Java classes 的繼承根源,其內(nèi)聲明了數(shù)個(gè)應(yīng)該在所有 Java class 中被改寫的 methods : hashCode() 、 equals() 、 clone() 、 toString() 、 getClass() 等。其中 getClass() 返回一個(gè) Class object 。
?
Class class 十分特殊。它和一般 classes 一樣繼承自 Object ,其實(shí)體用以表達(dá) Java 程序運(yùn)行時(shí)的 classes 和 interfaces ,也用來表達(dá) enum 、 array 、 primitive Java types ( boolean, byte, char, short, int, long, float, double )以及關(guān)鍵詞 void 。當(dāng)一個(gè) class 被加載,或當(dāng)加載器( class loader )的 defineClass() 被 JVM 調(diào)用, JVM 便自動(dòng)產(chǎn)生一個(gè) Class object 。如果您想借由 “ 修改 Java 標(biāo)準(zhǔn)庫源碼 ” 來觀察 Class object 的實(shí)際生成時(shí)機(jī)(例如在 Class 的 constructor 內(nèi)添加一個(gè) println() ),不能夠!因?yàn)? Class 并沒有 public constructor (見 圖 1 )。本文最后我會(huì)撥一小塊篇幅順帶談?wù)? Java 標(biāo)準(zhǔn)庫源碼的改動(dòng)辦法。
?
Class 是 Reflection 故事起源。針對任何您想探勘的 class ,唯有先為它產(chǎn)生一個(gè) Class object ,接下來才能經(jīng)由后者喚起為數(shù)十多個(gè)的 Reflection APIs 。這些 APIs 將在稍后的探險(xiǎn)活動(dòng)中一一亮相。
?
#001 public final
#002 class Class <T> implements java.io.Serializable,
#003 java.lang.reflect.GenericDeclaration,
#004 java.lang.reflect.Type,
#005 java.lang.reflect.AnnotatedElement {
#006 ?? private Class() {}
#007 ?? public String toString () {
#008 ?????? return ( isInterface() ? "interface " :
#009 ?????? (isPrimitive() ? "" : "class "))
#010 ?? + getName();
#011 }
...
圖 1 : Class class 片段。注意它的 private empty ctor ,意指不允許任何人經(jīng)由編程方式產(chǎn)生 Class object 。是的,其 object 只能由 JVM 產(chǎn)生。
?
“ Class ” object 的取得途徑
Java 允許我們從多種管道為一個(gè) class 生成對應(yīng)的 Class object 。 圖 2 是一份整理。
Class object 誕生管道 |
示例 |
運(yùn)用 getClass() 注:每個(gè) class 都有此函數(shù) |
String str = "abc"; Class c1 = str.getClass(); |
運(yùn)用 Class.getSuperclass() 2 |
Button b = new Button(); Class c1 = b.getClass(); Class c2 = c1.getSuperclass(); |
運(yùn)用 static method Class.forName() (最常被使用) |
Class c1 = Class.forName ("java.lang.String"); Class c2 = Class.forName ("java.awt.Button"); Class c3 = Class.forName ("java.util.LinkedList$Entry"); Class c4 = Class.forName ("I"); Class c5 = Class.forName ("[I"); |
運(yùn)用 .class 語法 |
Class c1 = String.class; Class c2 = java.awt.Button.class; Class c3 = Main.InnerClass.class; Class c4 = int.class; Class c5 = int[].class; |
運(yùn)用 primitive wrapper classes 的 TYPE 語法 ? |
Class c1 = Boolean.TYPE; Class c2 = Byte.TYPE; Class c3 = Character.TYPE; Class c4 = Short.TYPE; Class c5 = Integer.TYPE; Class c6 = Long.TYPE; Class c7 = Float.TYPE; Class c8 = Double.TYPE; Class c9 = Void.TYPE; |
圖 2 : Java 允許多種管道生成 Class object 。
?
Java classes 組成分析
首先容我以 圖 3 的 java.util.LinkedList 為例,將 Java class 的定義大卸八塊,每一塊分別對應(yīng) 圖 4 所示的 Reflection API 。 圖 5 則是“獲得 class 各區(qū)塊信息”的程序示例及執(zhí)行結(jié)果,它們都取自本文示例程序的對應(yīng)片段。
?
package java.util; ???????????????? ??? //(1)
import java.lang.*; ??????????????? ??? //(2)
public class LinkedList < E > ???????? ??? //(3)(4)(5)
extends AbstractSequentialList <E> ????? //(6)
implements List <E>, Queue <E>,
Cloneable, java.io.Serializable ??????? //(7)
{
private static class Entry <E> { … }//(8)
public LinkedList () { … } ????????? //(9)
public LinkedList (Collection<? extends E> c) { … }
public E getFirst () { … } ????????? //(10)
public E getLast () { … }
private transient Entry<E> header = … ; ? //(11)
private transient int size = 0;
}
圖 3 :將一個(gè) Java class 大卸八塊,每塊相應(yīng)于一個(gè)或一組 Reflection APIs (圖 4 )。
?
Java classes 各成份所對應(yīng)的 Reflection APIs
圖 3 的各個(gè) Java class 成份,分別對應(yīng)于 圖 4 的 Reflection API ,其中出現(xiàn)的 Package 、 Method 、 Constructor 、 Field 等等 classes ,都定義于 java.lang.reflect 。
Java class 內(nèi)部模塊(參見 圖 3 ) |
Java class 內(nèi)部模塊說明 |
相應(yīng)之 Reflection API ,多半為 Class methods 。 |
返回值類型 (return type) |
(1) package |
class 隸屬哪個(gè) package |
getPackage() |
Package |
(2) import |
class 導(dǎo)入哪些 classes |
border-style: none solid solid none; border-color: rgb(236, 233, 216) windowtext windowtext rgb(236, 233, 21
發(fā)表評論 |
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

評論