欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
反射,java的靈魂
反射使您的程序代碼能夠接入裝載到JVM中的類(lèi)的內部信息,允許您編寫(xiě)與執行時(shí),而不是源代碼中選定的類(lèi)協(xié)作的代碼。這使反射成為構建靈活的應用的主要工具。但需注意的是 -- 如果使用不當,反射的成本很高。在Java平臺系列的第2部分中,軟件顧問(wèn)Dennis Sosnoski介紹了如何使用反射,以及某些相關(guān)的成本。您還將找到Java Reflection API如何使您能夠在運行時(shí)關(guān)聯(lián)對象。

在“Java編程的動(dòng)態(tài)性,第1部分,”我為您介紹了Java編程類(lèi)和類(lèi)裝入。該篇文章介紹了一些Java二進(jìn)制類(lèi)格式的相關(guān)信息。這個(gè)月我將闡述使用Java反射API來(lái)在運行時(shí)接入和使用一些相同信息的基礎。為了使已經(jīng)熟知反射基礎的開(kāi)發(fā)人員關(guān)注本文,我將在文章中包括反射性能如何與直接接入相比較。

使用反射不同于常規的Java編程,其中它與元數據--描述其它數據的數據協(xié)作。Java語(yǔ)言反射接入的特殊類(lèi)型的原數據是JVM中類(lèi)和對象的描述。反射使您能夠運行時(shí)接入廣泛的類(lèi)信息。它甚至使您能夠讀寫(xiě)字段,調用運行時(shí)選擇的類(lèi)的方法。

反射是一種強大的工具。它使您能夠創(chuàng )建靈活的代碼,這些代碼可以在運行時(shí)裝配,無(wú)需在組件之間進(jìn)行源代表鏈接。但反射的某些方面存在一些疑問(wèn)。在本文中,我將深入討論為什么您可能不希望在程序中使用反射,以及您應該這樣做的理由。在了解了權衡性分析之后,您可以自行決定是否利大于弊。

初學(xué)者的類(lèi)
使用反射的啟點(diǎn)總是java.lang.Class實(shí)例。如果您希望與預先定義的類(lèi)協(xié)作,那么Java語(yǔ)言提供一種直接獲得Class實(shí)例的簡(jiǎn)便快捷方式:


第1部分,“類(lèi)和類(lèi)裝入”

代碼:

Class clas = MyClass.class;

當您使用這一項技術(shù)時(shí),裝入類(lèi)涉及的所有工作在幕后進(jìn)行。但是,如果您需要在運行時(shí)從某些外部源讀取類(lèi)名,這種方法并不適合。實(shí)際上,您需要使用一個(gè)類(lèi)裝入器來(lái)查找類(lèi)信息。以下介紹一種方法:

代碼:

// "name" is the class name to load
Class clas = null;
try {
  clas = Class.forName(name);
} catch (ClassNotFoundException ex) {
  // handle exception case
}
// use the loaded class

如果已經(jīng)裝入了類(lèi),您將得到現有的Class信息。如果類(lèi)未被裝入,類(lèi)裝入器將現在裝入并返回新創(chuàng )建的類(lèi)實(shí)例。

基于類(lèi)的反射
Class對象為您提供接入類(lèi)元數據的反射的所有基本hook。這類(lèi)元數據包括關(guān)于類(lèi)自身的信息,如包和類(lèi)的父類(lèi),以及該類(lèi)實(shí)施的接口。它還包括該類(lèi)定義的構造函數、字段和方法的詳細信息。這些最后的項目都是編程中最經(jīng)常使用的項目, 因此我將在本小節的稍后部分給出一些與它們協(xié)作的實(shí)例。

對于以下三類(lèi)組件中的任何一類(lèi)來(lái)說(shuō) -- 構造函數、字段和方法 -- java.lang.Class 提供四種獨立的反射調用,以不同的方式來(lái)獲得信息。調用都遵循一種標準格式。以下是用于查找構造函數的一組反射調用:
Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數類(lèi)型的公共構造函數,


Constructor[] getConstructors() -- 獲得類(lèi)的所有公共構造函數


Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數類(lèi)型的構造函數(與接入級別無(wú)關(guān))


Constructor[] getDeclaredConstructors() -- 獲得類(lèi)的所有構造函數(與接入級別無(wú)關(guān))

每類(lèi)這些調用都返回一個(gè)或多個(gè)java.lang.reflect.Constructor函數。這種Constructor類(lèi)定義newInstance方法,它采用一組對象作為其唯一的參數,然后返回新創(chuàng )建的原始類(lèi)實(shí)例。該組對象是用于構造函數調用的參數值。作為解釋這一工作流程的實(shí)例,假設您有一個(gè)TwoString 類(lèi)和一個(gè)使用一對Strings的構造函數,如清單1所示:
清單1:從一對字符串創(chuàng )建的類(lèi)


代碼:

public class TwoString {
    private String m_s1, m_s2;
    public TwoString(String s1, String s2) {
        m_s1 = s1;
        m_s2 = s2;
    }
}

清單2中的代碼獲得構造函數并使用它來(lái)創(chuàng )建使用Strings "a" 和 "b"的TwoString 類(lèi)的一個(gè)實(shí)例:
清單2:構造函數的反射調用

代碼:


    Class[] types = new Class[] { String.class, String.class };
    Constructor cons = TwoString.class.getConstructor(types);
    Object[] args = new Object[] { "a", "b" };
    TwoString ts = cons.newInstance(args);

清單2中的代碼忽略了不同反射方法拋出的多種可能選中的例外類(lèi)型。例外在 Javadoc API 描述中詳細記錄,因此為了簡(jiǎn)明起見(jiàn),我將在所有程序實(shí)例中忽略它們。

盡管我在討論構造函數主題,Java編程語(yǔ)言還定義了一種您可以用來(lái)使用無(wú)參數(或缺?。嬙旌瘮祫?chuàng )建類(lèi)的一個(gè)實(shí)例的特殊快捷方式。這種快捷方式嵌入到Class定義中,如下:
Object newInstance() -- 使用缺省函數創(chuàng )建新的實(shí)例

即使這種方法只允許您使用一種特殊的構造函數,如果這正是您需要的,那么它將提供一種非常方便的快捷方式。當與JavaBeans協(xié)作時(shí)這項技術(shù)尤其有用,JavaBeans需要定義公共、無(wú)參數構造函數。

通過(guò)反射增加字段獲得字段信息的Class 反射調用不同于那些用于接入構造函數的調用,在參數類(lèi)型數組中使用了字段名:
Field getField(String name) -- 獲得命名的公共字段


Field[] getFields() -- 獲得類(lèi)的所有公共字段


Field getDeclaredField(String name) -- 獲得類(lèi)聲明的命名的字段


Field[] getDeclaredFields() -- 獲得類(lèi)聲明的所有字段

盡管與構造函數調用類(lèi)似,在字段方面仍存在一個(gè)重要的區別:前兩個(gè)變量返回可以通過(guò)類(lèi)接入的公共字段的信息 -- 即使它們來(lái)自于祖先類(lèi)。后兩個(gè)變量返回類(lèi)直接聲明的字段的信息 -- 與字段的接入類(lèi)型無(wú)關(guān)。

調用返回的java.lang.reflect.Field實(shí)例定義所有主類(lèi)型的getXXX 和 setXXX 方法,以及與對象引用協(xié)作的通用get 和 set 方法。您可以根據實(shí)際的字段類(lèi)型自行選擇一種適當的方法,而getXXX 方法將自動(dòng)處理擴展轉換(如使用getInt 方法來(lái)檢索一個(gè)字節值)。

清單3顯示使用字段反射方法的一個(gè)實(shí)例,以方法的格式根據名稱(chēng)增加對象的int字段 :
清單3:通過(guò)反射增加一個(gè)字段


代碼:

public int incrementField(String name, Object obj) throws... {
    Field field = obj.getClass().getDeclaredField(name);
    int value = field.getInt(obj) + 1;
    field.setInt(obj, value);
    return value;
}

這種方法開(kāi)始展示了反射帶來(lái)的某些靈活性。與特定的類(lèi)協(xié)作不同,incrementField 使用傳 入的對象的getClass 方法來(lái)查找類(lèi)信息,然后直接在該類(lèi)中查找命名的字段。

通過(guò)反射增加方法
獲得方法信息的Class 反射調用與用于構造函數和字段的調用非常類(lèi)似:
Method getMethod(String name, Class[] params) -- 使用特定的參數類(lèi)型,獲得命名的公共方法


Method[] getMethods() -- 獲得類(lèi)的所有公共方法


Method getDeclaredMethod(String name, Class[] params) -- 使用特寫(xiě)的參數類(lèi)型,獲得類(lèi)聲明的命名的方法


Method[] getDeclaredMethods() -- 獲得類(lèi)聲明的所有方法

與字段調用一樣,前兩個(gè)變量返回可以通過(guò)類(lèi)接入的公共方法的信息 -- 即使它們來(lái)自于祖先類(lèi)。后兩個(gè)變量返回類(lèi)聲明的方法的信息,與方法的接入類(lèi)型無(wú)關(guān)。

調用返回的java.lang.reflect.Method實(shí)例定義一種invoke方法,您可以用來(lái)在正在定義的類(lèi)的一個(gè)實(shí)例上調用方法。這種invoke 方法使用兩個(gè)參數,為調用提供類(lèi)實(shí)例和參數值數組。

清單4進(jìn)一步闡述字段實(shí)例,顯示反射正在運行的方法的一個(gè)實(shí)例。這種方法增加一個(gè)定義有g(shù)et 和 set方法的int JavaBean屬性。例如,如果對象為一個(gè)整數count值定義了getCount 和 setCount 方法,您可以在一次調用中向該方法傳遞“count”作為name參數,以增加該值。
清單4:通過(guò)反射增加一個(gè)JavaBean 屬性


代碼:

public int incrementProperty(String name, Object obj) {
    String prop = Character.toUpperCase(name.charAt(0)) +
        name.substring(1);
    String mname = "get" + prop;
    Class[] types = new Class[] {};
    Method method = obj.getClass().getMethod(mname, types);
    Object result = method.invoke(obj, new Object[0]);
    int value = ((Integer)result).intValue() + 1;
    mname = "set" + prop;
    types = new Class[] { int.class };
    method = obj.getClass().getMethod(mname, types);
    method.invoke(obj, new Object[] { new Integer(value) });
    return value;
}

為了遵循JavaBeans慣例,我把屬性名的首字母改為大寫(xiě),然后預先考慮 get 來(lái)創(chuàng )建讀方法名,set來(lái)創(chuàng )建寫(xiě)方法名。JavaBeans讀方法僅返回值,而寫(xiě)方法使用值作為唯一的參數,因此我規定方法的參數類(lèi)型以進(jìn)行匹配。最后,該慣例要求方法為公共,因此我使用查找格式,查找類(lèi)上可調用的公共方法。

這一實(shí)例是第一個(gè)我使用反射傳遞主值的實(shí)例,因此現在我們來(lái)看看它是如何工作的?;驹砗芎?jiǎn)單:無(wú)論什么時(shí)候您需要傳遞主值,只需用相應封裝類(lèi)的一個(gè)實(shí)例(在java.lang包中定義)來(lái)替換該類(lèi)主值。這可以應用于調用和返回。因此,當我在實(shí)例中調用get方法時(shí),我預計結果為實(shí)際int屬性值的java.lang.Integer封裝。

反射數組
數組是Java編程語(yǔ)言中的對象。與所有對象一樣,它們都有類(lèi)。如果您有一個(gè)數組,使用標準getClass方法,您可以獲得該數組的類(lèi),就象任何其它對象一樣。但是,不通過(guò)現有的實(shí)例來(lái)獲得類(lèi)不同于其它類(lèi)型的對象。即使您有一個(gè)數組類(lèi),您也不能直接對它進(jìn)行太多的操作 -- 反射為標準類(lèi)提供的構造函數接入不能用于數組,而且數組沒(méi)有任何可接入的字段,只有基本的java.lang.Object 方法定義用于數組對象。

數組的特殊處理使用java.lang.reflect.Array類(lèi)提供的靜態(tài)方法的集合。該類(lèi)中的方法使您能夠創(chuàng )建新數組,獲得數組對象的長(cháng)度,讀和寫(xiě)數組對象的索引值。

清單5顯示了一種重新調整現有數組大小的有效方法。它使用反射來(lái)創(chuàng )建相同類(lèi)型的新數組,然后在返回新數組之前,在老數組中復制所有數據。
清單 5:通過(guò)反射來(lái)擴展一個(gè)數組


代碼:

public Object growArray(Object array, int size) {
    Class type = array.getClass().getComponentType();
    Object grown = Array.newInstance(type, size);
    System.arraycopy(array, 0, grown, 0,
        Math.min(Array.getLength(array), size));
    return grown;
}

安全性和反射
在處理反射時(shí)安全性是一個(gè)較復雜的問(wèn)題。反射經(jīng)常由框架型代碼使用,由于這一點(diǎn),您可能希望框架能夠全面接入您的代碼,無(wú)需考慮常規的接入限制。但是,在其它情況下,不受控制的接入會(huì )帶來(lái)嚴重的安全性風(fēng)險,如當代碼在不值得信任的代碼共享的環(huán)境中運行時(shí)。

由于這些互相矛盾的需求,Java編程語(yǔ)言定義一種多級別方法來(lái)處理反射的安全性?;灸J绞菍Ψ瓷鋵?shí)施與應用于源代碼接入相同的的限制:
從任意位置到類(lèi)公共組件的接入
類(lèi)自身外部無(wú)任何到私有組件的接入
受保護和打包(缺省接入)組件的有限接入

不過(guò)-至少某些時(shí)候,圍繞這些限制有一種簡(jiǎn)單的方法。我在前面實(shí)例中使用的Constructor、Field 和 Method 類(lèi)都擴展了一個(gè)普通的基本類(lèi)-- java.lang.reflect.AccessibleObject 類(lèi)。該類(lèi)定義一種setAccessible方法,使您能夠啟動(dòng)或關(guān)閉對這些類(lèi)中其中一個(gè)類(lèi)的實(shí)例的接入檢測。唯一的問(wèn)題在于如果使用了安全性管理器,它將檢測正在關(guān)閉接入檢測的代碼是否許可了這樣做。如果未許可,安全性管理器拋出一個(gè)例外。

清單6展示了一個(gè)程序,在清單 1TwoString 類(lèi)的一個(gè)實(shí)例上使用反射來(lái)顯示安全性正在運行:
清單 6:反射安全性正在運行

代碼:


public class ReflectSecurity {
    public static void main(String[] args) {
        try {
            TwoString ts = new TwoString("a", "b");
            Field field = clas.getDeclaredField("m_s1");
//          field.setAccessible(true);
            System.out.println("Retrieved value is " +
                field.get(inst));
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }
    }
}

如果您編譯了這一程序,不使用任何特定參數直接從命令行運行,它將在field.get(inst)調用中拋出一個(gè)IllegalAccessException。如果您未注釋field.setAccessible(true)代碼行,那么重新編譯并重新運行該代碼,它將取得成功。最后,如果您在命令行添加了JVM參數-Djava.security.manager以實(shí)現安全性管理器,它將再次失敗,除非您定義了ReflectSecurity類(lèi)的許可權限。

反射性能
反射是一種強大的工具,但也存在一些不足。一個(gè)主要的缺點(diǎn)是對性能有影響。使用反射基本上是一種解釋操作,您可以告訴JVM您希望做什么并且它滿(mǎn)足您的要求。這類(lèi)操作總是慢于只直接執行相同的操作。為了闡述使用反射的性能成本,我為本文準備了一組基準程序(見(jiàn)參考資料,完整代碼鏈接)。

清單7是字段接入性能測試的一個(gè)摘用,包括基本的測試方法。每種方法測試字段接入的一種形式 -- accessSame 與同一對象的成員字段協(xié)作,accessOther 使用可直接接入的另一對象的字段,accessReflection 使用可通過(guò)反射接入的另一對象的字段。在每種情況下,方法執行相同的計算 -- 循環(huán)中簡(jiǎn)單的加/乘順序。
清單 7:字段接入性能測試代碼

代碼:


public int accessSame(int loops) {
    m_value = 0;
    for (int index = 0; index < loops; index++) {
        m_value = (m_value + ADDITIVE_VALUE) *
            MULTIPLIER_VALUE;
    }
    return m_value;
}

public int accessReference(int loops) {
    TimingClass timing = new TimingClass();
    for (int index = 0; index < loops; index++) {
        timing.m_value = (timing.m_value + ADDITIVE_VALUE) *
            MULTIPLIER_VALUE;
    }
    return timing.m_value;
}

public int accessReflection(int loops) throws Exception {
    TimingClass timing = new TimingClass();
    try {
        Field field = TimingClass.class.
            getDeclaredField("m_value");
        for (int index = 0; index < loops; index++) {
            int value = (field.getInt(timing) +
                ADDITIVE_VALUE) * MULTIPLIER_VALUE;
            field.setInt(timing, value);
        }
        return timing.m_value;
    } catch (Exception ex) {
        System.out.println("Error using reflection");
        throw ex;
    }
}

測試程序重復調用每種方法,使用一個(gè)大循環(huán)數,從而平均多次調用的時(shí)間衡量結果。平均值中不包括每種方法第一次調用的時(shí)間,因此初始化時(shí)間不是結果中的一個(gè)因素。在為本文進(jìn)行的測試中, 每次調用時(shí)我使用1000萬(wàn)的循環(huán)數,在1GHz PIIIm系統上運行。三個(gè)不同Linux JVM的計時(shí)結果如圖1所示。所有測試使用每個(gè)JVM的缺省設置。


上表的對數尺度可以顯示所有時(shí)間,但減少了差異看得見(jiàn)的影響。在前兩副圖中(Sun JVM),使用反射的執行時(shí)間超過(guò)使用直接接入的1000倍以上。通過(guò)比較,IBM JVM可能稍好一些,但反射方法仍舊需要比其它方法長(cháng)700倍以上的時(shí)間。任何JVM上其它兩種方法之間時(shí)間方面無(wú)任何顯著(zhù)差異,但IBM JVM幾乎比Sun JVM快一倍。最有可能的是這種差異反映了Sun Hot Spot JVM的專(zhuān)業(yè)優(yōu)化,它在簡(jiǎn)單基準方面表現得很糟糕。

除了字段接入時(shí)間測試之外,我還進(jìn)行了相同的方法調用時(shí)間測試。在方法調用中,我試用了與字段接入相同的三種接入變量,并增加了使用無(wú)參數方法變量,而不是在方法調用中傳遞和返回一個(gè)值。清單8顯示了用于測試調用傳遞和返回值形式的三種方法的代碼。
清單 8:方法接入性能測試代碼

代碼:


public int callDirectArgs(int loops) {
    int value = 0;
    for (int index = 0; index < loops; index++) {
        value = step(value);
    }
    return value;
}

public int callReferenceArgs(int loops) {
    TimingClass timing = new TimingClass();
    int value = 0;
    for (int index = 0; index < loops; index++) {
        value = timing.step(value);
    }
    return value;
}

public int callReflectArgs(int loops) throws Exception {
    TimingClass timing = new TimingClass();
    try {
        Method method = TimingClass.class.getMethod
            ("step", new Class [] { int.class });
        Object[] args = new Object[1];
        Object value = new Integer(0);
        for (int index = 0; index < loops; index++) {
            args[0] = value;
            value = method.invoke(timing, args);
        }
        return ((Integer)value).intValue();
    } catch (Exception ex) {
        System.out.println("Error using reflection");
        throw ex;
    }
}


反射性能是Sun開(kāi)發(fā)1.4 JVM時(shí)關(guān)注的一個(gè)方面,它在反射方法調用結果中顯示。在這類(lèi)操作的性能方面,Sun 1.4.1 JVM顯示了比1.3.1版本很大的改進(jìn),在我的測試中運行速度大約是1.3.1版本的開(kāi)部。在這類(lèi)簡(jiǎn)單的測試中,IBM 1.4.0 JVM再次獲得了更好的成績(jì),但是只比Sun 1.4.1 JVM快兩到三倍。

我還為創(chuàng )建使用反射的對象編寫(xiě)了類(lèi)似的計時(shí)測試程序,但這種情況下的差異不象字段和方法調用情況下那么顯著(zhù)。使用newInstance()調用創(chuàng )建一個(gè)簡(jiǎn)單的java.lang.Object實(shí)例耗用的時(shí)間大約是在Sun 1.3.1 JVM上使用new Object()的12倍,是在IBM 1.4.0 JVM的四倍,只是Sun 1.4.1 JVM上的兩部。使用Array.newInstance(type, size)創(chuàng )建一個(gè)數組耗用的時(shí)間是任何測試的JVM上使用new type[size]的兩倍,隨著(zhù)數組大小的增加,差異逐步縮小。

結束語(yǔ)
Java語(yǔ)言反射提供一種動(dòng)態(tài)鏈接程序組件的多功能方法。它允許程序創(chuàng )建和控制任何類(lèi)的對象(根據安全性限制),無(wú)需提前硬編碼目標類(lèi)。這些特性使得反射特別適用于創(chuàng )建以非常普通的方式與對象協(xié)作的庫。例如,反射經(jīng)常在持續存儲對象為數據庫、XML或其它外部格式的框架中使用。

反射有兩個(gè)缺點(diǎn)。第一個(gè)是性能問(wèn)題。當用于字段和方法接入時(shí)反射要遠慢于直接代碼。性能問(wèn)題的程度取決于程序中是如何使用反射的。如果它作為程序運行中相對很少涉及的部分,緩慢的性能將不會(huì )是一個(gè)問(wèn)題。即使測試中最壞情況下的計時(shí)圖顯示的反射操作只耗用幾微秒。僅反射在性能關(guān)鍵的應用的核心邏輯中使用時(shí)性能問(wèn)題才變得至關(guān)重要。

許多應用更嚴重的一個(gè)缺點(diǎn)是使用反射會(huì )模糊程序內部實(shí)際要發(fā)生的事情。程序人員希望在源代碼中看到程序的邏輯,反射等繞過(guò)了源代碼的技術(shù)會(huì )帶來(lái)維護問(wèn)題。反射代碼比相應的直接代碼更復雜,正如性能比較的代碼實(shí)例中看到的一樣。解決這些問(wèn)題的最佳方案是保守地使用反射-- 僅在它可以真正增加靈活性的地方 -- 記錄其在目標類(lèi)中的使用。

在下一部分,我將提供如何使用反射的更詳細實(shí)例。這種實(shí)例提供一個(gè)處理Java應用命令行參數的API,一種您可能發(fā)現適用于自己應用的工具。它還基于反射的優(yōu)勢來(lái)創(chuàng )建,同時(shí)避免其弱點(diǎn)。反射是否能簡(jiǎn)化您的命令行處理?您可以在Java編程的動(dòng)態(tài)性第3部分找到答案。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=281361

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Java Reflection
JVM學(xué)習筆記
JNI官方規范中文版——JNI程序設計總結
java反射機制_Java交流
Java筆記(一)
查看Java Reflection類(lèi)內部情況 - Builder開(kāi)發(fā)者在線(xiàn)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久